# Log-polar transform of an image

**URL:** https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004
**Category:** General Usage
**Created:** [December 17, 2020, 6:38pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004 "2020-12-17T18:38:35Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![rveltz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rveltz/32/2707_2.png) [@rveltz](https://discourse.julialang.org/u/rveltz)
#### Post date: [December 17, 2020, 6:38pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/1 "2020-12-17T18:38:35Z")

</div>

Hi,

I would like to perform the log-polar transform of an image. I tried. I failed. Maybe this is obvious to some of you…

First, I deal with the polar transform. The trouble seems to come from a specific type of images

```julia
using Revise
using CoordinateTransformations, ImageTransformation, Plots, TestImages, OffsetArrays
struct Retinotopy <: Transformation; end
struct InvRetinotopy <: Transformation; end
function (::Retinotopy)(x)
    length(x) == 2 || error("Polar transform takes a 2D coordinate")

    [(hypot(x[1], x[2])), atan(x[2], x[1])]
end

function (::InvRetinotopy)(x)
    s,c = sincos(x[2])
   ( (x[1]) * c, (x[1]) * s)
end

Base.inv(::Retinotopy) = InvRetinotopy()

img = testimage("lighthouse")
tfm = Retinotopy()

# this works, Houra!
img0 = OffsetArray(img, -256:255, -384:383) # origin near top of image
imgw = warp(img0, tfm)
heatmap(imgw)

# this does not work !!!! What???
img = Gray.([(cos(x - y)) for x in LinRange(0,5pi,512), y in LinRange(0,5pi,768)])
img0 = OffsetArray(img, -256:255, -384:383); # origin near top of image
imgw = warp(img0, tfm)
heatmap(imgw)

```

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [December 18, 2020, 11:03pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/2 "2020-12-18T23:03:18Z")

</div>

@rveltz, code updated with more wave periods/rings (and `using ImageCore`):

```julia
N = 2001;
img1 = Gray.([0.5*(1.0 + cos(x - y)) for x in LinRange(0,5pi,N), y in LinRange(0,5pi,N)])
img1 = ImageCore.n0f8(img1)
heatmap(img1)
img2 = OffsetArray(img1, -N÷2:N÷2, -N÷2:N÷2);
imgw = warp(img2, tfm)
heatmap(imgw)

```

Input:  
 ![input2](https://global.discourse-cdn.com/julialang/original/3X/e/f/ef9614c5b07f43a4bf023725b56b18eb5048707d.png)  
Output:  
 ![output2](https://global.discourse-cdn.com/julialang/original/3X/5/a/5aa98f2ba347d8aabc26c9192f616fc88003aa00.png)

---

<div class="post-metadata">

### Author: ![rveltz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rveltz/32/2707_2.png) [@rveltz](https://discourse.julialang.org/u/rveltz)
#### Post date: [December 18, 2020, 11:41pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/3 "2020-12-18T23:41:04Z")

</div>

Interesting… Thank you!

---

<div class="post-metadata">

### Author: ![rveltz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rveltz/32/2707_2.png) [@rveltz](https://discourse.julialang.org/u/rveltz)
#### Post date: [December 19, 2020, 12:12pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/4 "2020-12-19T12:12:07Z")

</div>

Actually, why cant we only see the first band?

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [December 19, 2020, 12:29pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/5 "2020-12-19T12:29:52Z")

</div>

@rveltz, not sure how the sampling is done but I think it is inevitable to have leftovers in this type of log-polar mapping, as both input and output from warp are rectangular. See code edited above. _PS: btw, why the logarithm is not used in your definition?_

---

<div class="post-metadata">

### Author: ![rveltz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rveltz/32/2707_2.png) [@rveltz](https://discourse.julialang.org/u/rveltz)
#### Post date: [December 19, 2020, 12:32pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/6 "2020-12-19T12:32:43Z")

</div>

> it is inevitable to have leftovers in this type of log-polar mapping,

Yes, but if you apply the rotation transform, it fills the unknowns with black. Cant we do the same here?

> _PS: btw, why the logarithm is not used in your definition?_

I could not get it work so I focused first on the polar one.

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [December 19, 2020, 12:42pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/7 "2020-12-19T12:42:49Z")

</div>

@rveltz, I am sorry but my knowledge on this topic is small. I would only point out that if we do not offset the array, we get more wavefront rings but seemingly incomplete:  
 ![output3](https://global.discourse-cdn.com/julialang/original/3X/6/e/6ebf717b5c730c7574cdba79947d6f46747c461d.png)

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [December 20, 2020, 7:41pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/8 "2020-12-20T19:41:25Z")

</div>

After some research on this, the results above do not seem to make sense.  
The Polar-Cartesian transforms should wrap/unwrap images like posted [here](https://imagej.nih.gov/ij/plugins/polar-transformer.html).  
The simple code below adapted from Matlab seems to behave as expected for the Polar transform. It seems that you are looking for the inverse (Cartesian) transform. It might be easier to write it from scratch than to understand all the packages listed at the top of the post.

```julia
function imgpolarcoord(img::Array{Float64,2})
# Adapted from: Javier Montoya (2020). Polar Coordinates Transform, MATLAB Central File Exchange
# https://www.mathworks.com/matlabcentral/fileexchange/16094-polar-coordinates-transform

   (rows,cols) = size(img)
   cy, cx = rows ÷ 2, cols ÷ 2  
   radius = Int(minimum((cy,cx))) - 1
   Nϕ = 4*360
   Δϕ = 2pi/Nϕ
   pcimg = zeros(radius + 1, Nϕ)
   for j = 1:Nϕ, i = 1:radius+1
         pcimg[i,j] = img[cy + round(Int,(i-1)*sin(Δϕ*(j-1))), cx + round(Int,(i-1)*cos(Δϕ*(j-1)))]
   end
   return pcimg
end

using ImageCore, Plots
N = 2000
img0 = ([0.5*(1.0 + cos(x-y)) for x in LinRange(0,5pi,N), y in LinRange(0,5pi,N)])
heatmap(Gray.(img0))
imgw = imgpolarcoord(img0)
imgw = ImageCore.n0f8(Gray.(imgw))
heatmap(imgw)

img0 = ([0.5*(1.0 + cos(hypot(x,y))) for x in LinRange(-4pi,4pi,N), y in LinRange(-4pi,4pi,N)])
heatmap(Gray.(img0))
imgw = imgpolarcoord(img0)
imgw = ImageCore.n0f8(Gray.(imgw))
heatmap(imgw)

```

Input plane wave:  
 ![input_plane_wave](https://global.discourse-cdn.com/julialang/original/3X/5/7/57079daa6f893f1701da0a9dacee172f35f4a998.png)  
Polar transform output:  
 ![polar_transform_plane_wave](https://global.discourse-cdn.com/julialang/original/3X/1/e/1e46f0189ea500b5e1ba44bbc8c761248dd600b4.png)  
Input spherical wave:  
 ![input_spherical_wave](https://global.discourse-cdn.com/julialang/original/3X/8/d/8d7a2ce1636c930de461a9d019ef33337bd5a7ea.png)  
Polar transform output:  
 ![polar_transform_spherical_wave](https://global.discourse-cdn.com/julialang/original/3X/3/e/3e636d6eb2bdd9f512284a76fbb16faaa994673f.png)

---

<div class="post-metadata">

### Author: ![mikkoku](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikkoku/32/16274_2.png) [@mikkoku](https://discourse.julialang.org/u/mikkoku)
#### Post date: [December 21, 2020, 8:13pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/9 "2020-12-21T20:13:28Z")

</div>

Mapping something with `atan` will give coordinates in the range -2 … 2, which is not good for an image.

Moreover `warp` tries to automagically guess the correct dimensions of the output image and this appears to fail for polar transform. Try

```julia
warp(img0, tfm, (-1000:1000, -1000:1000))

```

---

<div class="post-metadata">

### Author: ![rveltz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rveltz/32/2707_2.png) [@rveltz](https://discourse.julialang.org/u/rveltz)
#### Post date: [December 29, 2020, 8:30pm UTC](https://discourse.julialang.org/t/log-polar-transform-of-an-image/52004/10 "2020-12-29T20:30:31Z")

</div>

Wow!! Thank you a lot
