前言
? 这次介绍的是和图像区域操作的相关问题和解决办法。
图像区域相关操作
获得外接矩形
rect = cv2.boundingRect(contours[c])
? 在c++中,是返回的一个Rect类,可以使用rect.tl()和rect.br()返回左上角和右下角的坐标,而python中是返回一个tuple,只能直接使用:
? 而这个tuple返回了四个元素,分别的含义是:
- rect[0]为左上角的x坐标
- rect[1]为左上角的y坐标
- rect[2]为width
- rect[3]为height
? 把这个矩形在图像上画出来可以用下面的代码:
cv2.rectangle(ori_img, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (0, 0, 255), 1)
膨胀与腐蚀
? 我使用这两个操作是要用于区域的合并和分离。一般来说,合并是用膨胀操作,分离使用腐蚀操作。
? 这两个操作还可以用于去除图像周边的毛刺(一个是填充,一个是消除)
? 这两个过程很类似,只不过效果完全想法,类似一个做加法,一个做减法。
我们要在这个图上做膨胀操作:
- 首先,这个过程是一个像素一个像素来处理的,假设我们处理到了下图中蓝色框选中位置的数据了,我们需要在这个像素外面准备另外一个框框,假设是一个3*3大小的框:
这个框就被成为核(kernel),被处理的这个像素的值就依赖这个框的数据来进行计算(下面会提到这个计算过程),如果是边或者顶点的像素,就对应的去匹配一下,我懒的配图了。
核是可以被设计的,也就是说这个3*3的矩阵是可以被填充数据的,每个元素可以被填充0或者1。比如长这样:
0和1分别表示设计者是否要处理这个位置的数据,1是要处理,0是不处理。
-
核的处理过程 这个核覆盖上去之后,可以看到,为1的位置如下:
两种操作的区别就在如何对上述提到的这个像素点的计算过程:
- 膨胀,opencv官网上定义的像素点的计算过程是:
找到核中为1覆盖的区域里的最大值,并把这个值赋值给这个像素点,相当于把图像本身的数据给扩充了一下,也就称之为膨胀。
如果是上图中标记的这个蓝色框中的数字,如果经过膨胀后就会变成255。
找到核中为1覆盖的区域里的最小值,并把这个值赋值给这个像素点,相当于把背景的数据给扩充了一下,也就称之为腐蚀
如果是上图中标记的这个蓝色框中的数字,如果经过腐蚀后就会变成0。
实现的效果就是,明显的胖了一圈:
上面dilate中的第二个函数iterations=1,表示做几次膨胀,就是上面描述的基本过程来几遍。在我设计的场景中,两个迭代,这两个矩形就接一起了,达到了我想要的合并区域的目的。
如果使用findContouers来输出上面的图像,就只有一个轮廓了。
-
腐蚀的代码类似: kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
bin_clo = cv2.erode(img, kernel2, iterations=2)
明显瘦了一圈。
重叠区域问题
? 在我碰到的问题里,还需要计算两个通道之间的重叠区域,我想到的办法是使用opencv中提供的bitwise_and方法
? 这个方法的逻辑是,将两个二值化图按对应位置匹配求逻辑与,作为新图像的位置的值:
? 当然这个方法还可以接受第三个参数,也就是mask,mask矩阵中元素为true的位置才进行处理(mask的使用可参见第一篇:
dst_green = cv2.bitwise_and(output_blue, dst_green)
? 两个参数都是二值化后的图层,后续我就可以使用连通域的函数来针对dst_green做处理,并计算面积了。
|