写了好多年opencv 有好多解决问题的手段 项目中用完了过后又会忘记
记录一下吧,争取不做遗忘黑熊
这段c++代码目的是将图片中的黑白标定板定位出来,想要得到四个角点
bool _CompairPointXX(Point2f &a, Point2f &b)
{
return a.x > b.x;
}
bool _CompairPointYY(Point2f &a, Point2f &b)
{
return a.y > b.y;
}
bool GetPoint_Data(Mat imageInput, Size board_size, vector<Point2f>&newarr)
{
//ofstream fout("caliberation_result.txt"); // 保存标定结果的文件
cout << "开始提取角点………………" << endl;
int image_count = 0; // 图像数量
vector<Point2f> image_points; // 缓存每幅图像上检测到的角点
vector<vector<Point2f>> image_points_seq; // 保存检测到的所有角点
vector<Point2f>fourpoint;
/* 提取角点 */
bool ok = cv::findChessboardCorners(imageInput, board_size, image_points, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
//board_size 是你标定板的行列的 “有效”格子数目(例如我是(9,13))
if (0 == ok)
{
cout << "照片提取角点失败,请删除后,重新标定!" << endl; //找不到角点
/*imshow("失败照片", imageInput);
waitKey(0);*/
image_points.clear();
image_points_seq.clear();
return false;
}
else
{
Mat view_gray;
if (imageInput.channels()==3)
{
cvtColor(imageInput, view_gray, CV_RGB2GRAY);
}
else
{
imageInput.copyTo(view_gray);
}
cout << "imageInput.channels()=" << imageInput.channels() << endl;
/* 亚像素精确化 */
//find4QuadCornerSubpix(view_gray, image_points, Size(5, 5)); //对粗提取的角点进行精确化
cv::cornerSubPix(view_gray, image_points, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 20, 0.01));
image_points_seq.push_back(image_points); //保存亚像素角点
///* 在图像上显示角点位置 */
//drawChessboardCorners(view_gray, board_size, image_points, true);
//这里的image_points是标定板格子所有角点,需要继续筛选我要的四个角点。
std::sort(image_points.begin(), image_points.end(), _CompairPointXX);
vector<int>pointxAy;
int adnum;
for (int i = 0; i < image_points.size(); i++)
{
adnum = image_points[i].x + image_points[i].y;
pointxAy.push_back(adnum);
}
int minPosition = min_element(pointxAy.begin(), pointxAy.end()) - pointxAy.begin();
int maxPosition = max_element(pointxAy.begin(), pointxAy.end()) - pointxAy.begin();
pointxAy.clear();
Point2f temppt;
int minxx = image_points[minPosition].x;//左上点
int minxy = image_points[minPosition].y;
temppt.x = minxx;
temppt.y = minxy;
fourpoint.push_back(temppt);
int maxxx = image_points[maxPosition].x;//右下点
int maxxy = image_points[maxPosition].y;
temppt.x = maxxx;
temppt.y = maxxy;
fourpoint.push_back(temppt);
//右上点的筛选 不做这个操作的时候获取到的点吧,它有时候就不是准确的右上点,因为拍摄标定板子本身放置角度的问题 图像上 一行格子的水平像素和竖直像素并不在同一行或者列
std::sort(image_points.begin(), image_points.end(), _CompairPointYY);
//排序后;获取在一定范围内的最大值的位置,由位置索取值
vector<int>pointy;
int maxsize = 0;
maxsize = image_points.size();
for (int i = image_points.size() - 1; i >= 0; i--)
{
if (i<maxsize - 1 && (abs(image_points[i].y - image_points[maxsize - 1].y) <= 50.0))
//50.0根据你自己图像的实际情况设置改掉
{
pointy.push_back(image_points[i].x);
}
else if (i == (maxsize - 1))
{
pointy.push_back(image_points[i].x);
}
else
{
break;
}
}
int maxPosy = max_element(pointy.begin(), pointy.end()) - pointy.begin();
pointy.clear();
int minyx = image_points[maxsize - maxPosy - 1].x;
int minyy = image_points[maxsize - maxPosy - 1].y;
temppt.x = minyx;
temppt.y = minyy;
fourpoint.push_back(temppt);
int maxyx, maxyy;
vector<int>pointx;
for (int i = 0; i < image_points.size(); i++)
{
if (i>0 && (abs(image_points[i].y - image_points[0].y) <= 100.0))
//100.0 根据你自己的实际情况试试改掉
{
pointx.push_back(image_points[i].x);
}
else if (i == 0)
{
pointx.push_back(image_points[i].x);
}
else
{
break;
}
}
int minPosx = min_element(pointx.begin(), pointx.end()) - pointx.begin();
pointx.clear();
maxyx = image_points[minPosx].x;
maxyy = image_points[minPosx].y;
temppt.x = maxyx;
temppt.y = maxyy;
fourpoint.push_back(temppt);
for (int i = 0; i < 4; i++)
{
circle(view_gray, fourpoint[i],10,180,3,8,0); //把点画到图像上,看看结果
}
imwrite("view_gray.jpg", view_gray);
view_gray.release();
}
newarr = fourpoint;
fourpoint.clear();
image_points.clear();
image_points_seq.clear();
//cout << "角点提取完成!!!" << endl;
return true;
}
图有点糊,能明白意思就行(如果想得到最边界的值,那就根据现有的很多点的xy像素值,想上下左右扩一下,就可以得到最边上的点了)
自己弄个标定板吧,我当时阴天室内,光线不好。上图便于理解。
点赞奥,收藏奥。