opencv Python -围绕一组等值线绘制边界框

dbf7pr2w  于 2023-02-09  发布在  Python
关注(0)|答案(1)|浏览(131)

嗨,我有一个代码,发现并绘制轮廓周围的对象是黄色.
下面是代码:

import cv2
import numpy as np
from PIL import ImageGrab

lower_yellow = np.array([20, 100, 100])
upper_yellow = np.array([30, 255, 255])

def test():
    while True:
        imgDef = ImageGrab.grab()
        image = np.array(imgDef)

        rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        hsv = cv2.cvtColor(rgb, cv2.COLOR_BGR2HSV)

        mask = cv2.inRange(hsv, lower_yellow, upper_yellow)

        kernel = np.ones((5,5),np.uint8)
        mask = cv2.dilate(mask, kernel, iterations=1)
        mask = cv2.erode(mask, kernel, iterations=1)

        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        cv2.drawContours(image, contours, -1, (0,255,0), 3)

        cv2.imshow('test', image)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cv2.destroyAllWindows()

if __name__ == "__main__":
    test()

现在的输出如下所示:

我希望将彼此非常接近的等值线分组,并在它们周围绘制一个边界框,如下所示:

我怎样才能做到这一点呢?我是否应该研究scikitKMeans函数来对它们进行分组?

qxsslcnc

qxsslcnc1#

你可以使用cv2.kmeans来实现这个目标。我建议把cv2.RETR_EXTERNAL改为cv2.RETR_TREE。我在这里分享一个可能的解决方案,唯一的问题是你需要在使用cv2.kmeans之前知道集群的编号。

import cv2
import numpy as np
from PIL import ImageGrab
import random

lower_yellow = np.array([20, 100, 100])
upper_yellow = np.array([30, 255, 255])

def get_contours_by_zones(contours, number_of_zones):
    center_points = []
    for cnt in contours:
        cx = cnt[:,0,0].mean()
        cy = cnt[:,0,1].mean()  
        center_points.append((cx, cy))
    center_points = np.array(center_points).astype(np.float32)

    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    _,_,cluster_centers=cv2.kmeans(center_points, number_of_zones, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

    contour_zones = [[] for _ in range(number_of_zones)]
    for i, (cnt_x, cnt_y) in enumerate(center_points):
        tmp = cluster_centers - (cnt_x, cnt_y)  
        distances = np.sqrt( (tmp**2).sum(axis=1) )
        cluster_index = np.argmin(distances)
        contour_zones[cluster_index].append( contours[i] )

    return contour_zones

def test():
    while True:
        imgDef = ImageGrab.grab()
        image = np.array(imgDef)

        rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        hsv = cv2.cvtColor(rgb, cv2.COLOR_BGR2HSV)

        mask = cv2.inRange(hsv, lower_yellow, upper_yellow)

        kernel = np.ones((5,5),np.uint8)
        mask = cv2.dilate(mask, kernel, iterations=1)
        mask = cv2.erode(mask, kernel, iterations=1)

        contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        # ignore outer contour
        contour_per_zone = get_contours_by_zones(contours=contours[1:], number_of_zones=3)
        canvas = np.empty_like(image)
        canvas[...]=255
  
        for zone in contour_per_zone:
            # add the corresponding code to get xmin, xmax, ymin, ymax from zone, 
            # so you can draw the corresponding reactangle 
            # draw each zone with a different color
            cv2.drawContours(canvas, zone, -1, (random.randint(0, 256), random.randint(0, 256), random.randint(0, 256)), 3)

        cv2.imshow('test', image)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cv2.destroyAllWindows()

if __name__ == "__main__":
    test()

get_contours_by_zones()函数使用cv2.kmeans将每个等值线分配给一个组。

相关问题