将HSV遮罩分割成多个矩形

时间:2018-08-05 13:09:38

标签: python-3.x opencv image-processing

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

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

我遇到2问题。

  1. 我不知道如何在遮罩中定位起点和终点以创建矩形。如果我使用for循环逐行扫描蒙版,则可能会将蒙版分为2部分。 enter image description here

  2. 有时,在一幅图像中还包含2个不同的蒙版。如何绘制矩形? enter image description here

有人可以给我一些建议吗?

1 个答案:

答案 0 :(得分:2)

您可以使用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坐标上显示了矩形,将其分为两段(左右),因为它们的距离略有不同,并且我不想按原样绘制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