在我的项目中,我尝试在我的数据集中检测商店标志。我在用Mask-RCNN。图像大小为512x512。shop sign images with Mask-RCNN
results = model.detect([image], verbose=1)
r = results[0]
masked = r['masks']
rois = r['rois']
在我运行上面的代码后,“rois”给了我商店招牌的边界框的坐标(例如40,52,79,249)。R‘mask’给了我一个布尔矩阵,它代表了图像中的每个蒙版。如果该像素在掩码区域中,则掩码矩阵中的像素值为'True‘。并且如果该像素在掩码区域之外,则像素值为'False‘。如果模型在图像中检测到7个商店招牌(即7个蒙版),则r“蒙版”的大小为512x512x7。每个通道代表不同的掩码。
我必须单独处理每个掩码,因此我分离了每个通道,假设获得第一个通道。然后我找到了'True‘像素的掩码数组中的坐标。
array = masked[:,:,0]
true_points = []
for i in range(512):
for j in range(512):
if array[i][j] == True:
true_points.append([j, i])
所以,我的问题是,我如何从这个布尔矩阵中获得面具(即商店标志)的角的坐标?大多数商店的招牌都是直角的,但可以旋转。我有边界框的坐标,但当商店招牌旋转时,它不准确。我有'True‘点的坐标。你能推荐一个算法来找到角的'True‘值吗?
发布于 2019-12-05 17:52:35
如果您知道旋转角度,只需旋转角点上的bbox角,例如usig cv2.warpAffine。如果您不这样做,那么您可以或多或少很容易地找到极值,如下所示
H,W = array.shape
left_edges = np.where(array.any(axis=1),array.argmax(axis=1),W+1)
flip_lr = cv2.flip(array,1) #1 horz vert 0
right_edges = W-np.where(flip_lr.any(axis=1),flip_lr.argmax(axis=1),W+1)
top_edges = np.where(array.any(axis=0),array.argmax(axis=0),H+1)
flip_ud = cv2.flip(array,0) #1 horz vert 0
bottom_edges = H - np.where(flip_ud.any(axis=0),flip_ud.argmax(axis=0),H+1)
leftmost = left_edges.min()
rightmost = right_edges.max()
topmost = top_edges.min()
bottommost = bottom_edges.max()你的bbox有角(最左边,最上面),(最右边,最下面),here's我试过的一个例子。顺便说一句,如果你发现自己在像素上循环,你应该知道几乎总是有一个numpy向量化操作,它会做得更快。
发布于 2020-07-27 07:50:18
透视变换可用于解决此问题:
cv2.getPerspectiveTransform and cv2.warpPerspective对于角点检测,我们可以使用cv2.findContours和cv2.approxPolyDP
cv2.findContours在二进制图像中查找轮廓。
contours, _ = cv2.findContours(r['masks'][:,:,0].astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)然后使用cv2.approxPolyDP从轮廓中近似矩形
cv2.approxPolyDP中的关键点是epsilon (逼近精度的参数)。用于矩形点检测的自定义阈值(下图)
def Contour2Quadrangle(contour):
def getApprox(contour, alpha):
epsilon = alpha * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
return approx
# find appropriate epsilon
def getQuadrangle(contour):
alpha = 0.1
beta = 2 # larger than 1
approx = getApprox(contour, alpha)
if len(approx) < 4:
while len(approx) < 4:
alpha = alpha / beta
approx = getApprox(contour, alpha)
alpha_lower = alpha
alpha_upper = alpha * beta
elif len(approx) > 4:
while len(approx) > 4:
alpha = alpha * beta
approx = getApprox(contour, alpha)
alpha_lower = alpha / beta
alpha_upper = alpha
if len(approx) == 4:
return approx
alpha_middle = (alpha_lower * alpha_upper ) ** 0.5
approx_middle = getApprox(contour, alpha_middle)
while len(approx_middle) != 4:
if len(approx_middle) < 4:
alpha_upper = alpha_middle
approx_upper = approx_middle
if len(approx_middle) > 4:
alpha_lower = alpha_middle
approx_lower = approx_middle
alpha_middle = ( alpha_lower * alpha_upper ) ** 0.5
approx_middle = getApprox(contour, alpha_middle)
return approx_middle
def getQuadrangleWithRegularOrder(contour):
approx = getQuadrangle(contour)
hashable_approx = [tuple(a[0]) for a in approx]
sorted_by_axis0 = sorted(hashable_approx, key=lambda x: x[0])
sorted_by_axis1 = sorted(hashable_approx, key=lambda x: x[1])
topleft_set = set(sorted_by_axis0[:2]) & set(sorted_by_axis1[:2])
assert len(topleft_set) == 1
topleft = topleft_set.pop()
topleft_idx = hashable_approx.index(topleft)
approx_with_reguler_order = [ approx[(topleft_idx + i) % 4] for i in range(4) ]
return approx_with_reguler_order
return getQuadrangleWithRegularOrder(contour)最后,我们使用所需的目的地坐标生成一个新图像。
contour = max(contours, key=cv2.contourArea)
corner_points = Contour2Quadrangle(contour)
src = np.float32(list(map(lambda x: x[0], corner_points)))
dst = np.float32([[0,0],[0, 200],[400, 200],[200, 0]])
M = cv2.getPerspectiveTransform(src, dst)
transformed = cv2.warpPerspective(img, M, (rect_img_w, rect_img_h))
plt.imshow(transformed) # check the resultshttps://stackoverflow.com/questions/59191179
复制相似问题