裁剪后如何检测和对齐倾斜的图像 [英] How to detect and align tilted images after cropping

查看:54
本文介绍了裁剪后如何检测和对齐倾斜的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在解决方案上实现了一种裁剪算法,效果很好.问题是当图像倾斜时,裁切将起作用,但是将显示图像显示的背景空间.

种植流程:

第一步:

第二步:

最终结果:

我已经搜索/尝试了多种解决方案,但无法获得令人满意的结果,或者我没有在考虑正确的方法.

预期结果是这样

编辑[最终结果]:

  import cv2将numpy导入为npdef order_corner_points(corners):#将角分开成单个点#索引0-右上#1-左上方#2-左下#3-右下拐角= [(拐角处的拐角[0] [0],拐角[0] [1])]top_r,top_l,bottom_l,bottom_r =角[0],角[1],角[2],角[3]返回(top_l,top_r,bottom_r,bottom_l)def Perspective_transform(图像,角):#按顺时针顺序排列点ordered_corners = order_corner_points(角)top_l,top_r,bottom_r,bottom_l = ordered_corners#确定新图片的宽度,即新图片之间的最大距离#(右下和左下)或(右上和左上)x坐标width_A = np.sqrt((((bottom_r [0]-bottom_l [0])** 2)+(((bottom_r [1]-bottom_l [1])** 2))width_B = np.sqrt((((top_r [0]-top_l [0])** 2)+(((top_r [1]-top_l [1])** 2))宽度= max(int(width_A),int(width_B))#确定新图片的高度,即新图片之间的最大距离#(右上和右下)或(左上和左下)y坐标height_A = np.sqrt((((top_r [0]-bottom_r [0])** 2)+(((top_r [1]-bottom_r [1])** 2))height_B = np.sqrt((((top_l [0]-bottom_l [0])** 2)+(((top_l [1]-bottom_l [1])** 2))高度= max(int(height_A),int(height_B))#构造新的点以获得图像的自上而下的视图#top_r,top_l,bottom_l,bottom_r顺序尺寸= np.array([[0,0],[width-1,0],[width-1,height-1],[0,高度-1]],dtype ="float32")#转换为Numpy格式ordered_corners = np.array(ordered_corners,dtype ="float32")#查找透视变换矩阵矩阵= cv2.getPerspectiveTransform(ordered_corners,尺寸)#返回转换后的图像返回cv2.warpPerspective(图像,矩阵,(宽度,高度))def get_image_width_height(image):image_width = image.shape [1]#当前图像的宽度image_height = image.shape [0]#当前图像的高度返回image_width,image_heightdef compute_scaled_dimension(scale,image):image_width,image_height = get_image_width_height(图像)ratio_of_new_with_to_old =比例/图像宽度尺寸=(比例尺,int(图像高度*新的with_to_old的比例))返回尺寸def scale_image(图片,大小):image_resize_scaled = cv2.resize(图像,calculate_scaled_dimension(尺寸,图像),插值= cv2.INTER_AREA)返回image_resize_scaleddef rotation_image(图像,角度):#抓住图像的尺寸,然后确定中心(h,w)= image.shape [:2](cX,cY)=(w/2,h/2)#抓取旋转矩阵(应用#角度顺时针旋转),然后抓住正弦和余弦#(即矩阵的旋转分量)M = cv2.getRotationMatrix2D((cX,cY),-angle,1.0)cos = np.abs(M [0,0])sin = np.abs(M [0,1])#计算图像的新边界尺寸nW = int((h * sin)+(w * cos))nH = int(((h * cos)+(w * sin))#调整旋转矩阵以考虑平移M [0,2] + =(nW/2)-cXM [1,2] + =(nH/2)-cY#执行实际旋转并返回图像返回cv2.warpAffine(image,M,(nW,nH))图片= cv2.imread('images/damina_cc_back.jpg')original_image = image.copy()图片= scale_image(图片,500)#将图像转换为灰度,使其模糊,并在图像中找到边缘灰色= cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY)灰色= cv2.bilateralFilter(灰色,11,17,17)边= cv2.Canny(灰色,30,200)cnts = cv2.findContours(edged.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)如果len(cnts)== 2,则cnts = cnts [0]否则,cnts [1]cnts = sorted(cnts,键= cv2.contourArea,reverse = True)[:10]screen_cnt =无#在轮廓上循环对于C中的cnts:#近似轮廓周长= cv2.arcLength(c,True)大约= cv2.approxPolyDP(c,0.015 * peri,True)如果len(大约)== 4:screen_cnt =大约转换= Perspective_transform(image,screen_cnt)休息#绘制投资回报率cv2.drawContours(image,[screen_cnt],-1,(0,255,0),1)(h,w)= transform.shape [:2]如果(h> w):旋转= rotation_image(已转换,90)别的:旋转=已转换cv2.imshow("image",original_image)cv2.imshow("ROI",图片)cv2.imshow(已转换",已转换)cv2.imshow("rotated",旋转)cv2.waitKey(0) 

