Ask Your Question
0

Remap a single point not working

asked 2019-05-09 03:31:27 -0600

Kafan gravatar image

updated 2019-05-09 03:32:28 -0600

Detailed descriptionTried remapping a single point but it does not work but remapping the whole image works fine. I know it is not probably a bug but I am helpless as all previous similar question on https://answers.opencv.org or other forums like SO are still unanswered.

The camMapX and The camMapY were calculated for image of size 1280x960, a point (615, 492) should certainly lie within the image boundaries, but calculated remapped point is way outside the image and it happens for any other point too. What am I missing?

Steps to reproduce

 // This works fine for the whole image Mat
 remap(camImage, camImage, camMapX, camMapY, cv::INTER_LINEAR);

 outputPoint.x = camMapX.at<int>(inputPoints[z].y, inputPoint.x);
 outputPoint.y = camMapY.at<int>(inputPoints[z].y, inputPoint.x);

__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "in: (%d, %d)  o: (%d, %d)",inputPoints.x, inputPoints.y, outputPoint.x, outputPoint.y);
// inputPoint: (615, 492)  outputPoint: (32244308, 66192352)
edit retag flag offensive close merge delete

1 answer

Sort by » oldest newest most voted
1

answered 2019-05-09 04:48:32 -0600

HYPEREGO gravatar image

updated 2019-05-09 08:52:55 -0600

First of all, which type is the matrix returned by remap? You can check the camImage.type() after calling remap (see the snippet below, I suggest you to write a utility function to retrieve it)

Secondly, you are accessing a camMapX (we can say the same for camMapY), that from the documentation is the following parameter

map1 – The first map of either (x,y) points or just x values having the type CV_16SC2 , CV_32FC1 , or CV_32FC2 .

From the documentation, this matrix is at least CV_16S, but usually they are CV_32F or CV_64F. In addition .at access method want the coordinates in (x,y) format, while you gave them as y and x.

If you are using the formula from the documentation (x,y) = src(map_x(x,y), map_y(x,y)) supposing that you have an inputPoint in x and y coordinate:

 outputPoint.x = camMapX.at<float>(inputPoint.x, inputPoint.y);
 outputPoint.y = camMapY.at<float>(inputPoint.x, inputPoint.y);

Most of the OpenCV function that perform this kind of operation (remap, undistort etc) retrieve a CV_64F or CV_32F to avoid the loss of information, so I suggest you to try with float or double.

Briefly you can try something really similar to that:

remap(camImage, camImage, camMapX, camMapY, cv::INTER_LINEAR);

uchar depth = camImage.type() & CV_MAT_DEPTH_MASK;
if(depth == CV_32F)
 {
      outputPoint.x = camMapX.at<float>(inputPoint.x, inputPoint.y);
      outputPoint.y = camMapY.at<float>(inputPoint.x, inputPoint.y);
      __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "in: (%f, %f)  o: (%f, %f)",inputPoints.x, inputPoints.y, outputPoint.x, outputPoint.y);
 }
 else if (depth == CV_64F)
 {
      outputPoint.x = camMapX.at<double>(inputPoint.x, inputPoint.y);
      outputPoint.y = camMapY.at<double>(inputPoint.x, inputPoint.y);
      __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "in: (%f, %f)  o: (%f, %f)",inputPoints.x, inputPoints.y, outputPoint.x, outputPoint.y);
 }

Remember that this snippet take into account an arbitrary inputPoint, if you have an array or other structure you have to change it accordingly! The access mode is always x,y, don't forget that! Once you have find which of the two is correct you can remove the if statement and leave the correct one.

edit flag offensive delete link more

Comments

@HYPERGO depth is coming to be 0, which I believe is for CV_8U. But I looked at the code that I used for generating these camera calibration maps and I used CV_16SC2. I found I need to use .at<vec2s> and look at index 0. I am unable to find any information regarding which index to look at and what does it mean.

Kafan gravatar imageKafan ( 2019-05-10 03:18:25 -0600 )edit

CV_SC2 is a 16bit with 2 channel, so when you'are accessing it you have to take care about both channels. In that case, in the first channel there is the mapping for the x coordinate, while in the second channel there is the mapping for the y coordinate. The argument map2 can be cv::noArray() since in the first mapping you already provide all the mapping for both coordinates. If you want you can split them in two distinct matrix using convertMaps:

convertMaps(camMap, cv::noArray(), dstmap1, dstmap2, CV_32FC1);

where camMap is the 16SC2 map, dstMap and dstmap2 are both empty cv::Mat. After you've done this, you'll be able to access the new dstmap1 and dstmap2 using float and in the same way I showed to you :)

HYPEREGO gravatar imageHYPEREGO ( 2019-05-10 04:01:13 -0600 )edit

@HYPERGO My map2 is not null and has value. I have accessed x and y coordinate from map1 using vec2s and then looking at the index 0 for x and 1 for y. It is giving values but it is wrong by around 2% compared to what the remap function maps the source to destination.

My map2 is not null or empty and has value but not sure what do they represent. Any way in reaching accurate pixel value without convertMaps?

input Pixel: (640, 480) Expected destination Pixel value should be (648, 486)

output Pixel through vec2s on map1 at index 0 (x) and 1 (y): (629, 474)

map2 values at index 0 and 1: (90, 106)

Kafan gravatar imageKafan ( 2019-05-10 06:53:56 -0600 )edit

Can you provide more code to reproduce it?

HYPEREGO gravatar imageHYPEREGO ( 2019-05-13 02:16:29 -0600 )edit
1

Had a similar problem: I could not use remap with a single point. I've verified the documentation and the UndistortPoints should work.

python points = cv2.undistortPoints(points, k, d, np.eye(3), k)

These takes the camera parameters k and distortion coefficients d from initUndistortRectifyMap.

gscast gravatar imagegscast ( 2019-07-18 08:09:27 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2019-05-09 03:31:27 -0600

Seen: 2,212 times

Last updated: May 09 '19