无需ML的实时目标检测绘制BBox

问题描述

我正在尝试在没有任何ML的情况下进行实时目标检测。该方法是根据对象的颜色配置文件来识别对象。我试着用一种颜色识别一个矩形物体,并画一个边框。代码如下:

import cv2
import numpy as np

class ColourBounds:
    def __init__(self, rgb):
        hsv = cv2.cvtColor(np.uint8([[[rgb[2], rgb[1], rgb[0]]]]), cv2.COLOR_BGR2HSV).flatten()

        lower = [hsv[0] - 10]
        upper = [hsv[0] + 10]

        if lower[0] < 0:
            lower.append(179 + lower[0]) # + negative = - abs
            upper.append(179)
            lower[0] = 0
        elif upper[0] > 179:
            lower.append(0)
            upper.append(upper[0] - 179)
            upper[0] = 179

        self.lower = [np.array([h, 100, 100]) for h in lower]
        self.upper = [np.array([h, 255, 255]) for h in upper]

def contains_vertical(r1, r2):
    x1, y1, w1, h1 = r1
    x2, y2, w2, h2 = r2

    return x1 <= x2 < x1 + w1 and x1 <= x2 + w2 < x1 + w1

def drawLabel(w, h, x, y, text, frame):
    cv2.rectangle(frame,(x,y),(x+w,y+h),(120,0,0),2)
    cv2.putText(frame, text, (x,y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,255), 2)

colourMap = {"Antigen Device": ColourBounds((237,237,237))}

while(True):

    frame = cv2.imread('antigen.png')

    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    rects = {}

    for name, colour in colourMap.items():
        mask = cv2.inRange(hsv, colour.lower[0], colour.upper[0])

        if len(colour.lower) == 2:
            mask = mask | cv2.inRange(hsv, colour.lower[1], colour.upper[1])

        conts, heirarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

        if (len(conts) == 0):
            continue

        biggest = sorted(conts, key=cv2.contourArea, reverse=True)[0]
        rect = cv2.boundingRect(biggest)
        x, y, w, h = rect

        if w < 50 or h < 50:
            continue

        if name == "Antigen Device":
            if any([contains_vertical(rects[n], rect) for n in rects]):
                continue

        rects[name] = rect
        drawLabel(w, h, x, y, name, frame)

    cv2.imshow('image',frame)
    k = cv2.waitKey(0) & 0xFF
    if k == 27:
        break

cv2.destroyAllWindows()
cv2.waitKey(1)

但是,我没有看到边框或标签。下面是我的照片。不应用任何更改:


解决方案

您正在尝试进行颜色检测,然后在其周围绘制一个边框。

最简单的方法:

第一步:实现颜色检测。

我实现了以下代码来为您的图像查找正确的遮罩值。使用轨迹栏,当您对结果感到满意时,按Q键,系统将为您打印掩码​​的值。

注意:除了你的目标之外,你可以找到更多的小轮廓。

我发现这些值非常有效:

h_min,h_max,s_min,s_max,v_min,v_max:0 179 0 15 223 255

import cv2
import numpy as np

def empty():
   pass


while True:

   img = cv2.imread(Path to your image)
   imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
   h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
   h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
   s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
   s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
   v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
   v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
   lower = np.array([h_min, s_min, v_min])
   upper = np.array([h_max, s_max, v_max])
   mask = cv2.inRange(imgHSV, lower, upper)
   imgResult = cv2.bitwise_and(img, img, mask=mask)

   # for OpenCV 4
   contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
   cv2.CHAIN_APPROX_NONE) 

    # ---For OpenCV 3---
    # _, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
    # cv2.CHAIN_APPROX_NONE) 
    # ---For OpenCV 3---

   for contour in contours:
         cv2.drawContours(img, contour, -1, (0, 255, 0), 3)

   cv2.imshow("Original", img)
   cv2.imshow("Result", imgResult)

   if cv2.waitKey(27) & 0xFF == ord('q'):
       print(h_min, h_max, s_min, s_max, v_min, v_max)
       break

第二步:只在目标周围画边界框。(2个绘制选项)

代码与前面类似,但现在我们知道了正确的值,我们将在所需的等高线周围绘制一条线。我们的目标是获得最大的轮廓,因此我们可以使用contourArea()方法提取轮廓的大小,然后仅在轮廓足够大的情况下绘制边界框。它的实现与您的代码略有不同,但您可以根据您的逻辑对其进行调整(对等高线区域的大小进行排序,并仅在最大的区域上绘制)。

例如:

import cv2
import numpy as np

while True:
    frame = cv2.imread("stackoverflow2pic.jpeg")
    blurred_frame = cv2.GaussianBlur(frame, (5, 5), 0)
    hsv = cv2.cvtColor(blurred_frame, cv2.COLOR_BGR2HSV)

    lower = np.array([0, 0, 223])
    upper = np.array([179, 15, 255])
    mask = cv2.inRange(hsv, lower, upper)
    
    # for OpenCV 4
    contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
       cv2.CHAIN_APPROX_NONE) 

    # ---For OpenCV 3---
    # _, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, 
    # cv2.CHAIN_APPROX_NONE) 
    # ---For OpenCV 3---

    for contour in contours:
        area = cv2.contourArea(contour)
        if area > 5000:
             # -- Draw Option 1 --
             cv2.drawContours(frame, contour, -1, (0, 255, 0), 3)

             # -- Draw Option 2--
             # rect = cv2.boundingRect(contour)
             # x, y, w, h = rect
             # cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

    cv2.imshow("Mask", mask)
    cv2.imshow("Frame", frame)

    cv2.waitKey(1)

结果(绘图选项1):

结果(绘图选项2):

相关文章