解决方案

要在裁剪后对齐图像,我们可以使用

现在有了孤立的角点,我们可以使用 cv2.getPerspectiveTransform()获得变换矩阵,并实际上使用 cv2.warpPerspective()获得变换后的图像.

  def Perspective_transform(图像,边角):#按顺时针顺序排列点ordered_corners = order_corner_points(角)top_l,top_r,bottom_r,bottom_l = ordered_corners#确定新图片的宽度,即新图片之间的最大距离#(右下和左下)或(右上和左上)x坐标width_A = np.sqrt((((bottom_r [0]-bottom_l [0])** 2)+(((bottom_r [1]-bottom_l [1])** 2))width_B = np.sqrt((((top_r [0]-top_l [0])** 2)+(((top_r [1]-top_l [1])** 2))宽度= max(int(width_A),int(width_B))#确定新图片的高度,即新图片之间的最大距离#(右上和右下)或(左上和左下)y坐标height_A = np.sqrt((((top_r [0]-bottom_r [0])** 2)+(((top_r [1]-bottom_r [1])** 2))height_B = np.sqrt((((top_l [0]-bottom_l [0])** 2)+(((top_l [1]-bottom_l [1])** 2))高度= max(int(height_A),int(height_B))#构造新的点以获得图像的自上而下的视图#top_r,top_l,bottom_l,bottom_r顺序尺寸= np.array([[0,0],[width-1,0],[width-1,height-1],[0,高度-1]],dtype ="float32")#转换为Numpy格式ordered_corners = np.array(ordered_corners,dtype ="float32")#查找透视变换矩阵矩阵= cv2.getPerspectiveTransform(ordered_corners,尺寸)#返回转换后的图像返回cv2.warpPerspective(图像,矩阵,(宽度,高度)) 

这是结果

我们可以使用此功能旋转图像

  def rotation_image(图像,角度):#抓住图像的尺寸,然后确定中心(h,w)= image.shape [:2](cX,cY)=(w/2,h/2)#抓取旋转矩阵(应用#角度顺时针旋转),然后抓住正弦和余弦#(即矩阵的旋转分量)M = cv2.getRotationMatrix2D((cX,cY),-angle,1.0)cos = np.abs(M [0,0])sin = np.abs(M [0,1])#计算图像的新边界尺寸nW = int(((h * sin)+(w * cos)))nH = int(((h * cos)+(w * sin))#调整旋转矩阵以考虑平移M [0,2] + =(nW/2)-cXM [1,2] + =(nH/2)-cY#执行实际旋转并返回图像返回cv2.warpAffine(image,M,(nW,nH)) 

旋转后的最终结果:

