如何修复变换透视功能错误地以错误的方向返回图像
How to fix transform perspective function incorrectly returning image in the wrong orientation
请帮助我理解为什么会发生这种情况,如果可能的话,请提供比我的补丁更好、更可靠的解决方案。
该功能基于。问题是,有一种情况是图像轮廓在错误的方向上不正确地扭曲:在固定旋转代码之前它已经是正面朝上了。因此,当它被返回时,它的方向不正确,它的顶边向左。轮廓是矩形的(在其正确方向上大约为 2991 x 2025)并且被正确识别为宽度方向。
该功能主要是为了尽可能拉直裁剪矩形轮廓的方向;没有任何极端情况需要将它旋转 >45 度,因为在此之前还有另一个功能可以解决这个问题。图像总是矩形的,从不正方形,无论是横向(宽度>高度)还是纵向(高度>宽度)都在代码中说明。你可以在上面的link看到它的用例。
代码如下:
def transform_perspective(img, corners):
def reorder_corner_points(corners):
tr, tl, bl, br = [(corner[0][0], corner[0][1]) for corner in corners][0:4]
return tl, tr, br, bl
# order the points in clockwise order
ordered_corners = reorder_corner_points(corners)
tl, tr, br, bl = ordered_corners
# determine width of new image which is the max distance between
# (bottom right and bottom left) or (top right and top left) x-coordinates
width_A = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
width_B = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
width = max(int(width_A), int(width_B))
# determine height of new image which is the max distance between
# (top right and bottom right) or (top left and bottom left) y-coordinates
height_A = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
height_B = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
height = max(int(height_A), int(height_B))
# construct new points to obtain top-down view of image in
# tr, tl, bl, br order
dimensions = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1],
[0, height - 1]], dtype="float32")
# convert to numpy format
ordered_corners = np.array(ordered_corners, dtype="float32")
# find perspective transform matrix
matrix = cv2.getPerspectiveTransform(ordered_corners, dimensions)
# get the transformed image,
# should be its right side up is facing to the right,
# height = img.shape[0] > width = img.shape[1]
warped = cv2.warpPerspective(img, matrix, (width, height))
# "rotate" -90 degrees to correct orientation
warped = cv2.transpose(warped)
warped = cv2.flip(warped, 0)
return warped
我的补丁是在固定旋转之前简单地添加这个if
语句:
# rotate the transformed image
# rotate counter-clockwise once if landscape and length is greater than height
# so that the fields to be extracted and read are right side up
# skip rotating if it's already right side up for some reason.
if (warped.shape[0] > warped.shape[1]) and config.is_landscape:
warped = cv2.transpose(warped)
warped = cv2.flip(warped, 0)
其中,由于图像是横向的,config.is_landscape
设置为 True
。并考虑另一种情况:
if (warped.shape[0] < warped.shape[1]) and not config.is_landscape:
warped = cv2.transpose(warped)
warped = cv2.flip(warped, 0)
复制预处理等的完整代码。粘贴在上面的函数之后。
# read and preprocess image
image = cv2.imread('asdasd.png', 1)
original = image.copy()
blur = cv2.bilateralFilter(image,9,75,75)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,0,255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# get all contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# get the largest contour
cnt = max(cnts, key=cv2.contourArea)
# warp
peri = cv2.arcLength(cnt, True)
transformed = transform_perspective(original, cv2.approxPolyDP(cnt, 0.05 * peri, True))
# show results
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.imshow('transformed', transformed)
# cv2.imshow('rotated', rotated)
cv2.waitKey(0)
破坏我代码的图像:
老实说,我不知道这张图片和轮廓有什么特别之处或不同之处在于它破坏了密码。请参阅之前 post 中的图像进行比较。我的大多数其他图像也与后者类似。
你调用了你的函数 reorder_corner_points(corners):
但你实际上没有实现任何 sorting/ordering 例程。
你必须从左上角正确地排列你的点数。
如果操作得当,代码末尾就不需要这个了:
# "rotate" -90 degrees to correct orientation
# warped = cv2.transpose(warped)
# warped = cv2.flip(warped, 0)
试试这个:
def reorder_corner_points(corners):
Corners_ = []
tr, tl, bl, br = [(corner[0][0], corner[0][1]) for corner in corners][0:4]
for corner in corners:
Corners_.append([(corner[0][0], corner[0][1])])
Corners_ = np.reshape(Corners_, (-1, 2))
# order the points in clockwise order
ordered_corners = order_points(Corners_)
return ordered_corners
排序函数:
def order_points(pts):
# Order along X axis
Xorder = pts[np.argsort(pts[:, 0]), :]
left = Xorder[:2, :]
right = Xorder[2:, :]
# Order along Y axis
left = left[np.argsort(left[:, 1]), :]
(tl, bl) = left
# use distance to get bottom right
D = dist.cdist(tl[np.newaxis], right, "euclidean")[0]
(br, tr) = right[np.argsort(D)[::-1], :]
return np.array([tl, tr, br, bl])
请帮助我理解为什么会发生这种情况,如果可能的话,请提供比我的补丁更好、更可靠的解决方案。
该功能基于
该功能主要是为了尽可能拉直裁剪矩形轮廓的方向;没有任何极端情况需要将它旋转 >45 度,因为在此之前还有另一个功能可以解决这个问题。图像总是矩形的,从不正方形,无论是横向(宽度>高度)还是纵向(高度>宽度)都在代码中说明。你可以在上面的link看到它的用例。
代码如下:
def transform_perspective(img, corners):
def reorder_corner_points(corners):
tr, tl, bl, br = [(corner[0][0], corner[0][1]) for corner in corners][0:4]
return tl, tr, br, bl
# order the points in clockwise order
ordered_corners = reorder_corner_points(corners)
tl, tr, br, bl = ordered_corners
# determine width of new image which is the max distance between
# (bottom right and bottom left) or (top right and top left) x-coordinates
width_A = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
width_B = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
width = max(int(width_A), int(width_B))
# determine height of new image which is the max distance between
# (top right and bottom right) or (top left and bottom left) y-coordinates
height_A = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
height_B = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
height = max(int(height_A), int(height_B))
# construct new points to obtain top-down view of image in
# tr, tl, bl, br order
dimensions = np.array([[0, 0], [width - 1, 0], [width - 1, height - 1],
[0, height - 1]], dtype="float32")
# convert to numpy format
ordered_corners = np.array(ordered_corners, dtype="float32")
# find perspective transform matrix
matrix = cv2.getPerspectiveTransform(ordered_corners, dimensions)
# get the transformed image,
# should be its right side up is facing to the right,
# height = img.shape[0] > width = img.shape[1]
warped = cv2.warpPerspective(img, matrix, (width, height))
# "rotate" -90 degrees to correct orientation
warped = cv2.transpose(warped)
warped = cv2.flip(warped, 0)
return warped
我的补丁是在固定旋转之前简单地添加这个if
语句:
# rotate the transformed image
# rotate counter-clockwise once if landscape and length is greater than height
# so that the fields to be extracted and read are right side up
# skip rotating if it's already right side up for some reason.
if (warped.shape[0] > warped.shape[1]) and config.is_landscape:
warped = cv2.transpose(warped)
warped = cv2.flip(warped, 0)
其中,由于图像是横向的,config.is_landscape
设置为 True
。并考虑另一种情况:
if (warped.shape[0] < warped.shape[1]) and not config.is_landscape:
warped = cv2.transpose(warped)
warped = cv2.flip(warped, 0)
复制预处理等的完整代码。粘贴在上面的函数之后。
# read and preprocess image
image = cv2.imread('asdasd.png', 1)
original = image.copy()
blur = cv2.bilateralFilter(image,9,75,75)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,0,255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# get all contours
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# get the largest contour
cnt = max(cnts, key=cv2.contourArea)
# warp
peri = cv2.arcLength(cnt, True)
transformed = transform_perspective(original, cv2.approxPolyDP(cnt, 0.05 * peri, True))
# show results
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.imshow('transformed', transformed)
# cv2.imshow('rotated', rotated)
cv2.waitKey(0)
破坏我代码的图像:
老实说,我不知道这张图片和轮廓有什么特别之处或不同之处在于它破坏了密码。请参阅之前 post 中的图像进行比较。我的大多数其他图像也与后者类似。
你调用了你的函数 reorder_corner_points(corners):
但你实际上没有实现任何 sorting/ordering 例程。
你必须从左上角正确地排列你的点数。
如果操作得当,代码末尾就不需要这个了:
# "rotate" -90 degrees to correct orientation
# warped = cv2.transpose(warped)
# warped = cv2.flip(warped, 0)
试试这个:
def reorder_corner_points(corners):
Corners_ = []
tr, tl, bl, br = [(corner[0][0], corner[0][1]) for corner in corners][0:4]
for corner in corners:
Corners_.append([(corner[0][0], corner[0][1])])
Corners_ = np.reshape(Corners_, (-1, 2))
# order the points in clockwise order
ordered_corners = order_points(Corners_)
return ordered_corners
排序函数:
def order_points(pts):
# Order along X axis
Xorder = pts[np.argsort(pts[:, 0]), :]
left = Xorder[:2, :]
right = Xorder[2:, :]
# Order along Y axis
left = left[np.argsort(left[:, 1]), :]
(tl, bl) = left
# use distance to get bottom right
D = dist.cdist(tl[np.newaxis], right, "euclidean")[0]
(br, tr) = right[np.argsort(D)[::-1], :]
return np.array([tl, tr, br, bl])