【问题标题】:Python: Contour around rectangle based on specific color on a dark image (OpenCV)Python:基于深色图像上的特定颜色的矩形轮廓(OpenCV)
【发布时间】:2020-07-07 11:13:05
【问题描述】:

因为我正在尝试在 Python 中使用 OpenCV 来提高我的技能,所以我想知道从大部分是深色的图像中提取特定灰色调的最佳方法是什么。

首先,我创建了一个测试图像,以便使用 OpenCV 测试不同的方法:

假设我想在此图像中提取特定颜色并为其添加边框。现在我选择了中间的灰色矩形,颜色为 (33, 33, 34 RGB),见下图:

(这是没有红色边框的图像,以便您测试您的想法:https://i.stack.imgur.com/Zf8Vb.png

这是我迄今为止尝试过的,但效果不佳:

img = cv2.imread(path) #Read input image
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Convert from BGR to HSV color space
saturation_plane = hsv[:, :, 1] # all black/white/gray pixels are zero, and colored pixels are above zero
_, thresh = cv2.threshold(saturation_plane, 8, 255, cv2.THRESH_BINARY) # Apply threshold on s
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # draw all contours 
contours = contours[0] if len(contours) == 2 else contours[1]
result = img.copy()

for contour in contours:
   (x, y, w, h) = cv2.boundingRect(contour) # compute the bounding box for the contour
   if width is equal to the width of the rectangle i want to extract:
       draw contour

如果矩形的大小不固定,我无法通过它的宽度/高度来检测它怎么办?此外,将图像转换为灰度而不是HSV更好吗?我刚接触它,我想听听你实现这一目标的方法。

提前致谢。

【问题讨论】:

    标签: python opencv python-imaging-library crop contour


    【解决方案1】:

    如果知道具体的颜色,可以以gray = np.all(img == (34, 33, 33), 2)开头。

    结果是一个逻辑矩阵,其中True BGR = (34, 33, 33),如果不是,则为 False。
    注意:OpenCV 颜色排序是 BGR 而不是 RGB。

    • 将逻辑矩阵转换为uint8gray = gray.astype(np.uint8)*255
    • gray 图像上使用findContours

    如果您想找到蓝色矩形而不是具有非常特定 RGB 值的灰色矩形,则将图像转换为 HSV 没有用。

    以下代码用颜色(33、33、34 RGB)找到最大尺寸的轮廓:

    import numpy as np
    import cv2
    
    # Read input image
    img = cv2.imread('rectangles.png')
    
    # Gel all pixels in the image - where BGR = (34, 33, 33), OpenCV colors order is BGR not RGB
    gray = np.all(img == (34, 33, 33), 2)  # gray is a logical matrix with True where BGR = (34, 33, 33).
    
    # Convert logical matrix to uint8
    gray = gray.astype(np.uint8)*255
    
    # Find contours
    cnts = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # Use index [-2] to be compatible to OpenCV 3 and 4
    
    # Get contour with maximum area
    c = max(cnts, key=cv2.contourArea)
    
    x, y, w, h = cv2.boundingRect(c)
    
    # Draw green rectangle for testing
    cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), thickness = 2)
    
    # Show result
    cv2.imshow('gray', gray)
    cv2.imshow('img', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    结果:

    灰色:

    img:


    如果你不知道大部分深色的具体颜色,你可能会找到所有轮廓,并搜索灰度值最低的那个:

    import numpy as np
    import cv2
    
    # Read input image
    img = cv2.imread('rectangles.png')
    
    # Convert from BGR to Gray
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # Apply threshold on gray
    _, thresh = cv2.threshold(gray, 8, 255, cv2.THRESH_BINARY)
    
    # Find contours on thresh
    cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2]  # Use index [-2] to be compatible to OpenCV 3 and 4
    
    min_level = 255
    min_c = []
    
    #Iterate contours, and find the darkest:
    for c in cnts:
        x, y, w, h = cv2.boundingRect(c)
    
        # Ignore contours that are very thin (like edges)
        if w > 5 and h > 5:
            level = gray[y+h//2, x+w//2]  # Get gray level of center pixel
    
            if level < min_level:
                # Update min_level abd min_c
                min_level = level
                min_c = c
    
    x, y, w, h = cv2.boundingRect(min_c)
    
    # Draw red rectangle for testing
    cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), thickness = 2)
    
    # Show result
    cv2.imshow('img', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    结果:

    【讨论】:

    • 非常感谢!我有点知道RGB值。它至少总是在 30-35 之间,这意味着它可以是 RGB(31,32,33)、RGB(35,35,35)、RGB(30,35,33) 等。
    • 如果您知道颜色,请使用 cv2.inRange() 在颜色的一些上下限内对该颜色设置阈值。
    • @Keanu 如果您知道范围,请使用thresh = cv2.inRange(img, (30, 30, 30), (35, 35, 35)),正如 fmw42 评论的那样。
    • @Rotem 你的回答真的很有帮助。终于弄明白了,谢谢
    猜你喜欢
    • 2012-08-29
    • 2012-11-06
    • 2013-04-23
    • 1970-01-01
    • 2017-11-19
    • 2017-12-19
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    相关资源
    最近更新 更多