【问题标题】:Finding coordinates of corners of the mask(rectengular shape) from Mask matrix(Boolean matrix) in Mask-RCNN?从 Mask-RCNN 中的掩码矩阵(布尔矩阵)中查找掩码角的坐标(矩形)?
【发布时间】:2019-12-05 08:40:44
【问题描述】:

在我的项目中,我尝试检测数据集中的商店标志。我正在使用 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['masks'] 给了我代表图像中每个掩码的布尔矩阵。如果此像素在掩码区域中,则掩码矩阵中的像素值为“真”。如果该像素超出掩码区域,则该像素值为“假”。如果模型在图像中检测到 7 个商店标志(即 7 个​​面具),则 r['masks'] 的大小为 512x512x7。每个通道代表不同的掩码。

我必须单独处理每个掩码,因此我将每个通道分开,假设获取第一个。然后我在“真”像素的掩码数组中找到了坐标。

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])

所以,我的问题是如何从这个布尔矩阵中获取掩码角的坐标(即商店标志)?大多数商店标志是矩形的,但它们可以旋转。我有边界框的坐标,但是旋转商店标志时它不准确。我有“真”点的坐标。你能建议一种算法来找到角“真”值吗?

【问题讨论】:

    标签: python deep-learning mask


    【解决方案1】:

    如果您知道旋转角度,只需旋转 bbox 角,例如在角点上使用 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 矢量化操作会更快地完成它。

    【讨论】:

      【解决方案2】:

      透视变换可以解决这个问题:

      1. 从检测到的掩码中查找商店标志的角点。 (源点)
      2. 所需的矩形框点(dst 点)
      3. 使用cv2.getPerspectiveTransformcv2.warpPerspective 生成新图像

      对于角点检测,我们可以使用cv2.findContourscv2.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 results
      

      【讨论】:

        猜你喜欢
        • 2020-08-07
        • 2014-04-10
        • 2021-06-16
        • 2013-12-03
        • 2022-11-02
        • 2018-05-15
        • 2020-03-13
        • 1970-01-01
        • 2016-01-04
        相关资源
        最近更新 更多