8

I have used this question to help me come up with an undistorted coordinated system of an image. Now, I'm not sure how to implement the new coordinate system into the image so I can be able to produce an undistorted image.

I'm having trouble finding answers that don't involve Matlab, OpenCV, or C++ as I am using R.

The answer I'm using from the cited question has given me the following transformed xy coordinate :

1 -19.50255239, -19.50255239
2 -18.26735544, -18.26735544
3 -17.03391152, -17.03391152
4 -15.80221494, -15.80221494
5 -14.57225998, -14.57225998
6 -13.34404095, -13.34404095
...

and so on for 512 pixels in a 512 x 512 image.

How to apply this back to the original 512 x 512 image is what I'm struggling with. I've seen some mention on pages like the Open CV page here and specific pre-defined shifts, or latitudinal/longitudinal shifts, use SpatialObjectsDataFrames, but not from one user-defined list of xy coordinates to another.

-An example of getting the source image coordinates:

im_coords <- RSAGA::grid.to.xyz(as.matrix(as.raster(im)))

(note, I don't actually want to raster the images, its just what I found at the time)

-Code I'm using to get the transformed coordinates:

undistort <- function(X, Y, a, b, c, d = 1, imWidth = 512, imHeight = 512) {

    #radial barrel distortion
    normX <- X - (imWidth / 2)
    normY <- Y - (imHeight / 2)

    #rmax
    radius_u <- sqrt(imWidth^2 + imHeight^2)

    #normalize r so that its between 0 and 1
    r <- sqrt(normX^2 + normY^2) /  radius_u

    #Barrel distorition equation: where "r" is the destination radius and "Rsrc" is the source pixel to get the pixel color from
    Rsrc <- r * (a*r^3 + b*r^2 + c*r + d)

    theta <- ifelse(Rsrc == 0, 1, 1 / atan(Rsrc) * Rsrc)

    newX <- (imWidth / 2) + theta * normX
    newY <- (imHeight / 2) + theta * normY

    return(data.frame(X = newX, Y = newY))
}

Here is a sample sample 512x512 .png barrel distorted image: https://i.stack.imgur.com/qddFb.jpg

enter image description here

I'm wondering if kriging could be useful? Or gdalwarp or proj4string? Not sure how to implement these.

UPDATE: Using Rohit's suggestions I was able to distort a rainbow grid from:

enter image description here

to this:

enter image description here

When I try it with the barrel image I get this weird superimposed image:

enter image description here

Ok, I think it is down to what coefficients you use as seen here:

enter image description here

SqueakyBeak
  • 366
  • 4
  • 15

1 Answers1

3

You don't actually need to calculate the transformed xy coordinates. You just need the function that takes the x and y coordinates and returns the undistorted ones. Given your undistort function, write a wrapper around it that uses only x and y as inputs:

im2 <- imwarp(im1, function(x,y){ 
  undistort(x,y,a=1,b=2,c=4) # Give appropriate values for arguments, I'm not an expert.
})

If you want to map specifically from one list to another, then you can do that as well:

df <- expand.grid(x=1:512,y=1:512) # Original grid coordinates
df1 <- undistort(X=df$x,Y=df$y) # Undistorted grid coordinates
im2 <- imwarp(im1, function(x,y){
  df1[df$x==x & df$y==y,] # Map appropriately. Should still work.
})

Try out different options for interpolation to see what works best.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Rohit
  • 1,967
  • 1
  • 12
  • 15
  • 1
    Thanks for responding. So when I try to pass the list of coords that the function 'undistort' gives me into imwarp I receive an error of: "Error in 1:d[4] : NA/NaN argument". This is probably expected since the impwarp is supposed to use images as the warp field, not coordinate lists. I'm working on the 2nd suggestion now. The main problem remains that I need to make an image from a list of coordinates. – SqueakyBeak Mar 18 '19 at 15:34
  • 1
    See `?imager::as.cimg.data.frame` – Rohit Mar 18 '19 at 15:46
  • 1
    @SqueakyBeak please ensure if the solution above worked or not – Edeki Okoh Mar 18 '19 at 16:01
  • @EdekiOkoh it has not, as I mentioned I encounter an error when I use the function wrapper and he has not shown how to get an image from the new coordinates. Thank you – SqueakyBeak Mar 18 '19 at 16:07
  • 1
    Maybe I wasn't clear. If `im1` is your original image, `df` has your original grid coordinates, `df1` has the corresponding new coordinates then `im2` is the image with the requisite mapping. If you look further into the documentation for `imager` you'll find the needed functions to load and save images in the required format. – Rohit Mar 18 '19 at 16:23
  • I'm working through it now, I hadn't seen your comment about cimg. I'll let you know if it works, thanks – SqueakyBeak Mar 18 '19 at 16:36
  • 2
    So I was able to make it work on a rainbow grid I had made to distort the image, but when I tried it on a barrel distortion pic it just showed up entirely black. I'll update description with the pics. – SqueakyBeak Mar 18 '19 at 16:44
  • @Rohit Ok I got it to 'work' on the barrel image but it just looks like waves of water on top of the image vs actually undistorting the image... – SqueakyBeak Mar 18 '19 at 16:58
  • After working with different coefficients I think the wave patterns are due to different coefficients and so in that case I would consider Rohit 's solution correct @Edeki_Okoh. Please feel free to award the bounty and thank you for your help. – SqueakyBeak Mar 18 '19 at 17:18