昨年写的OpenCV处理表格的东西搞丢了,这几天拿到了一点图片数据,想起来需要继续做完但是又找不到代码了,翻遍了硬盘还是没找到代码,今天呆在电脑前,还是觉得应该有始有终,再做一个吧,不知道这次能坚持多久。2020年4月29日 00:00:49
目的:使用OpenCV获取到表格主体轮廓,并用红线画出轮廓。
4月29日的进度
为了方便后续桌面开发,暂时用C#作为编程语言。
//通过图片框拿到Mat
Bitmap bi = new Bitmap(pictureBox1.Image);
Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bi);
//另外再复制一个,用于绘画
Mat mat2 = mat.Clone();
后续不同操作的例子:
开运算
//开运算
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect,new OpenCvSharp.Size(80,80));
Cv2.MorphologyEx(mat,mat2, MorphTypes.Open, kernel);
pictureBox1.Image = mat2.ToBitmap();
边缘检测
//进行边缘检测
Cv2.Canny(mat, mat2, 194, 105,3);
pictureBox1.Image = mat2.ToBitmap();
经过了边缘检测后的霍夫变换取直线
//进行边缘检测
Cv2.Canny(mat, mat2, 194, 105,3);
//创建一个纯黑背景的Mat
Mat black = new Mat();
black.Create(mat.Height, mat.Width, MatType.CV_8UC3);
//霍夫变换取直线
var p = Cv2.HoughLinesP(mat2, 1,Math.PI/180,100,50,100);
foreach (var item in p) {
Cv2.Line(black, item.P1, item.P2,Scalar.Red);
}
pictureBox1.Image = black.ToBitmap();
到这里感觉有那个意思了,但是杂线还是太多了,远没达到理想效果,还需要继续处理,分析这些比较集中的竖线,看得出是因为表格上的内容比较多,所以要做形态学腐蚀操作,具体还需研究,今天更在这里。2020年4月29日 00:23:49
5月2日的进度
为了搞清楚不同操作的效果,花了二十分钟写了个OpenCV工具箱,代码很少,但功能足够用了。
首先进行闭运算,把OpenCvSharp.Size的width调高,height调低,我们发现可以取出表格中的所有横线了。
同理,把width设置为1,height调到100,可以取出表格中的竖线。
![]() | ![]() |
既然拿到了这么清晰的直线,还等什么,直接用霍夫变换取直线啦。
if (mat_clone == null) return;
Mat mat_clone2 = mat_clone.Clone();
//进行边缘检测
Cv2.Canny(mat_clone, mat_clone2, 194, 105, 3);
//创建一个纯黑背景的Mat
Mat black = new Mat();
black.Create(mat_clone.Height, mat_clone.Width, MatType.CV_8UC3);
//霍夫变换取直线
var p = Cv2.HoughLinesP(mat_clone2, 1, Math.PI / 180, 100, 50, 100);
foreach (var item in p){
Cv2.Line(black, item.P1, item.P2, Scalar.Red,3);
}
pictureBox1.Image = black.ToBitmap();
有很多重复的线条,不是很理想,HoughLinesP(InputArray image, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0);
参数名 | 描述 |
image | 被处理的图像 |
rho | 像素每次迭代的大小(每一次选取像素的过程跳跃多少,一般设置为1) |
theta | 角度累加器的大小(即直线参数theta,一般为pi/180) |
thresold | 超过设定阈值才被检测出线段,值越大,检出的线段越长,个数越少。 |
minLineLength | 线段的最小长度 |
maxLineGap | 同一方向上两条线段判定为一条线段的最大允许间隔 |
看api发现可以调高thresold参数,那就再试试。
有部分横线被消除了,说明仅依靠这个参数是行不通的,反而丢失了很多数据,调低至50能拿到更多的线,虽然直线是断断续续的但更加连续。
此时用图像梯度MorphTypes.Gradient可以拿到二值化后的横线,调整height可以加厚线条。
Cv2.MorphologyEx(mat_native, mat_clone, MorphTypes.Gradient, kernel);
同上,拿到竖线。但竖线不理想,需要想其他办法。
![]() | ![]() |
说明通过闭运算->图像梯度->霍夫变换的方法宽和高的参数不能照搬否则有瑕疵。那继续找修补方法。
原图基础上,闭运算height从100调低到40,进行霍夫变换,可拿到大部分直线。
![]() | ![]() |
继续闭运算把高调低到40后,再进行膨胀,膨胀的高调到60,再进行霍夫变换。这样就比较清晰了。
![]() | ![]() |
从下午开始分析、设计、敲代码到现在已经深夜了,查阅了多方大牛的资料,我脑袋有点麻,我的方向好像错了。大牛们用的寻找轮廓,我用的霍夫变换,大牛对表格做了透视变换,让弯曲的表格进行修正,我没有做,让它无脑曲线了。这个点了,我需要好好想想接下来怎么做,有点烧脑了。2020年5月2日 23:42:56