完整代码

  import cv2将numpy导入为npdef order_corner_points(corners):#将角分开成单个点#索引0-右上#1-左上方#2-左下#3-右下拐角= [(拐角处的拐角[0] [0],拐角[0] [1])]top_r,top_l,bottom_l,bottom_r =角[0],角[1],角[2],角[3]返回(top_l,top_r,bottom_r,bottom_l)def Perspective_transform(图像,角):#按顺时针顺序排列点ordered_corners = order_corner_points(角)top_l,top_r,bottom_r,bottom_l = ordered_corners#确定新图片的宽度,即新图片之间的最大距离#(右下和左下)或(右上和左上)x坐标width_A = np.sqrt((((bottom_r [0]-bottom_l [0])** 2)+(((bottom_r [1]-bottom_l [1])** 2))width_B = np.sqrt((((top_r [0]-top_l [0])** 2)+(((top_r [1]-top_l [1])** 2))宽度= max(int(width_A),int(width_B))#确定新图片的高度,即新图片之间的最大距离#(右上和右下)或(左上和左下)y坐标height_A = np.sqrt((((top_r [0]-bottom_r [0])** 2)+(((top_r [1]-bottom_r [1])** 2))height_B = np.sqrt((((top_l [0]-bottom_l [0])** 2)+(((top_l [1]-bottom_l [1])** 2))高度= max(int(height_A),int(height_B))#构造新的点以获得图像的自上而下的视图#top_r,top_l,bottom_l,bottom_r顺序尺寸= np.array([[0,0],[width-1,0],[width-1,height-1],[0,高度-1]],dtype ="float32")#转换为Numpy格式ordered_corners = np.array(ordered_corners,dtype ="float32")#查找透视变换矩阵矩阵= cv2.getPerspectiveTransform(ordered_corners,尺寸)#返回转换后的图像返回cv2.warpPerspective(图像,矩阵,(宽度,高度))def rotation_image(图像,角度):#抓住图像的尺寸,然后确定中心(h,w)= image.shape [:2](cX,cY)=(w/2,h/2)#抓取旋转矩阵(应用#角度顺时针旋转),然后抓住正弦和余弦#(即矩阵的旋转分量)M = cv2.getRotationMatrix2D((cX,cY),-angle,1.0)cos = np.abs(M [0,0])sin = np.abs(M [0,1])#计算图像的新边界尺寸nW = int(((h * sin)+(w * cos)))nH = int(((h * cos)+(w * sin))#调整旋转矩阵以考虑平移M [0,2] + =(nW/2)-cXM [1,2] + =(nH/2)-cY#执行实际旋转并返回图像返回cv2.warpAffine(image,M,(nW,nH))图片= cv2.imread('1.PNG')original_image = image.copy()#将图像转换为灰度,使其模糊,并在图像中找到边缘灰色= cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY)灰色= cv2.bilateralFilter(灰色,11,17,17)边= cv2.Canny(灰色,30,200)cnts = cv2.findContours(edged.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)如果len(cnts)== 2,则cnts = cnts [0]否则,cnts [1]cnts = sorted(cnts,键= cv2.contourArea,reverse = True)[:10]screen_cnt =无#在轮廓上循环对于C中的cnts:#近似轮廓周长= cv2.arcLength(c,True)大约= cv2.approxPolyDP(c,0.015 * peri,True)如果len(大约)== 4:screen_cnt =大约转换= Perspective_transform(原始图像,screen_cnt)休息#绘制投资回报率cv2.drawContours(image,[screen_cnt],-1,(0,255,0),3)#旋转图像旋转= rotation_image(已转换,-90)cv2.imshow("image",original_image)cv2.imshow("ROI",图片)cv2.imshow(已转换",已转换)cv2.imshow("rotated",旋转)cv2.waitKey(0) 

I have implemented a cropping algorithm on my solution that works pretty good. The problem is when the image is tilted, the crop will work but it will have background space showing as the images will show.

Cropping flow:

First step:

Second step:

Final result:

I have searched/tried multiple solutions but could not get a decent result or I'm not thinking the right way.

The expected result is this:

EDIT [FINAL RESULT]:

import cv2
import numpy as np

def order_corner_points(corners):
    # Separate corners into individual points
    # Index 0 - top-right
    #       1 - top-left
    #       2 - bottom-left
    #       3 - bottom-right
    corners = [(corner[0][0], corner[0][1]) for corner in corners]
    top_r, top_l, bottom_l, bottom_r = corners[0], corners[1], corners[2], corners[3]
    return (top_l, top_r, bottom_r, bottom_l)

