文章目录

  • 前言
  • 图像区域相关操作
  • 获得外接矩形
  • 膨胀与腐蚀
  • 重叠区域问题


前言

这次介绍的是和图像区域操作的相关问题和解决办法。

图像区域相关操作

获得外接矩形

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份,独立来处理的,假设有这么一副灰度图:

python cv2 平移 python cv2 rectangle_数据

我们要在这个图上做膨胀操作:

  • 首先,这个过程是一个像素一个像素来处理的,假设我们处理到了下图中蓝色框选中位置的数据了,我们需要在这个像素外面准备另外一个框框,假设是一个3*3大小的框:

python cv2 平移 python cv2 rectangle_计算机视觉_02

这个框就被成为核(kernel),被处理的这个像素的值就依赖这个框的数据来进行计算(下面会提到这个计算过程),如果是边或者顶点的像素,就对应的去匹配一下,我懒的配图了。

是可以被设计的,也就是说这个3*3的矩阵是可以被填充数据的,每个元素可以被填充0或者1。比如长这样:

python cv2 平移 python cv2 rectangle_python cv2 平移_03

0和1分别表示设计者是否要处理这个位置的数据,1是要处理,0是不处理。

  • 核的处理过程
    这个核覆盖上去之后,可以看到,为1的位置如下:

python cv2 平移 python cv2 rectangle_opencv_04

两种操作的区别就在如何对上述提到的这个像素点的计算过程:

  • 膨胀,opencv官网上定义的像素点的计算过程是:

python cv2 平移 python cv2 rectangle_opencv_05

找到核中为1覆盖的区域里的最大值,并把这个值赋值给这个像素点,相当于把图像本身的数据给扩充了一下,也就称之为膨胀。

python cv2 平移 python cv2 rectangle_opencv_06

如果是上图中标记的这个蓝色框中的数字,如果经过膨胀后就会变成255。

  • 腐蚀,这个过程相当于反过来:

python cv2 平移 python cv2 rectangle_opencv_07

找到核中为1覆盖的区域里的最小值,并把这个值赋值给这个像素点,相当于把背景的数据给扩充了一下,也就称之为腐蚀

python cv2 平移 python cv2 rectangle_python_08

如果是上图中标记的这个蓝色框中的数字,如果经过腐蚀后就会变成0。

  • 迭代过程,遍历原图中所有的像素点,都做这样一个计算,就得到了膨胀或者腐蚀之后的图。
  • 代码实现
    代码实现很简单:
  • 膨胀:
kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
bin_clo = cv2.dilate(img, kernel2, iterations=1)

其中的kernel2就是上面提到的核,通过opencv内置的枚举类型来初始化一个核,上面代码中的cv2.MORPH_RECT, (3, 3)就是初始化了一个3*3的矩形,这个矩形中的9个元素都是1。opencv还提供了其他的类型:

python cv2 平移 python cv2 rectangle_数据_09

实现的效果就是,明显的胖了一圈:

python cv2 平移 python cv2 rectangle_python_10

上面dilate中的第二个函数iterations=1,表示做几次膨胀,就是上面描述的基本过程来几遍。在我设计的场景中,两个迭代,这两个矩形就接一起了,达到了我想要的合并区域的目的。

python cv2 平移 python cv2 rectangle_opencv_11

如果使用findContouers来输出上面的图像,就只有一个轮廓了。

  • 腐蚀的代码类似:
kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
bin_clo = cv2.erode(img, kernel2, iterations=2)

python cv2 平移 python cv2 rectangle_python cv2 平移_12

明显瘦了一圈。

重叠区域问题

在我碰到的问题里,还需要计算两个通道之间的重叠区域,我想到的办法是使用opencv中提供的bitwise_and方法

这个方法的逻辑是,将两个二值化图按对应位置匹配求逻辑与,作为新图像的位置的值:

python cv2 平移 python cv2 rectangle_数据_13

当然这个方法还可以接受第三个参数,也就是mask,mask矩阵中元素为true的位置才进行处理(mask的使用可参见第一篇:

dst_green = cv2.bitwise_and(output_blue, dst_green)

两个参数都是二值化后的图层,后续我就可以使用连通域的函数来针对dst_green做处理,并计算面积了。