![深度学习技术图像处理入门](https://wfqqreader-1252317822.image.myqcloud.com/cover/584/26793584/b_26793584.jpg)
3.3 使用OpenCV“抠图”——基于颜色通道以及形态特征
3.2节用简单的矩阵操作方法对二维码图片进行了一系列操作,包括去Logo、降低像素等。本节谈一谈如何对图片进行一些比较复杂的操作,比如我们3.1.1节中用数组切片来抓取足球,使用的命令是:
ball = img[280:340, 330:390]
为什么是这个坐标?这个坐标是我们人眼看出来的,能否让计算机自动识别这个足球的位置?这里提供一种基于OpenCV的“套路”。
首先,还是需要认真观察数据,就是刚才抓下来的球(如图3-11所示):
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P71_4132.jpg?sign=1738887663-adylhtA85FuNyKuyOSyvIjuNFhz3zYj3-0-12d118277e6970546ddbf2ffdbe71311)
图3-11 从原图中截取足球区域
plt.imshow(ball)
这个球具有以下特点:
- 看起来是个圆形。
- 颜色是黄色+藏蓝色。
- 由于在草地上,因此背景是绿色。
根据这三个特点,我们大致确定思路,几个步骤依次对应下面几个特点:
- 看看有没有圆形的识别算法——Hough变换。
- 用黄色+藏蓝色将球从背景提取出来。
- 用绿色过滤背景色。
我们观察这张球小型图片中的60×60 =3600个像素,其中RGB的分布如何。这里仿照第2章用过的seaborn的pairplot函数来表达RGB三种颜色的两两组合,其结果如图3-12所示:
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P71_10203.jpg?sign=1738887663-GcjY9pVSWDhPkMRs8lCbXXC7jrsq0PK0-0-c8a958d1794162ec4a0dbc49e291e0fc)
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P72_4146.jpg?sign=1738887663-qclxleTT554vuz5WnQuEA64HRwsw9U87-0-6209de7497c17b715e02d572b5d4d828)
图3-12 图3-11中各像素点RGB的分布情况
图中的黄色与蓝黑色均为足球的颜色,而绿色则是足球场的颜色。我们接下来要做的就是找一个规则来区分足球与足球场。这里简单地写一个规则组合,其结果如图3-13所示:
fig = plt.figure(figsize=(15, 5)) ax1 = fig.add_subplot(131) ax2 = fig.add_subplot(132) ax3 = fig.add_subplot(133) ax1.imshow( (ball[:,:,0]>200) ) ax2.imshow( (ball[:,:,0]>130)+(ball[:,:,0]<50) ) ax3.imshow( (ball[:,:,0]>130)+(ball[:,:,0]<50)+(ball[:,:,1]<120) )
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P72_4158.jpg?sign=1738887663-a6IeIsbPDrOZYfwzRGNEo3kP2vXNToz4-0-bd16cb323b29e5e78df9358a3b97809d)
图3-13 使用颜色规则对球的区域进行二值化(黑色代表球的区域)
好了,根据颜色规则,我们已经依稀得到了一个圆形物体。下一步,将这一规则推广到整张图片中,其结果如图3-14所示。
fig = plt.figure(figsize=(12, 5)) ax1 = fig.add_subplot(121) ax2 = fig.add_subplot(122)
img1 = ((img[:,:,0]>130)+(img[:,:,0]<50)+(img[:,:,1]<120)).astype(np.uint8) ax1.imshow(img) ax2.imshow(img1)
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P73_4175.jpg?sign=1738887663-P8neCXIHBddW6cQ4hy5ufOSuSva07iU3-0-73cd615ddcb77dcfc07dfceed6a13d10)
图3-14 使用颜色规则对整张图片球的区域进行二值化(黑色代表球的区域)
由此可见,对整张图片进行的颜色二值化处理还是比较有效的,至少球这里出现了圆形的形状,我们经过简单的处理后,将这里的圆形提取出来即可。但是这里任务并不轻松,因为图中还是比较杂乱:首先,球中间的黑色部分含有白色,需要填充掉;其次,背景部分有很多观众、标语造成的白色环状噪点,这些噪点不大,但会在圆形检测环节干扰结果。
为了让图片结果减少噪点,我们这里利用OpenCV进行一组侵蚀(erode)稀释(dilute)操作,如图3-15(对图3-14的结果先进行2像素侵蚀,再进行8像素的稀释,最后进行3像素的侵蚀的整个过程)所示。形象地说,可以将图中的黑色区域看成是海岛,白色看成是海洋。进行侵蚀操作后,海水上涨,白色区域变多,将孤立的黑色区域“淹没”;然后进行稀释操作。此时海水退去,没有被完全淹没的、面积较大的海岛基本恢复以前的样子,而被完全淹没的、面积小的海岛则从此消失。
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P73_10207.jpg?sign=1738887663-KjyCt5VAQZX61CA9pQmBCQIbA4Y1Hgyi-0-c38fdd575a3f18c0e2386215549aef98)
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P74_4190.jpg?sign=1738887663-uNoKu6HpGIWBYq264iHATd2vgTkKH51Q-0-d582c81b7d23b849c5fc2d8ed4bda3d9)
图3-15 侵蚀、稀释操作
经过侵蚀、稀释操作后,图中的黑色部分将会完全连在一起,面积较小的噪点则会被完全淹没在背景中。此时,下面的两个黑色圆形物体正是我们需要识别的球。现在先不着急,因为OpenCV的圆形识别算法识别的并非圆形物体,而是圆形的线条。因此还需要将这张图片的边缘提取出来,提取边缘的方法就是对整张图片计算梯度,此时如果一张像素周围全是黑色或者全是白色,则梯度为0;而旁边既有黑色又有白色,则会产生一个颜色梯度,即图片边缘。我们可以用Sobel算子分别对图像的横向、纵向计算颜色梯度,然后求平方根,得到总梯度。Sobel算子是一个3×3的卷积核,定义如下:
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P74_4194.jpg?sign=1738887663-sFpyfFzvnVIxJ0l90jZSy19UpDRmdynm-0-c2f18f9336d47220c007be39a3667734)
计算过程如下:
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P74_4198.jpg?sign=1738887663-CBEK2EFJnor6omk0LaH0P57LSc7zmbVq-0-71d2889bc190383975bf638623fdf20d)
Opencv-python的对应代码如下:
sobelx = cv2.Sobel(img_ede*255, cv2.CV_64F, 1, 0) sobely = cv2.Sobel(img_ede*255, cv2.CV_64F, 0, 1) img_sob = np.sqrt(sobelx**2+sobely**2).astype(np.uint8) plt.imshow(img_sob)
其结果如图3-16所示。
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P74_4209.jpg?sign=1738887663-pbjcsz9blCShh1FKxRn9rfhLi1RL9Fqr-0-c1aa53f202c80a23751d2bcb6cdaee5e)
图3-16 对图3-15的结果使用Sobel算子找出其边缘位置所在
此时已经得到了圆形的边缘,接下来调用OpenCV的圆形检测函数——cv2.HoughCircle,用Hough变换提取图中的圆形物体即可,如图3-17所示。
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P75_10209.jpg?sign=1738887663-54PhJNYbDbvjISqFjMzxce62JIoZOKKf-0-1012d0aded42d931a586ea3d39f37da1)
![](https://epubservercos.yuewen.com/8A84A4/15253385704108306/epubprivate/OEBPS/Images/Figure-P75_4227.jpg?sign=1738887663-FEbXxnwpz7XZK1ctNBSbm9j1qaDJKiJl-0-8091281d2503e67d3786bd1a4f132f35)
图3-17 成功识别图3-14中球所在的位置
最后多说几句:
(1)Hough变换可以在图中检索线段以及圆形,具体原理与利用极坐标系来表示线段、圆上的点有关,大家可以另行学习。常见的应用场景包括自动驾驶系统检测道路线(直线检测),以及显微镜下观察细胞(圆形检测)。
(2)通常情况下,Hough变换可以直接用在灰度图上,即上一个代码框里的gray = img_sob可以是gray = img_gray。这里之所以没有这么做,是因为背景部分同样有很多类似圆形的物体,造成了很多干扰,可能需要调试很多参数才能得到想要的结果,读者不妨试一试。如果通过颜色选择将特征二值化,进而通过侵蚀、稀释操作进一步去除背景噪声之后,可以让输入的图形更加简单,更加方便参数的调试。