def perspective_transform(image, corners):
    # Order points in clockwise order
    ordered_corners = order_corner_points(corners)
    top_l, top_r, bottom_r, bottom_l = 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(((bottom_r[0] - bottom_l[0]) ** 2) + ((bottom_r[1] - bottom_l[1]) ** 2))
    width_B = np.sqrt(((top_r[0] - top_l[0]) ** 2) + ((top_r[1] - top_l[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(((top_r[0] - bottom_r[0]) ** 2) + ((top_r[1] - bottom_r[1]) ** 2))
    height_B = np.sqrt(((top_l[0] - bottom_l[0]) ** 2) + ((top_l[1] - bottom_l[1]) ** 2))
    height = max(int(height_A), int(height_B))

    # Construct new points to obtain top-down view of image in 
    # top_r, top_l, bottom_l, bottom_r 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)

    # Return the transformed image
    return cv2.warpPerspective(image, matrix, (width, height))

def get_image_width_height(image):
    image_width = image.shape[1]  # current image's width
    image_height = image.shape[0]  # current image's height
    return image_width, image_height

def calculate_scaled_dimension(scale, image):
    image_width, image_height = get_image_width_height(image)
    ratio_of_new_with_to_old = scale / image_width


    dimension = (scale, int(image_height * ratio_of_new_with_to_old))
    return dimension

def scale_image(image, size):
    image_resized_scaled = cv2.resize(
        image,
        calculate_scaled_dimension(
            size,
            image
        ),
        interpolation=cv2.INTER_AREA
    )
    return image_resized_scaled

def rotate_image(image, angle):
    # Grab the dimensions of the image and then determine the center
    (h, w) = image.shape[:2]
    (cX, cY) = (w / 2, h / 2)

    # grab the rotation matrix (applying the negative of the
    # angle to rotate clockwise), then grab the sine and cosine
    # (i.e., the rotation components of the matrix)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # Compute the new bounding dimensions of the image
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # Adjust the rotation matrix to take into account translation
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # Perform the actual rotation and return the image
    return cv2.warpAffine(image, M, (nW, nH))

image = cv2.imread('images/damina_cc_back.jpg')
original_image = image.copy()

image = scale_image(image, 500)

# convert the image to grayscale, blur it, and find edges in the image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)

cnts = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]
screen_cnt = None

# loop over our contours
for c in cnts:
    # approximate the contour
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.015 * peri, True)

    if len(approx) == 4:
        screen_cnt = approx
        transformed = perspective_transform(image, screen_cnt)
        break

# Draw ROI
cv2.drawContours(image, [screen_cnt], -1, (0, 255, 0), 1)

(h, w) = transformed.shape[:2]

if (h > w):
    rotated = rotate_image(transformed, 90)
else:
    rotated = transformed

cv2.imshow("image", original_image)
cv2.imshow("ROI", image)
cv2.imshow("transformed", transformed)
cv2.imshow("rotated", rotated)
cv2.waitKey(0)

解决方案

To align your image after cropping, we can we can use a perspective transformation. To begin, we separate the four corners of the rectangle into individual points given to us by cv2.approxPolyDP(). We reorder the points into a clockwise orientation (top-left, top-right, bottom-right, bottom-left) using this function:

def order_corner_points(corners):
    # Separate corners into individual points
    # Index 0 - top-right
    #       1 - top-left
    #       2 - bottom-left
    #       3 - bottom-right
    corners = [(corner[0][0], corner[0][1]) for corner in corners]
    top_r, top_l, bottom_l, bottom_r = corners[0], corners[1], corners[2], corners[3]
    return (top_l, top_r, bottom_r, bottom_l)

This function gives us the the bounding box coordinates of the ROI

Now with the isolated corner points, we can obtain the transformation matrix using cv2.getPerspectiveTransform() and actually obtain the transformed image using cv2.warpPerspective().

def perspective_transform(image, corners):
    # Order points in clockwise order
    ordered_corners = order_corner_points(corners)
    top_l, top_r, bottom_r, bottom_l = 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(((bottom_r[0] - bottom_l[0]) ** 2) + ((bottom_r[1] - bottom_l[1]) ** 2))
    width_B = np.sqrt(((top_r[0] - top_l[0]) ** 2) + ((top_r[1] - top_l[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(((top_r[0] - bottom_r[0]) ** 2) + ((top_r[1] - bottom_r[1]) ** 2))
    height_B = np.sqrt(((top_l[0] - bottom_l[0]) ** 2) + ((top_l[1] - bottom_l[1]) ** 2))
    height = max(int(height_A), int(height_B))

    # Construct new points to obtain top-down view of image in 
    # top_r, top_l, bottom_l, bottom_r 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)

    # Return the transformed image
    return cv2.warpPerspective(image, matrix, (width, height))

Here's the result

We can rotate the image with this function

def rotate_image(image, angle):
    # Grab the dimensions of the image and then determine the center
    (h, w) = image.shape[:2]
    (cX, cY) = (w / 2, h / 2)

    # grab the rotation matrix (applying the negative of the
    # angle to rotate clockwise), then grab the sine and cosine
    # (i.e., the rotation components of the matrix)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # Compute the new bounding dimensions of the image
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # Adjust the rotation matrix to take into account translation
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # Perform the actual rotation and return the image
    return cv2.warpAffine(image, M, (nW, nH))

The final result after rotating:

Full code

import cv2
import numpy as np

def order_corner_points(corners):
    # Separate corners into individual points
    # Index 0 - top-right
    #       1 - top-left
    #       2 - bottom-left
    #       3 - bottom-right
    corners = [(corner[0][0], corner[0][1]) for corner in corners]
    top_r, top_l, bottom_l, bottom_r = corners[0], corners[1], corners[2], corners[3]
    return (top_l, top_r, bottom_r, bottom_l)

def perspective_transform(image, corners):
    # Order points in clockwise order
    ordered_corners = order_corner_points(corners)
    top_l, top_r, bottom_r, bottom_l = 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(((bottom_r[0] - bottom_l[0]) ** 2) + ((bottom_r[1] - bottom_l[1]) ** 2))
    width_B = np.sqrt(((top_r[0] - top_l[0]) ** 2) + ((top_r[1] - top_l[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(((top_r[0] - bottom_r[0]) ** 2) + ((top_r[1] - bottom_r[1]) ** 2))
    height_B = np.sqrt(((top_l[0] - bottom_l[0]) ** 2) + ((top_l[1] - bottom_l[1]) ** 2))
    height = max(int(height_A), int(height_B))

    # Construct new points to obtain top-down view of image in 
    # top_r, top_l, bottom_l, bottom_r 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)

    # Return the transformed image
    return cv2.warpPerspective(image, matrix, (width, height))

def rotate_image(image, angle):
    # Grab the dimensions of the image and then determine the center
    (h, w) = image.shape[:2]
    (cX, cY) = (w / 2, h / 2)

    # grab the rotation matrix (applying the negative of the
    # angle to rotate clockwise), then grab the sine and cosine
    # (i.e., the rotation components of the matrix)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])

    # Compute the new bounding dimensions of the image
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))

    # Adjust the rotation matrix to take into account translation
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # Perform the actual rotation and return the image
    return cv2.warpAffine(image, M, (nW, nH))

image = cv2.imread('1.PNG')
original_image = image.copy()

# convert the image to grayscale, blur it, and find edges in the image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)

cnts = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]
screen_cnt = None

# loop over our contours
for c in cnts:
    # approximate the contour
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.015 * peri, True)

    if len(approx) == 4:
        screen_cnt = approx
        transformed = perspective_transform(original_image, screen_cnt)
        break

# Draw ROI
cv2.drawContours(image, [screen_cnt], -1, (0, 255, 0), 3)

# Rotate image
rotated = rotate_image(transformed, -90)

cv2.imshow("image", original_image)
cv2.imshow("ROI", image)
cv2.imshow("transformed", transformed)
cv2.imshow("rotated", rotated)
cv2.waitKey(0)

这篇关于裁剪后如何检测和对齐倾斜的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