c++ opencv像素值运算–辅助文档角点判断

现有一组vector< Point > 类型的corners 角点坐标(通过拟合文档边框,计算交点获得)
还有一Mat类型的二值化文档轮廓图(将文档图片经过Canny轮廓提取+findContours() 轮廓检测函数处理获得)
由于角点是以霍夫变换后的直线计算交点得来的,所以有些点并不在真正的文档角点上,需要判断哪些角点找对了位置,哪些没有。

为此暂时考虑尝试通过 获取文档轮廓图中 的角点附近 像素值的方法进行计算。

文档轮廓图(二值化)如下

opencv 顶点 opencv角点坐标_opencv 顶点

首先参考Mat类型图像的像素点访问方法

代码如下:

写出获取角点附近8*8像素点的方式

//vector<Point> corners;//角点
//Mat Outlineimg;//二值图
Mat PointMat(Size(8, 8), Outlineimg.type());//8*8矩阵 用于存储角点附近图像

int BeginY = corners[num].y - 4, BeginX = corners[num].x - 4;//取点起始位
int EndY = corners[num].y + 4 , EndX = corners[num].x + 4;//取点终止位

for (int i =  BeginY ; i < EndY; i++)
{
	for (int j = BeginX; j < EndX; j++)
	{
		PointMat.at<uchar>(i - BeginY, j - BeginX) = Outlineimg.at<uchar>(i, j);
	}
}
imshow("show PointMat", PointMat);//打印角点附近图像

显示的角点附近图像如下:

opencv 顶点 opencv角点坐标_c++_02

存在问题:如果角点为与图像边界相邻的点时,那么在访问图像像素的时候,就可能发生访问越界的情况,而导致程序崩溃

解决方法:可以根据corners角点当前坐标与Mat图像尺寸来计算获取角点附近8*8像素图像所需的偏移量

代码如下

vector<Point> DocScan::CalPixValue(Mat& Outlineimg, vector<Point>& corners)//计算corners的像素值
{
	Mat PointMat(Size(8, 8), Outlineimg.type());
	vector<Point>  Markcorners;
	for (char num=0;num<corners.size();num++)
	{
		int dx, dy;//偏移量
        //---------------偏移量计算-------------
		if (corners[num].x - 0 < 4) {
			dx = 4 - corners[num].x;
		}else if (Outlineimg.cols - corners[num].x < 4) {
			dx = Outlineimg.cols - corners[num].x - 4;
		}else
			dx = 0;

		if (corners[num].y - 0 < 4) {
			dy = 4 - corners[num].y;
		}else if (Outlineimg.rows - corners[num].y < 4) {
			dy = Outlineimg.rows - corners[num].y - 4;
		}else
			dy = 0;

		int BeginY = corners[num].y - 4 + dy, BeginX = corners[num].x - 4 + dx;//取点起始位
		int EndY = corners[num].y + 4 + dy, EndX = corners[num].x + 4 + dx;//取点终止位
		//----------------访问角点附近的像素-----------------
		int whitenum = 0;
		for (int i = BeginY; i < EndY; i++)
		{
			for (int j = BeginX; j < EndX; j++)
			{
				PointMat.at<uchar>(i - BeginY, j - BeginX) = Outlineimg.at<uchar>(i, j);
				if (Outlineimg.at<uchar>(i, j) == 255)//找到白色像素
				{
					++whitenum;
				}
			}
		}
		if (whitenum >= 9)//如果白色像素数量>=9则可能为角点(不是太准确,具体参数根据个人需求修改)
		{
			cout << "got edge,whitenum= " << whitenum << endl;
			Markcorners.push_back(corners[num]);//符合条件的角点放入Markcorners中
		}
	}
	
	imshow("show PointMat", PointMat);//打印角点附近图像
	return Markcorners;//返回符合条件的角点
}

获取该函数返回的Markcorners,然后在在图上使用黄色圆圈来标出
如下图,黄色为可能的角点,红色为错误的角点(紫红色的点是霍夫变换拟合出来的线段端点,请忽略),可以看到一般情况下还是能分辨出正确的角点的。

opencv 顶点 opencv角点坐标_opencv 顶点_03

但遇到这种情况的角点就检测不出来了(像素点数量=7)

opencv 顶点 opencv角点坐标_c++_04

那么单纯使用像素计算就没法满足需求了,可以考虑使用霍夫变换查找线条的方法计算两线夹角来判断其是否为角点。