opencv 表格识别之表格透视矫正(一)

3 篇文章 6 订阅
3 篇文章 0 订阅

 这个项目的目的是让用户选择模板表格(未填写的表格)中的多个或者一个小格子,然后将扫描(注意:是扫描的表格)传入的填写好的表格对应的格子提取出来,对格子中的选择进行处理。

在对表格进行处理之前,我们应该先将传入的填写好的表格对照着模板表格进行矫正。一下提供了一种矫正表格的方法,这种方法效果还行,但是当运用到一张纸上有多个的表格的时候,只能对其中最大的表格进行处理,所以下一篇文章,将给出一种能进行多个表格矫正的方法。

        Mat src = imread("9.jpg");
	Mat srcClone = src.clone();


	// 检查是否为灰度图,如果不是,转化为灰度图
	Mat gray;
	if (src.channels() == 3) {
		cvtColor(src, gray, CV_BGR2GRAY);
	}
	else {
		gray = src;
	}


	//转化为二值图 
	Mat bw;
	adaptiveThreshold(~gray, bw, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);

	
        //形态学
	Mat Structure = getStructuringElement(MORPH_RECT, Size(3, 3));

	// Apply morphology operations
	erode(bw, bw, Structure, Point(-1, -1));
	dilate(bw, bw, Structure, Point(-1, -1));

阈值化的结果如下:

阈值化

 

//提取轮廓 
	vector<Vec4i> hierarchy;
	std::vector<std::vector<cv::Point> > contours;
	cv::findContours(bw, contours, hierarchy, CV_RETR_LIST, CHAIN_APPROX_SIMPLE);// , Point(0, 0));

	//逼近多边形
	vector<vector<Point> > contours_poly(contours.size());

	int indexMax = 0;
	double areaMax = 0;
	for (size_t i = 0; i < contours.size(); i++)
	{
		//面积
		double area = contourArea(contours[i]);

		//筛选可能存在且不代表表的单独的行的行。
		if (area < 20) // value is randomly chosen
			continue;

		Scalar color(0, 255, 0);
		drawContours(srcClone, contours, i, color, 2, 8);

		//逼近区域成为一个形状
		approxPolyDP(Mat(contours[i]), contours_poly[i], 10, true);


		//不知为何,加了四个点的筛选之后,就没有最大的框了
		//if (contours_poly[i].size() != 4)
		//	continue;

		//找出面积最大的四边形
		if (area > areaMax)
		{
			areaMax = area;
			indexMax = i;
		}
	}

在原图上画出所有的轮廓,效果如下:

在原图上画出所有的轮廓

 

	Scalar color(0, 0, 255);
	drawContours(srcClone, contours, indexMax, color, 2, 8);
	imshow("contou1", srcClone);


	Mat polyPic = Mat::zeros(src.size(), CV_8UC3);
	drawContours(polyPic, contours, indexMax, color, 2, 8);

	imshow("Contour2", polyPic);
        vector<int>  hull;
	convexHull(contours_poly[indexMax], hull, false);    //检测该轮廓的凸包

	for (int j = 0; j < hull.size(); j++)
	{
		circle(src, contours_poly[indexMax][j], 10, Scalar(255, 0, 0));
	}

在原图上找出最大的轮廓:

原图最大轮廓

提取出最大轮廓:

最大轮廓

绘制凸包:

hull

        //矫正后的坐标
        Mat outPic = Mat(Size(800, 800), src.type());
	Point2f srcPoints[4], dstPoints[4];
	dstPoints[0] = Point2f(0, 0);
	dstPoints[1] = Point2f(outPic.cols, 0);
	dstPoints[2] = Point2f(outPic.cols, outPic.rows);
	dstPoints[3] = Point2f(0, outPic.rows);
        
        //排序
	bool sorted = false;
	int n = 4;
	while (!sorted)
	{
		for (int i = 1; i < n; i++)
		{
			sorted = true;
			if (contours_poly[indexMax][i - 1].x > contours_poly[indexMax][i].x)
			{
				swap(contours_poly[indexMax][i - 1], contours_poly[indexMax][i]);
				sorted = false;
			}
		}
		n--;
	}

	if (contours_poly[indexMax][0].y < contours_poly[indexMax][1].y)
	{
		srcPoints[0] = contours_poly[indexMax][0];
		srcPoints[3] = contours_poly[indexMax][1];
	}
	else
	{
		srcPoints[0] = contours_poly[indexMax][1];
		srcPoints[3] = contours_poly[indexMax][0];
	}
	if (contours_poly[indexMax][2].y < contours_poly[indexMax][3].y)
	{
		srcPoints[1] = contours_poly[indexMax][2];
		srcPoints[2] = contours_poly[indexMax][3];
	}
	else
	{
		srcPoints[1] = contours_poly[indexMax][3];
		srcPoints[2] = contours_poly[indexMax][2];
	}
	
	Mat transMat = getPerspectiveTransform(srcPoints, dstPoints);    //得到变换矩阵
	warpPerspective(src, outPic, transMat, outPic.size()); //进行坐标变换

矫正后的图像:

结果

 

由于代码过于简单,处理过的图像也比较粗糙。

参考:https://blog.csdn.net/xingchenbingbuyu/article/details/50783585

  • 2
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值