Python中OpenCV透视变换恢复扭曲图像

Python中OpenCV透视变换恢复扭曲图像

在处理图像问题时,经常会遇到将要处理的目标的位置是斜的,需要使用透视变换进行矫正。如下图,该图片中左边的目标是扭曲倾斜拍摄的,那么任务就是将其矫正过来,如下图右图所示。

在这里插入图片描述

方法

  • 前提1:这里假设我已经知道四个点坐标(可用深度学习方法检测/分割)和目标宽高比(比如身份证、驾驶证、发票等有固定宽高比)
  • 基本流程:
    • 1、计算变换矩阵getPerspectiveTransform
    • 2、透视变换warpPerspective
  • 一些理论可参考:https://zhuanlan.zhihu.com/p/36082864

函数接口简介

# 变换矩阵函数
Mat getPerspectiveTransform(const Point2f* src, const Point2f* dst)
# 参数const Point2f* src:原图的三个固定顶点
# 参数const Point2f* dst:目标图像的三个固定顶点
# 返回值:Mat型变换矩阵,可直接用于warpPerspective()函数
# 注意,顶点数组长度超过4个,则会自动以前4个为变换顶点;数组可用Point2f[]或Point2f*表示

# 透视变换函数
void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
# 参数InputArray src:输入变换前的图像;
# 参数OutputArray dst:输出变换后图像,需要初始化一个空矩阵用来保存结果,不用设定矩阵尺寸;
# 参数Size dsize:设置输出图像大小;
# 参数int flags=INTER_LINEAR:设置插值方式,默认方式为线性插值;

代码

def get_rotate_crop_image(img, points):
    '''
    img_height, img_width = img.shape[0:2]
    left = int(np.min(points[:, 0]))
    right = int(np.max(points[:, 0]))
    top = int(np.min(points[:, 1]))
    bottom = int(np.max(points[:, 1]))
    img_crop = img[top:bottom, left:right, :].copy()
    points[:, 0] = points[:, 0] - left
    points[:, 1] = points[:, 1] - top
    '''
    assert len(points) == 4, "shape of points must be 4*2"
    img_crop_width = int(
        max(
            np.linalg.norm(points[0] - points[1]),
            np.linalg.norm(points[2] - points[3])))
    img_crop_height = int(
        max(
            np.linalg.norm(points[0] - points[3]),
            np.linalg.norm(points[1] - points[2])))
    pts_std = np.float32([[0, 0], [img_crop_width, 0],
                          [img_crop_width, img_crop_height],
                          [0, img_crop_height]])
    M = cv2.getPerspectiveTransform(points, pts_std)
    dst_img = cv2.warpPerspective(
        img,
        M, (img_crop_width, img_crop_height),
        borderMode=cv2.BORDER_REPLICATE,
        flags=cv2.INTER_CUBIC)
    return dst_img


if __name__ == '__main__':
    img_path = '../images/trans/test01.jpg'
    img = cv2.imread(img_path)
    # 四个定点左边
    points = [180, 160, 656, 152, 760, 414, 86, 428]
    # 行驶证比例:102/73
    points = np.array(points).astype(np.float32).reshape(4, 2)
    partImg = get_rotate_crop_image(img, points)
    height, width, _ = partImg.shape
    cv2.imwrite('text01.jpg', partImg)
    # 最长边为长边,resize图片
    new_height = int(width * 73/102)
    partImg = cv2.resize(partImg,(width, new_height))
    cv2.imwrite('text.jpg', partImg)

完整结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lxk2017/article/details/130366264