Home > OS >  Log-polar transform
Log-polar transform

Time:06-20

I'm trying to perform a Log-polar transform on an image for the purpose of image registration. In other words I'm trying to achieve this:

Input image ------> output image (nevermind the red lines)

I need to code this from scratch in Java because I'll be doing this on the GPU side with OpenCL Java bindings and can't use libraries. There are multiple threads on this but none that could really help me, mostly because they're all using in-built MATLAB functions that I cannot replicate.

I've been trying the Polar Transform instead of the Log-Polar Transform for the sake of getting this to work because most info online refers to the first. So far, the best result I've had is with this bit here (pseudocode), based on this thread:

w = input.width; // Width of the input image
h = input.height; // Height of the input image

// Copy input pixels into an array
for(y=0; y<h; y  ){
    for(x=0; x<w; x  ){
        input[y*w x] = getPixel(x, y);
    }
}

// Polar transform
maxRadius = sqrt(w*w   h*h);
radiusScale = w / maxRadius;
angleScale = h / (2 * PI);

for(y=0; y<h; y  ){
    dy = y - h/2; // Distance from the center in the y-axis
    for(x=0; x<w; x  ){
        dx = x - w/2; // Distance from the center in the x-axis
        angle = atan2(dy, dx) % (2*PI);
        radius = sqrt(dx*dx   dy*dy);
        newY = radius * radiusScale;
        newX = radius * thetaScale;
        output[y*w x] = input[newY*w newX];
    }
}  

What I get resembles some sort of polar transformation, despite not being the result that I'm looking for: output image

Can someone give me any pointers on this?

Thanks

EDIT: The log-polar transform goes like this.

EDIT: Implementing @matt suggestions I now have the following code:

    w = input.width; // Width of the input image
    h = input.height; // Height of the input image
    maxRadius = sqrt(w*w/4   h*h/4);
    radiusScale = h / maxRadius;
    angleScale = w /PI/2;
    offset = PI;
    
    for(y=0; y<h; y  ){
        dy = y - h/2; // Distance from center in the y-axis
        for(x=0; x<w; x  ){
            dx = x - w/2; // Distance from the center in the x-axis
            angle = atan2(dy, dx);
            radius = sqrt(dx*dx   dy*dy);
            
            newY = radius * radiusScale;
            newX = (angle   offset) * angleScale;
            
            output[newY*w newX] = input.getPixel(x, y); 
        }
    }

Plotting the new output gives me this, which is still not what I expect to get.

CodePudding user response:

One issue with this transform is that each "pixel" in the transformed space takes up a different amount of space in the x,y space. So here is how I am defining the transform.

  • Our new image will have the same dimensions
  • The Y axis will be 0 to Max Rho
  • The X axis will be -PI to PI

So we start by iterating over the i,j coordinates of the output image. The resulting rho and theta are as follows.

double rho = j*maxRho / height;
double theta = i*maxTheta / width   offset;

Now we need to grab the input pixels at the respective location.

int x = (int) ( Math.exp(rho)*Math.cos(theta)   width/2);
int y = (int) ( Math.exp(rho)*Math.sin(theta)   height/2);

Now we can get the pixel value.

int pixel = input[y*width   x];

Your input variable is a bit redundante since you could just use your getPixel(x, y)

Then we just set the corresponding output value.

output[j*width   i] = pixel;

Here is a compilable example.

import javax.imageio.ImageIO;
import java.net.URL;
import java.awt.image.BufferedImage;
import java.io.File;
public class ScannerJunk{
  
  public static void main(String[] args) throws Exception{
        BufferedImage img = ImageIO.read( new URL("https://i.stack.imgur.com/MvDQT.png") );
        
        BufferedImage out = new BufferedImage( img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB );
        
        double w = img.getWidth();
        double h = img.getHeight();
        
        double maxRho = 0.5*Math.log( w*w/4.0   h*h/4.0 );
        
        double maxTheta = 2 * Math.PI;
        double offset = - Math.PI;
        for(int i = 0; i< w; i  ){
            for(int j = 0; j< h; j  ){
                double rho = j*maxRho / h;
                double theta = i*maxTheta / w   offset;
                int x = (int) ( Math.exp(rho)*Math.cos(theta)   w/2);
                int y = (int) ( Math.exp(rho)*Math.sin(theta)   h/2);
                
                try{
                    out.setRGB( i, j, img.getRGB( x, y ) );
                } catch(Exception e){
                    System.out.println( i   ", "   j   " :: "   rho   ", "   theta   " :: "   x   ", "   y );
                }
            }
        }
        
        
        ImageIO.write(out, "PNG", new File("transformed.png") );
  }
}

Note that the max radius, does not map to the input image for all of the possible angles.

Also, the radius and theta axis appeat to be transposed from your example image.

  • Related