Reputation: 211
I am performing calibration as showed here, but with cv.CALIB_RATIONAL_MODEL.
I am using around 40 images and my average re-projection error (calculated by cv2.calibrateCamera) is always less than 0.5.
Now, I want to be able to take any other image and apply to it, the distortion that I got from the calibration.
I know I can calculate and re-distort calibration images by using corners I saved during calibration, but I want to apply distortion on a completely different image using only intrinsic and/or extrinsic parameters that I can save and use.
Is it possible?
I tried passing np.negative(distortion)
to cv.undistort()
hoping it would undistort with negative values so it will actually distort, but it is not working and giving me totally messed up results.
I tried translating answers on other (one, two, three) threads from c++ to Python, and also creating my own function by studying the theory behind distortion, but it is not working.
Are there any other libraries or theories I can leverage to solve this issue?
Upvotes: 3
Views: 18440
Reputation: 1
Well, to get the distort image from undistort, maybe you can use undistortPoints function of opencv to get reverse map. Use initUndistortRectifyMap you get map from distort->undistort, and use undistortPoints, you can get map from undistort->distort points by points, then use remap to get the distort image.
Inverting a real-valued index grid
Upvotes: 0
Reputation: 725
OpenCV doesn't provide distort function for image, but you can implement one by yourself. All you need are:
cam_mtx
, dis_cef
, and image_size
.cam_mtx_ud
and image_size_ud
.R
.The rectification transform matrix R
can be computed by stereoRectify()
, but in mono-camera system, it's normally identity (you can just use empty Mat
).
Recall the procedure when you undistort an image, it takes two steps:
initUndistortRectifyMap(cam_mtx, dis_cef, R, cam_mtx_ud, image_size_ud, CV_32FC1, map_x, map_y)
remap(image, image_ud, map_x, map_y, INTER_LINEAR);
The rectification maps (map_x
and map_y
) describe pixel-coordinate-map from the undistorted image to the distorted image. With them, every pixel on the undistorted image can find it's location on the distorted image, and then retrieve the pixel value with interpolation. That's how remap
works.
So, to produce the undistort rectification maps, you need to loop on the pixels of destination (undistorted) image and distort the points.
Now, applying distortion on an image is just similar to undistorting.
You need to produce the "distort maps" by looping on the pixels of destination (distorted) image and undistort the points. Then, use remap
to apply the distortion.
Here is the code:
Mat map_x = Mat(image_size, CV_32FC1);
Mat map_y = Mat(image_size, CV_32FC1);
vector<Point2f> pts_ud, pts_distort;
for (int y = 0; y < image_size.height; ++y)
for (int x = 0; x < image_size.width; ++x)
pts_distort.emplace_back(x, y);
undistortPoints(pts_distort, pts_ud, cam_mtx, dis_cef, R, cam_mtx_ud);
for (int y = 0; y < image_size.height; ++y) {
float* ptr1 = map_x.ptr<float>(y);
float* ptr2 = map_y.ptr<float>(y);
for (int x = 0; x < image_size.width; ++x) {
const auto& pt = pts_ud[y * image_size.width + x];
ptr1[x] = pt.x;
ptr2[x] = pt.y;
}
}
Mat image_distort;
remap(image_ud, image_distort, map_x, map_y, INTER_LINEAR);
I'm not good with python,so I wrote the code in C++. Sorry about that, but I think the code is not hard to read.
Upvotes: 5