Log-polar transform of an image

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

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)

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

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
Output:
output2

2 Likes

Interesting… Thank you!

Actually, why cant we only see the first band?

@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?

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.

@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

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.
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.

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
Polar transform output:
polar_transform_plane_wave
Input spherical wave:
input_spherical_wave
Polar transform output:
polar_transform_spherical_wave

1 Like

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

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

Wow!! Thank you a lot