简体   繁体   English

如何修复变换透视 function 错误地以错误的方向返回图像

[英]How to fix transform perspective function incorrectly returning image in the wrong orientation

Please help me understand why this happened and if possible provide a better, more robust solution than my patch.请帮助我理解为什么会发生这种情况,如果可能的话,请提供比我的补丁更好、更强大的解决方案。

The function is based on this . function就是基于 The problem is, there is a case where an image contour is warped incorrectly in the wrong orientation: it was already right side up before the fixed rotation code.问题是,有一种情况是图像轮廓在错误的方向上被错误地扭曲:在固定旋转代码之前它已经是正面朝上的。 Therefore when it is returned its oriented incorrectly with its top side to the left.因此,当它被退回时,它的方向不正确,其顶部向左。 The contour is rectangular (about 2991 x 2025 on its correct orientation) and is identified correctly as width-wise.轮廓是矩形的(在其正确方向上约为 2991 x 2025),并且被正确识别为宽度方向。

The function is mostly there just to straighten the orientation of the cropped rectangular contour as much as possible; function 主要是为了尽可能拉直裁剪后的矩形轮廓的方向; there is no extreme cases where it needs to be rotated >45 degrees either way as there's another function before this that takes care of that.没有任何极端情况需要旋转 >45 度,因为在此之前还有另一个 function 可以解决这个问题。 The image is always rectangular, never square, and whether it's in landscape (width>height) or portrait (height>width) is accounted for in the code.图像始终是矩形的,绝不是正方形的,无论是横向(宽度>高度)还是纵向(高度>宽度)都在代码中进行了说明。 You can see its use case on the link above.您可以在上面的链接中看到它的用例。

Here is the code:这是代码:

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

My patch is to simply add this if statement before the fixed rotation:我的补丁是在固定旋转之前简单地添加这个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)

Where, since the image is landscape, config.is_landscape is set to True .其中,由于图像是横向的,因此config.is_landscape设置为True And to account for the other case:并考虑另一种情况:

        if (warped.shape[0] < warped.shape[1]) and not config.is_landscape:
            warped = cv2.transpose(warped)
            warped = cv2.flip(warped, 0)

Whole code to replicate pre-processing etc. Paste after the function from above.复制预处理等的整个代码。从上面粘贴到 function 之后。

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

The image that broke my code:破坏我的代码的图像: 破坏我的代码的图像

I honestly don't know what's special or different with this image and contour that it breaks the code.老实说,我不知道这个图像和轮廓有什么特别或不同之处,它破坏了代码。 See the image from the previous post for a comparison.请参阅上一篇文章中的图片进行比较。 Most of my other images behave similarly like the latter too.我的大多数其他图像的行为也与后者类似。

You call your function reorder_corner_points(corners): but you didn't actually implement any sorting/ordering routine.你调用你的 function reorder_corner_points(corners):但你实际上并没有实现任何排序/排序例程。

you have to order your points properly from top left.您必须从左上角正确排序您的积分。

if you do it properly you don't need this at the end of your code:如果你做得正确,你不需要在代码末尾这样做:

# "rotate" -90 degrees to correct orientation
# warped = cv2.transpose(warped)
# warped = cv2.flip(warped, 0)

Try this:尝试这个:

    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

Ordering function:订购 function:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM