python-opencv实现logo缺陷检测

python-opencv实现logo缺陷检测

编辑:zero
关注 CV工程师的一技之长 AI算法与图像处理 微信公众号 ,研究好玩又有用的技术

在学习中发现快乐,在应用找到价值。


本文介绍了如何使用python-opencv来实现检测企业的logo,并返回有效的参数信息。文中涉及到了很多关于遇到问题之后解决方案的思考并寻找相应的对策,一步一步的逼近我们想要的结果,看完之后希望能对大家在解决问题方面有思路上的帮助~

概述

最近在忙一个项目,其中涉及到了对于企业logo的检测,检测logo是否出现倾斜或偏移。 logo标志是品牌形象核心部分,是表明事物特征的识别符号。 在工业生产中,由于各种不可控的因素可能会使得部分logo发生倾斜,移位等等的不合格产品,而logo又是一个公司的品牌形象的核心部分。因此,企业是无法容忍存在这样子的不合格产品流入到市场中,有损企业的形象。 下面用华为的logo作为例子。

声明:仅作为例子分析,并无侵犯或侮辱诋毁企业的意思
合格的logo
不合格的logo

从上面的示例图中可以看出来,logo似乎是分为图案+名字拼音两个部分。 因此首先想到是:是否可以将 图案和拼音 分别用单独的矩形来代表,因为我们并不关心logo的细节部分,所以将图案和拼音分别作为一个整体来考虑,可以有效的简化我们的问题。 那么有什么函数可以实现我们的功能呢? 没错就是opencv中的寻找最小外接矩形函数,可以通过寻找图案和拼音的最小外界矩形来分别代表这两个部分,再进一步利用最小外界矩形的参数来计算我们需要的结果。

函数 cv2.minAreaRect()

整个解决方案中最核心的函数就是函数 cv2.minAreaRect(cnt)

其中:cnt为需要查找的图像的轮廓点集,cnt不定个数

函数 cv2.minAreaRect(cnt)返回的结果为 ((x,y),(w,h),theta (x,y)代表最小外界矩形的中心点(w,h)分别代表矩形的宽和高 theta是指矩形与水平轴(x轴)所成的角度 下面这张图清晰的表达了函数返回各个函数的实际意义


注意点:对于minAreaRect返回矩形的角度值理解,theta的范围为[-90,0),在opencv中原点为左上角,横向为x轴,纵向为y轴,将x轴逆时针转动,碰到的第一条边(延长线)为宽, 宽与x轴所成的角度为theta【后面会继续遇到这个问题】 ,如下面的示意图所示。

参考链接: jb51.net/article/164341

利用最小外界矩形解决我们的问题

OK!既然思路有了,那么开始搞起(1)读取图片(2)寻找轮廓(3)对轮廓求取最小外界矩形得到下面的结果:

gg!!!牛逼吹大了,翻车了~

不要急,好好分析一下,问题出在哪里,目前我们已经能够找到 每个小元素的最小外界矩形 ,但是这不是我们想要的, 我们需要的是将图案和拼音分别当成一个整体,并用分别用最小外界矩形来代表。 通过仔细观察发现,其实图案与拼音的距离是稍微大于图案内部元素和各个拼音字母之间的距离,因此,考虑通过形态学操作中的 膨胀 方法对其进行一定的处理,将图案和拼音分别变为一个整体。OK,try again!

perfect!我们实现了预期的效果~同时终端输出了相关的参数:

注意:可以看到这里显示的是-90°,而不是0°,请结合上面函数 cv2.minAreaRect()的讲解来进行理解。
-90°是因为水平轴与宽(70.0-右边拼音部分)所成的角度
而0°则是水平轴与宽(149.0-左边图案部分)所成的角度

对不合格logo进行测试的结果:

终端输出的参数:

因此根据输出的结果做进一步的数据分析可以得到我们需要的结果,比如计算 倾斜角度,logo是否倾斜严重,是否发生偏移等等

这里建议将所有得到的最终结果都进行一定的变换,例如,假设图案的尺寸在标准的情况下,宽和高分别为100*100个像素,以此为标准进行换算来确定其他所有参数,这样子对于后续的其他处理能减少很多不必要的麻烦~

代码

# 导入必要的包
import numpy as np
import imutils
import cv2
# 导入图片
image = cv2.imread('logo1.png',0)
# 寻找图片中的所有黑色形状
shapeMask = cv2.inRange(image, 0, 200)
shapeMask = cv2.dilate(shapeMask, None, iterations = 10)
# 在mask上找到轮廓
cnts = cv2.findContours(shapeMask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
print("I found {} black shapes".format(len(cnts)))
cv2.imshow("Mask", shapeMask)
#cv2.imshow("")
# 遍历所有轮廓
for c in cnts: 
    # 绘制轮廓并显示    
    rect = cv2.minAreaRect(c) 
    # 返回的结果是 矩形中心点,矩形长和宽,以及旋转角度    
    print(rect)