一种基于opencv的分辨检测圆形,三角形,矩形的思路

一种基于opencv的分辨圆形,三角形,矩形的思路

题目要求是分辨出一个随机颜色(红色,绿色,蓝色)的图形(矩形,圆形,三角形)。

上篇文章给大家讲了基于openmv的思路,这篇文章大致讲讲如何用opencv来做。
我事先查了一下,我这个方法不知道有多少人早就用过了。(可能是因为当时我也是疯狂查出来的,已经记忆模糊了)他们讲的比我详细多了,我就简单说说思路。

我的思路是:色块识别+轮廓提取+角点检测

1. 色块识别:

色块识别是很基础的一个操作了,也比较简单。直接看代码:

    lower_red_1 = np.array([0, 80, 128]) #先找出HSV色彩空间红绿蓝三种颜色的大致范围。红色有两个是因为hsv空间中,色相h最上面和最下面都是红色。可以看下面这张图你就懂了。
    upper_red_1 = np.array([6, 255, 255])
    lower_red_2 = np.array([170, 110, 128])
    upper_red_2 = np.array([180, 255, 255])
    lower_green = np.array([35, 80, 80])
    upper_green = np.array([77, 255, 255])
    lower_blue = np.array([90, 110, 110])
    upper_blue = np.array([124, 255, 255])

    hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) #frame就是输入的图像
    
    red_mask_1 = cv.inRange(hsv,lower_red_1,upper_red_1) #将图像二值化,在lower和upper之间的颜色变为白色,其他全为黑色
    red_mask_2 = cv.inRange(hsv,lower_red_2,upper_red_2)
    red_mask = cv.bitwise_or(red_mask_1, red_mask_2) #两种红色统一
    green_mask = cv.inRange(hsv, lower_green, upper_green)
    blue_mask = cv.inRange(hsv, lower_blue, upper_blue)  

《一种基于opencv的分辨检测圆形,三角形,矩形的思路》

上面这一段不懂的话可以看看这篇文章,这位博主讲得很好(侵删)

    red_res = cv.bitwise_or(frame, frame, mask = red_mask) #或运算,将彩色图像中红色部分选中,忽略其余颜色
    green_res = cv.bitwise_and(frame, frame, mask = green_mask)
    blue_res = cv.bitwise_and(frame, frame, mask = blue_mask)

    red_gray = cv.cvtColor(red_res, cv.COLOR_BGR2GRAY) #转灰度图
    green_gray = cv.cvtColor(green_res, cv.COLOR_BGR2GRAY)
    blue_gray = cv.cvtColor(blue_res, cv.COLOR_BGR2GRAY)

    final_gray = cv.bitwise_or(red_res, green_res) #将选出的红色,蓝色,绿色都集成起来
    final_gray = cv.bitwise_or(final_gray, blue_res)
    final_gray = cv.cvtColor(final_gray,cv.COLOR_BGR2GRAY) #得到最终的灰度图。就是下一步轮廓提取的输入

2. 轮廓提取
轮廓提取的话,opencv有自己的API,好用的很。

    __, contours,hierarchy = cv.findContours(final_gray, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
#这个地方要注意一下。这个函数根据版本不同,返回的值可能有两个或者三个。如果opencv版本比较新,就只有后面两个返回值。如果比较旧(我代码是在树莓派上跑的,所以比较旧),就有三个返回值。不过我们只用到countours这个返回值就行。
    for cnt in range(len(contours)): #对检测到的每个轮廓遍历
        p = cv.arcLength(contours[cnt],True) #p是Perimeter周长的意思,当时偷懒了
        area = cv.contourArea(contours[cnt]) #area是该轮廓的像素面积

3. 角点检测
原理我也没啥好说的,毕竟这也不是计算机视觉原理专栏,调用api就完事了。

    for cnt in range(len(contours)):
        p = cv.arcLength(contours[cnt],True)
        area = cv.contourArea(contours[cnt])

        if area > 2500:
            mm = cv.moments(contours[cnt]) #计算图像轮廓中的中心矩,原理见代码后链接
            if mm['m00'] != 0: #如果算出了中心距(感觉这里应该用try,except,当时写的不严谨)
                cx = int(mm['m10'] / mm['m00']) #归一化计算得出轮廓中心的横纵坐标
                cy = int(mm['m01'] / mm['m00'])
            else:
                continue
            epsilon = 0.04 * cv.arcLength(contours[cnt], True) #多边形拟合的距离参数,下一个函数要用到。原理见代码后链接
            approx = cv.approxPolyDP(contours[cnt], epsilon, True)  #轮廓近似。将圆润曲线折线化,以此得到该图像的角点坐标。
            corners = len(approx) #得到角点数量
            if corners == 3: #三个角点的就是三角形
                shapes['triangle'] = shapes['triangle'] + 1
                shapeLenth = p/3 #得到三角形边长
            elif corners == 4: #四个角点就是矩形
                shapes['rectangle'] = shapes['rectangle'] + 1
                shapeLenth = p/4 #得到正方形边长
            else: #圆有好多角点
                shapes['circles'] = shapes['circles'] + 1
                pi = 3.1415926
                rad = p/(2*pi) #得到圆周长
                

解释中心距(侵删)概率论的知识了
解释多边形拟合(侵删)
解释角点检测原理(侵删)这两篇文章都讲的很清楚,一看就明白了,知道原理 然后拿来用就行。

  
  效果图是拿树莓派跑的:
《一种基于opencv的分辨检测圆形,三角形,矩形的思路》

有需要的可以自己拿去跑了试试,根据角点检测的原理,五边形,六边形,七边形等多边形都可以识别出来,但是可能会和圆搞混,调一调epsilon 这个参数就行。
  
        有问题可以评论区交流

    原文作者:ddatalent
    原文地址: https://blog.csdn.net/ddatalent/article/details/109229951
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