opencv 影象畸變矯正加速、透視變換加速方法總結
阿新 • • 發佈:2019-02-08
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); }
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++; } } }