透视变换可以解决这个问题:
- 从检测到的掩码中查找商店标志的角点。 (源点)
- 所需的矩形框点(dst 点)
- 使用
cv2.getPerspectiveTransform 和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 results