转载自http://blog.csdn.net/hust_bochu_xuchao/article/details/54585200,校正镜头畸变,校正透视畸变,加速计算。
1、畸变矫正
相机标定完成后,我们得到内参和畸变系数。每次从相机得到一张源图,我们都需要进行一次畸变矫正。
之前博主都是采用 undistort函数,直接输入内参和畸变系数,输入为源图,输出为矫正后的图像。
undistort(picture, dst, intrinsic, distortion_coeff);//这一步骤需要耗费300多ms的时间,为最主要耗费时间的步骤
当仅仅处理一张照片,300多ms看不到任何问题,但是,当需要流畅的视频帧数,也即在40ms内处理完一张照片时,300多ms的时间耗费,简直不能够接受啊。
所以,想办法优化时间啊。所幸找到了解决办法。
解决办法为:
initUndistortRectifyMap(intrinsic, distortion_coeff, Mat(), Mat(),image_size, 0, map1, map2);此函数根据内参和畸变系数,建立了一个查找表,map1 map2设置为全局变量,所以这个函数只需要运行一次就好。
remap(picture, dst, map1, map2, CV_INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));此函数根据map1 map2进行畸变矫正,时间耗费在10多ms
好的,畸变矫正的加速,就这么解决了。
2、透视变换
同样的现象,cv::warpPerspective,一次透视变换的时间,需要耗费100多ms,这显然也是不能接受的。
解决办法,原理同上。建立查找表,一次就好。之后,每张图片调用remap函数。
代码奉上。
- void perspective_to_maps(const cv::Mat &perspective_mat, const cv::Size img_size,
- cv::Mat &map1, cv::Mat &map2)
- {
- // invert the matrix because the transformation maps must be
- // bird's view -> original
- cv::Mat inv_perspective(perspective_mat.inv());
- inv_perspective.convertTo(inv_perspective, CV_32FC1);
- // create XY 2D array
- // (((0, 0), (1, 0), (2, 0), ...),
- // ((0, 1), (1, 1), (2, 1), ...),
- // ...)
- cv::Mat xy(img_size, CV_32FC2);
- float *pxy = (float*)xy.data;
- for (int y = 0; y < img_size.height; y++)
- for (int x = 0; x < img_size.width; x++)
- {
- *pxy++ = x;
- *pxy++ = y;
- }
- // perspective transformation of the points
- cv::Mat xy_transformed;
- cv::perspectiveTransform(xy, xy_transformed, inv_perspective);
- //Prevent errors when float32 to int16
- float *pmytest = (float*)xy_transformed.data;
- for (int y = 0; y < xy_transformed.rows; y++)
- for (int x = 0; x < xy_transformed.cols; x++)
- {
- if (abs(*pmytest) > 5000) *pmytest = 5000.00;
- pmytest++;
- if (abs(*pmytest) > 5000) *pmytest = 5000.00;
- pmytest++;
- }
- // split x/y to extra maps
- assert(xy_transformed.channels() == 2);
- cv::Mat maps[2]; // map_x, map_y
- cv::split(xy_transformed, maps);
- // remap() with integer maps is faster
- cv::convertMaps(maps[0], maps[1], map1, map2, CV_16SC2);
- }
void perspective_to_maps(const cv::Mat &perspective_mat, const cv::Size img_size,
cv::Mat &map1, cv::Mat &map2)
{
// invert the matrix because the transformation maps must be
// bird's view -> original
cv::Mat inv_perspective(perspective_mat.inv());
inv_perspective.convertTo(inv_perspective, CV_32FC1);
// create XY 2D array
// (((0, 0), (1, 0), (2, 0), ...),
// ((0, 1), (1, 1), (2, 1), ...),
// ...)
cv::Mat xy(img_size, CV_32FC2);
float *pxy = (float*)xy.data;
for (int y = 0; y < img_size.height; y++)
for (int x = 0; x < img_size.width; x++)
{
*pxy++ = x;
*pxy++ = y;
}
// perspective transformation of the points
cv::Mat xy_transformed;
cv::perspectiveTransform(xy, xy_transformed, inv_perspective);
//Prevent errors when float32 to int16
float *pmytest = (float*)xy_transformed.data;
for (int y = 0; y < xy_transformed.rows; y++)
for (int x = 0; x < xy_transformed.cols; x++)
{
if (abs(*pmytest) > 5000) *pmytest = 5000.00;
pmytest++;
if (abs(*pmytest) > 5000) *pmytest = 5000.00;
pmytest++;
}
// split x/y to extra maps
assert(xy_transformed.channels() == 2);
cv::Mat maps[2]; // map_x, map_y
cv::split(xy_transformed, maps);
// remap() with integer maps is faster
cv::convertMaps(maps[0], maps[1], map1, map2, CV_16SC2);
}
3、好的,畸变矫正和透视变换的加速问题解决了。那么,是否可以把畸变矫正和透视变换放在一起计算呢。经过了解和研究后,是可以的。
代码如下:
- void perspective_to_maps(const cv::Mat &perspective_mat, const cv::Size img_size, cv::Mat distortion_map1, cv::Mat distortion_map2,
- cv::Mat &map1, cv::Mat &map2)
- {
- // invert the matrix because the transformation maps must be
- // bird's view -> original
- cv::Mat inv_perspective(perspective_mat.inv());
- inv_perspective.convertTo(inv_perspective, CV_32FC1);
- // create XY 2D array
- // (((0, 0), (1, 0), (2, 0), ...),
- // ((0, 1), (1, 1), (2, 1), ...),
- // ...)
- cv::Mat xy(img_size, CV_32FC2);
- float *pxy = (float*)xy.data;
- for (int y = 0; y < img_size.height; y++)
- for (int x = 0; x < img_size.width; x++)
- {
- *pxy++ = x;
- *pxy++ = y;
- }
- // perspective transformation of the points
- cv::Mat xy_transformed;
- cv::perspectiveTransform(xy, xy_transformed, inv_perspective);
- //Prevent errors when float32 to int16
- float *pmytest = (float*)xy_transformed.data;
- for (int y = 0; y < xy_transformed.rows; y++)
- for (int x = 0; x < xy_transformed.cols; x++)
- {
- if (abs(*pmytest) > 5000) *pmytest = 5000.00;
- pmytest++;
- if (abs(*pmytest) > 5000) *pmytest = 5000.00;
- pmytest++;
- }
- // split x/y to extra maps
- assert(xy_transformed.channels() == 2);
- cv::Mat maps[2]; // map_x, map_y
- cv::split(xy_transformed, maps);
- // remap() with integer maps is faster
- //cv::convertMaps(maps[0], maps[1], map1, map2, CV_16SC2);
- cv::convertMaps(maps[0], maps[1], map1, map2, CV_16SC2);
- short int *pt = (short int *)map1.data;
- short int *dispt = (short int *)distortion_map1.data;
- for (int i = 0; i < map1.rows; i++)
- {
- for (int j = 0; j < map1.cols; j++)
- {
- Point tem1;
- tem1.x = *pt++;
- tem1.y = *pt++;
- if ((tem1.x<0) || (tem1.x>distortion_map1.cols - 1) || (tem1.y<0) || (tem1.y>distortion_map1.rows - 1)) continue;
- int tem2 = (tem1.y*distortion_map1.cols + tem1.x) * 2;
- dispt += tem2;
- Point tem3;
- tem3.x = *dispt++;
- tem3.y = *dispt++;
- dispt -= tem2+2;
- *(--pt) = tem3.y;
- *(--pt) = tem3.x;
- pt++;
- pt++;
- }
- }
- }