怎么增加网站关键词库,哪个网站可以接程序项目来做,优化大师,个人工作室 网站建设文章目录 1.背景2.需求分析3.解决方案3.1.镜头畸变矫正3.2.知道矫正后的画面坐标(x, y)#xff0c;求其在原画面的坐标(x, y)3.2.知道原画面坐标(x1, y1)#xff0c;求其在矫正后的画面坐标(x2, y2) 4.效果5.代码 1.背景
目前有个项目#xff0c;需要用到热成像相机。但是这… 文章目录 1.背景2.需求分析3.解决方案3.1.镜头畸变矫正3.2.知道矫正后的画面坐标(x, y)求其在原画面的坐标(x, y)3.2.知道原画面坐标(x1, y1)求其在矫正后的画面坐标(x2, y2) 4.效果5.代码 1.背景
目前有个项目需要用到热成像相机。但是这个热成像相机它的畸变比较厉害因此需要用标定板进行标定从而消除镜头畸变。 同时需要实现用户用鼠标点击矫正后的画面后显示用户点击位置的像素所代表的温度。 另外热成像sdk中还有个功能选定一个rect可以返回这个rect中的最高最低温度以及其各自的位置。假如我们需要这个功能那么又需要知道从src到dst的关系了。
2.需求分析
消除镜头畸变后就不能直接使用热成像sdk提供的函数来查询像素对应的温度。 因为在查询函数中有个像素坐标的形参要求传入原来的热成像图像A的像素坐标函数返回此像素位置的温度。 而我们经过畸变消除后得到画面B。B上面的特定像素所处的坐标和原图不一定一样。 因此假如用户想查询画面B上的某个像素点的有效温度就必须要取得此像素点在原图A上的位置坐标。 而在知道原图的最高最低温度点的位置后需要知道其在纠正后的画面中的位置才能准确绘制出来。 总结一下需要实现以下功能 a、镜头畸变矫正 b、知道矫正后的画面坐标xy求其在原画面的坐标x’y’ c、知道原画面坐标x1y1求其在矫正后的画面坐标x2y2
3.解决方案
其实很简单opencv本身就提供了。
3.1.镜头畸变矫正
在经过 findChessboardCorners、calibrateCamera之后我们就已经获得了相机矩阵cameraMatrix、畸变矩阵distCoeffs。 然后我们利用getOptimalNewCameraMatrix获得了一个相对容易控制画面取舍的新相机矩阵newCamMatrix。 接下来就有两种方式对画面进行矫正 a、直接undistort。 b、先利用initUndistortRectifyMap得到map1、map2然后再利用remap进行画面矫正。 后面的代码把两种都演示了。
3.2.知道矫正后的画面坐标(x, y)求其在原画面的坐标(x’, y’)
其实我们真正需要的是第二种。 关键就在于map1、map2。 这两个矩阵是什么玩意呢 其实你先看看他们的尺寸、通道数再查阅一下资料就知道了 map1、map2的尺寸与目标图像矫正后的图像的尺寸一致而通道数为1这个其实不一定与其他参数有关暂时先这样认为。我们假设最终图像xy处的像素来源于源图像x’y’处那么map1中存储了坐标x’y’中的x’而map2中存储了y’。 虽然我描述得很混乱但是你配合代码应该明白我在说什么。 所以我们直接利用这个map1、map2就可以实现从消除畸变后的画面坐标转换到原画面的坐标了。 initUndistortRectifyMap(cameraMatrix, distCoeffs, cv::Mat(), newCamMatrix, imageSize, CV_32FC1, map1, map2);......Point dstPt(400, 109);double pt_x map1.atfloat(dstPt);double pt_y map2.atfloat(dstPt);3.2.知道原画面坐标(x1, y1)求其在矫正后的画面坐标(x2, y2)
这个可以利用opencv的undistortPoints函数进行求解。 需要注意的是第三个参数使用相机矩阵、第五个参数使用空矩阵、第六个参数使用新相机矩阵。这些参数需要和initUndistortRectifyMap的想对应起来。 vectorPoint2f srcPts;srcPts.push_back(Point2f(300, 145));vectorPoint2f dstPts;undistortPoints(srcPts, dstPts, cameraMatrix, distCoeffs, Mat(), newCamMatrix);4.效果
由于一些原因我不能直接展示我的效果图。这里用opencv自带的图像来演示吧。
5.代码
int cameraCalibration()
{Size boardSize {9, 6};float squareSize 0.05;bool displayCorners false;vectorstring imageList;for(int i 0; i 9; i){QString leftImgFile QString(../data/left%1.jpg).arg(i 1, 2, 10, QLatin1Char(0));imageList.push_back(leftImgFile.toStdString());}// 存放相机的图像的角点位置vectorvectorPoint2f imagePoints;// 存放实际的物体坐标vectorvectorPoint3f objectPoints;Size imageSize;int i, j, nimages imageList.size();imagePoints.resize(nimages);// 存放能够顺利找到角点的图像的路径vectorstring goodImageList;for(i 0, j 0; i nimages; i ){const string filename imageList[i];Mat img imread(filename, IMREAD_GRAYSCALE);// 检查图像是否为空if(img.empty())continue;imageSize img.size();// 找角点bool found false;vectorPoint2f corners imagePoints[j];found findChessboardCorners(img, boardSize, corners,CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);if(found false){continue;}// 再进行一次亚像素查找cornerSubPix(img, corners, Size(11,11), Size(-1,-1),TermCriteria(TermCriteria::COUNTTermCriteria::EPS,30, 0.01));// 显示查找的结果if(displayCorners){cout found: filename.c_str() endl;Mat cimg;cvtColor(img, cimg, COLOR_GRAY2BGR);drawChessboardCorners(cimg, boardSize, corners, found);imshow(corners, cimg);char c (char)waitKey(100);}goodImageList.push_back(imageList[i]);j;}nimages j;if( nimages 2 ){cout Error: too little data to run the calibration\n;return -1;}// 截取长度保留有用的数据imagePoints.resize(nimages);// 填充3d数据objectPoints.resize(nimages);for(int i 0; i nimages; i ){for(int j 0; j boardSize.height; j )for(int k 0; k boardSize.width; k )objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0));}cv::Mat cameraMatrix(3, 3, CV_32FC1, cv::Scalar::all(0)); //内参矩阵3*3cv::Mat distCoeffs(1, 5, CV_32FC1, cv::Scalar::all(0)); //畸变矩阵1*5vectorcv::Mat rotationMat; //旋转矩阵vectorcv::Mat translationMat; //平移矩阵//!标定/*** points3D_all_images: 真实三维坐标* points_all_images: 提取的角点* image_size: 图像尺寸* camera_K : 内参矩阵K* distCoeffs: 畸变参数* rotationMat: 每个图片的旋转向量* translationMat: 每个图片的平移向量* */calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rotationMat, translationMat, 0);Mat testImg imread(imageList[0], IMREAD_COLOR);cv::Rect validROI;Mat newCamMatrix getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1.0, imageSize, validROI);// Mat undistortedImg;
// undistort(testImg, undistortedImg, cameraMatrix, distCoeffs, newCamMatrix);// cv::rectangle(undistortedImg, validROI, Scalar(255, 0, 0));
// imshow(undistorted image, undistortedImg);Mat undistortedImg2;Mat map1, map2;initUndistortRectifyMap(cameraMatrix, distCoeffs, cv::Mat(), newCamMatrix, imageSize, CV_32FC1, map1, map2);// cout map1 size map1.size() , map1.channels() endl;// cout map2 size map2.size() , map2.channels() endl;remap(testImg, undistortedImg2, map1, map2, INTER_LINEAR);cv::rectangle(undistortedImg2, validROI, Scalar(255, 0, 0));cout calibration completed\r\n;// map1 map2中存储的分别是最终图像对应像素的xy坐标// 知道dst的坐标求src的相应坐标Point dstPt(400, 109);double pt_x map1.atfloat(dstPt);double pt_y map2.atfloat(dstPt);cout dstPt: dstPt ; origin pt: pt_x , pt_y endl;cv::circle(testImg, Point(pt_x, pt_y), 5, Scalar(255, 0, 0), 2);cv::circle(undistortedImg2, dstPt, 5, Scalar(255,0, 0), 2);// 知道src的坐标求dst的相应坐标vectorPoint2f srcPts;srcPts.push_back(Point2f(300, 145));vectorPoint2f dstPts;undistortPoints(srcPts, dstPts, cameraMatrix, distCoeffs, Mat(), newCamMatrix);cout the dst: dstPts endl;circle(testImg, srcPts[0], 8, Scalar(0, 255, 0));circle(undistortedImg2, dstPts[0], 8, Scalar(0, 255, 0));imshow(src to dst: src, testImg);imshow(src to dst: dst, undistortedImg2);
} 参考 【关于OpenCV中的去畸变】 【用OpenCV进行相机标定(张正友标定,有代码)】 【《opencv学习笔记》-- 重映射】