代码之家  ›  专栏  ›  技术社区  ›  SinLok

将HSV掩码拆分为多个矩形

  •  1
  • SinLok  · 技术社区  · 7 年前

    我从图像中创建了一个HSV蒙版。结果如下: enter image description here

    我的目标是绘制多个适合遮罩高度或宽度的矩形,如下所示: enter image description here

    我遇到了两个问题。

    1. 我不知道如何在创建矩形的掩码中定位起点和终点。如果我使用for循环逐行扫描掩码,它可能会将掩码分成两部分。 enter image description here

    2. 有时,在一个图像中还包含两个不同的遮罩。我怎样画矩形? enter image description here

    有人能给我一些建议吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   kavko    7 年前

    你可以用 cv2.findContour() . 它返回轮廓的坐标数组。然后,您可以在轮廓中搜索具有最高X坐标(即最右点)、最低X坐标(即最左点)、最高Y坐标(即最底点)和最低Y坐标(即最高点)的点。在您拥有所有4个值之后,您可以再次搜索等高线中具有该值的所有点,并将它们附加到4个不同的列表中,稍后对它们进行排序,这样您就可以将这些点淹没在底图上:

    enter image description here

    cv2.circle(img,(top_vertical[0]), 4, (0,0,255), -1)
    cv2.circle(img,(top_vertical[-1]), 4, (0,0,255), -1)
    cv2.circle(img,(bottom_vertical[0]), 4, (0,0,255), -1)
    cv2.circle(img,(bottom_vertical[-1]), 4, (0,0,255), -1)
    cv2.circle(img,(left_horizontal[0]), 4, (0,0,255), -1)
    cv2.circle(img,(left_horizontal[-1]), 4, (0,0,255), -1)
    cv2.circle(img,(right_horizontal[0]), 4, (0,0,255), -1)
    cv2.circle(img,(right_horizontal[-1]), 4, (0,0,255), -1)
    

    从这一点开始,我已经将列表转换为numpy数组,因为这对我来说更容易。你可以用其他方法。

    那么,问题就在于你想要多少个矩形,以及你想如何显示它们。在我的示例代码中,您需要输入多少个相同大小的矩形,最后一个是剩余矩形的大小。我首先在Y坐标(绿色)上显示矩形,然后在X坐标上显示矩形,X坐标分为两段(左和右),因为它们的距离略有不同,我不想绘制Y坐标矩形,因为它们不是在示例图像上绘制的。你可以随心所欲地改变书写矩形的逻辑。希望它能帮上一点忙,或者给你一个如何处理的主意。干杯!

    示例代码:

    import cv2
    import numpy as np
    
    # Read image and search for contours. 
    img = cv2.imread('cross.png')
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    _, threshold = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
    _, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    
    # Select the biggest contour (if you wish to segmentize only the cross-like contour). 
    cnt = max(contours, key=cv2.contourArea)
    
    # Create empty lists for appending key points. 
    top_vertical = []
    bottom_vertical = []
    left_horizontal = []
    right_horizontal = []
    
    # Setting the starter values for N, S, E, W. 
    top = 10000
    bottom = 0
    left = 10000
    right = 0
    
    # Loop to get highest key values of N, S, E, W.  
    for i in cnt:
        y = int(i[:,1])
        x = int(i[:, 0])
        if x < left:
            left = int(x)
        if x > right:
            right = int(x)
        if y < top:
            top = int(y)
        if y > bottom:
            bottom = int(y)
    
    # Loop for appending all points containing key values of N, S, E, W.   
    for i in cnt:
        if int(i[:,1]) == top:
            up = (int(i[:,0]), int(i[:,1]))
            top_vertical.append(up)
        if int(i[:,1]) == bottom:
            down = (int(i[:,0]), int(i[:,1]))
            bottom_vertical.append(down)
        if int(i[:,0]) == left:
            l = (int(i[:,0]), int(i[:,1]))
            left_horizontal.append(l)
        if int(i[:,0]) == right:
            r = (int(i[:,0]), int(i[:,1]))
            right_horizontal.append(r)
    
    
    # Sorting the lists. 
    top_vertical.sort(key=lambda tup: tup[0])
    bottom_vertical.sort(key=lambda tup: tup[0])
    left_horizontal.sort(key=lambda tup: tup[1])
    right_horizontal.sort(key=lambda tup: tup[1])
    
    # Optional drawing of key points. 
    '''cv2.circle(img,(top_vertical[0]), 4, (0,0,255), -1)
    cv2.circle(img,(top_vertical[-1]), 4, (0,0,255), -1)
    cv2.circle(img,(bottom_vertical[0]), 4, (0,0,255), -1)
    cv2.circle(img,(bottom_vertical[-1]), 4, (0,0,255), -1)
    cv2.circle(img,(left_horizontal[0]), 4, (0,0,255), -1)
    cv2.circle(img,(left_horizontal[-1]), 4, (0,0,255), -1)
    cv2.circle(img,(right_horizontal[0]), 4, (0,0,255), -1)
    cv2.circle(img,(right_horizontal[-1]), 4, (0,0,255), -1)'''
    
    # Transforming lists to arrays. 
    top_vertical = np.array(top_vertical)
    bottom_vertical = np.array(bottom_vertical)
    left_horizontal = np.array(left_horizontal)
    right_horizontal = np.array(right_horizontal)
    
    # Calculating height and weight of the contour.
    distance_y = bottom - top
    distance_x = right - left
    
    # Inputs for the number of same size segments. 
    a = input('Input the number of same size segments in Y coordinate: ')
    b = input('Input the number of same size segments in left X coordinate: ')
    c = input('Input the number of same size segments in right X coordinate: ')
    
    # Calculation of area per segment and limit for the lenght of combined segments (height and weight) . 
    segment_y = distance_y/int(a)
    segment_x_reference = int(top_vertical[0,0]) - int(left_horizontal[0,0])
    segment_x = segment_x_reference/int(b)
    segment_x_right_reference = int(right_horizontal[0,0]) - int(top_vertical[-1,0])
    segment_x_right = segment_x_right_reference/int(c)
    
    # Drawing rectangles on the Y axis.
    for i in range(1,20):
        sq = int(segment_y)*i
        if sq < distance_y:
            cv2.rectangle(img,(top_vertical[0,0], top_vertical[0,1]),((top_vertical[-1,0]),top_vertical[0,1] + sq),(0,255,0),1)
        else:
            sq = distance_y
            cv2.rectangle(img,(top_vertical[0,0], top_vertical[0,1]),((top_vertical[-1,0]),sq),(0,255,0),1)
            break
    
    # Drawing rectangles on the left side of X axis.   
    for i in range(1,20):
        sq = int(segment_x)*i
        if sq < segment_x_reference:
            cv2.rectangle(img,(left_horizontal[0,0], left_horizontal[0,1]),((left_horizontal[0,0])+sq, left_horizontal[-1,1]),(255,0,0),1)
        else:
            sq = segment_x_reference
            cv2.rectangle(img,(left_horizontal[0,0], left_horizontal[0,1]),((left_horizontal[0,0])+sq, left_horizontal[-1,1]),(255,0,0),1)
            break
    
    # Drawing rectangles on the right side of X axis. 
    for i in range(1,20):
        sq = int(segment_x_right)*i
        if sq < segment_x_right_reference:
            cv2.rectangle(img,(right_horizontal[0,0], right_horizontal[0,1]),((right_horizontal[0,0])-sq, right_horizontal[-1,1]),(255,0,0),1)
        else:
            sq = segment_x_right_reference
            cv2.rectangle(img,(right_horizontal[0,0], right_horizontal[0,1]),((right_horizontal[0,0])-sq, right_horizontal[-1,1]),(255,0,0),1)
            break
    
    # Displaying result. 
    cv2.imshow('img', img)
    

    结果:

    Input the number of same size segments in Y coordinate: 5
    Input the number of same size segments in left X coordinate: 2
    Input the number of same size segments in right X coordinate: 2
    

    enter image description here