首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

《OpenCV》——图像透视转换

  • 25-02-16 06:01
  • 3573
  • 8213
blog.csdn.net

图像透视转换简介

  • 在 OpenCV 里,图像透视转换属于重要的几何变换,也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。

原理

在这里插入图片描述

实现步骤

  • 选取对应点:要在源图像和目标图像上分别找出至少四个对应的点。这些对应点不能共线,因为它们是计算透视变换矩阵的关键依据。
  • 计算透视变换矩阵:利用 OpenCV 的 cv2.getPerspectiveTransform 函数,依据前面选取的对应点来计算透视变换矩阵。
  • 应用透视变换:使用 cv2.warpPerspective 函数,将计算得到的透视变换矩阵应用到源图像上,从而得到透视变换后的图像。

相关函数

  • cv2.getPerspectiveTransform
    • 功能:计算透视变换矩阵。
    • 语法:cv2.getPerspectiveTransform(src, dst)
    • 参数:
      • src:源图像中四个点的坐标,数据类型为 np.float32。
      • dst:目标图像中对应的四个点的坐标,数据类型为 np.float32。
  • 返回值:返回一个 3×3 的透视变换矩阵。
  • cv2.warpPerspective
    • 功能:对图像应用透视变换。
    • 语法:cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
    • 参数:
      • src:源图像。
      • M:透视变换矩阵。
      • dsize:输出图像的大小,格式为 (width, height)。
      • dst(可选):输出图像。
      • flags(可选):插值方法,如 cv2.INTER_LINEAR 等。
      • borderMode(可选):边界填充模式。
      • borderValue(可选):边界填充值。
  • 返回值:返回透视变换后的图像。

应用场景

  • 图像校正:校正因拍摄角度倾斜而产生畸变的图像,例如校正拍摄的文档图像,使其呈现为标准的矩形。
  • 虚拟现实:在虚拟现实场景中,将二维图像转换为具有透视效果的三维场景,增强沉浸感。
  • 自动驾驶:对车载摄像头拍摄的图像进行透视变换,以获取道路的鸟瞰图,辅助车辆进行路径规划和障碍物检测。

图像透视转换实例

对以下图片进行图像透视转换:
在这里插入图片描述

实例步骤

导入所需库

import numpy as np
import cv2
  • 1
  • 2

写入所需函数

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    # 初始化 dim 为 None,用于存储调整后的图像尺寸
    dim = None
    # 获取图像的高度和宽度
    (h, w) = image.shape[:2]
    # 如果宽度和高度都未指定,直接返回原图像
    if width is None and height is None:
        return image
    # 如果仅指定了高度,计算宽度的缩放比例
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    # 如果仅指定了宽度,计算高度的缩放比例
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    # 使用 cv2.resize 函数根据 dim 和指定的插值方法对图像进行缩放
    resized = cv2.resize(image, dim, interpolation=inter)
    # 返回缩放后的图像
    return resized

# 定义一个函数用于显示图像
# name: 显示窗口的名称
# img: 要显示的图像
def cv_show(name,img):
    # 使用cv2.imshow函数显示图像,第一个参数是窗口名称,第二个参数是要显示的图像
    cv2.imshow(name,img)
    # 使用cv2.waitKey(0)等待用户按键,参数为0表示无限等待
    cv2.waitKey(0)

# 定义一个函数用于对输入的四个点进行排序
# pts: 输入的四个点的坐标,是一个形状为(4, 2)的numpy数组
def order_points(pts):
    # 创建一个形状为(4, 2)的全零数组,数据类型为float32,用于存储排序后的点
    rect = np.zeros((4,2),dtype="float32")
    # 计算每个点的x和y坐标之和
    s = pts.sum(axis=1)
    # 找到坐标和最小的点,这个点通常是左上角的点
    rect[0]=pts[np.argmin(s)]
    # 找到坐标和最大的点,这个点通常是右下角的点
    rect[2]=pts[np.argmax(s)]
    # 计算每个点的x和y坐标之差
    diff = np.diff(pts,axis=1)
    # 找到坐标差最小的点,这个点通常是右上角的点
    rect[1]=pts[np.argmin(diff)]
    # 找到坐标差最大的点,这个点通常是左下角的点
    rect[3]=pts[np.argmax(diff)]
    # 返回排序后的四个点
    return rect

# 定义一个函数用于进行四点透视变换
# image: 输入的原始图像
# pts: 输入的四个点的坐标,是一个形状为(4, 2)的numpy数组
def four_point_transform(image,pts):
    # 调用order_points函数对输入的四个点进行排序
    rect = order_points(pts)
    # 解包排序后的四个点,分别赋值给左上角、右上角、右下角和左下角的点
    (tl,tr,br,bl) = rect

    # 计算新图像的宽度,通过计算右下角和左下角点之间的距离
    widthA = np.sqrt(((br[0]-bl[0])**2)+((br[1]-bl[1])**2))
    # 计算新图像的宽度,通过计算右上角和左上角点之间的距离
    widthB = np.sqrt(((tr[0]-tl[0])**2)+((tr[1]-tl[1])**2))
    # 取两个宽度中的最大值作为新图像的宽度
    maxWidth = max(int(widthA),int(widthB))
    # 计算新图像的高度,通过计算右上角和右下角点之间的距离
    heightA  = np.sqrt(((tr[0]-br[0])**2)+((tr[1]-br[1])**2))
    # 计算新图像的高度,通过计算左上角和左下角点之间的距离
    heightB  = np.sqrt(((tl[0]-bl[0])**2)+((tl[1]-bl[1])**2))
    # 取两个高度中的最大值作为新图像的高度
    maxHeight = max(int(heightA),int(heightB))
    # 创建一个形状为(4, 2)的numpy数组,用于存储变换后的四个点的坐标
    dst = np.array([[0,0],[maxWidth-1,0],[maxWidth-1,maxHeight-1],[0,maxHeight-1]],dtype="float32")

    # 使用cv2.getPerspectiveTransform函数计算透视变换矩阵
    M = cv2.getPerspectiveTransform(rect,dst)
    # 使用cv2.warpPerspective函数进行透视变换,得到变换后的图像
    warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))
    # 返回变换后的图像
    return warped
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

获取图片信息并处理图片

import cv2

# 读取指定路径的图片,返回一个表示图像的多维数组
image = cv2.imread('dan_zi.jpg')
# 调用自定义的cv_show函数展示原始图像,窗口名为'image'
cv_show('image', image)

# 计算原始图像高度与500像素的比例,后续用于恢复尺寸
ration = image.shape[0] / 500.0
# 复制原始图像,避免后续操作修改原始数据
orig = image.copy()
# 调用resize函数将图像高度调整为500像素,保持宽高比
image = resize(orig, height=500)
# 调用cv_show函数展示调整大小后的图像,窗口名为'1'
cv_show('1', image)

# 打印提示信息,表明进入轮廓检测步骤
print("STEP 1: 轮廓检测")
# 将调整大小后的图像从BGR颜色空间转换为灰度颜色空间
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 运用Otsu's算法进行二值化处理,得到二值化后的图像
edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 在二值化图像的副本上查找轮廓,使用RETR_LIST检索模式和CHAIN_APPROX_SIMPLE近似方法
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
# 在图像副本上绘制所有检测到的轮廓,颜色为红色,线条宽度为1像素
image_contours = cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 1)
# 调用cv_show函数展示绘制了所有轮廓的图像,窗口名为'image_contours'
cv_show("image_contours", image_contours)

# 打印提示信息,表明进入获取最大轮廓步骤
print("STEP 2:获取最大轮廓")
# 按轮廓面积从大到小对检测到的轮廓进行排序,选取面积最大的轮廓
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]

# 计算最大轮廓的周长,参数True表示轮廓是封闭的
peri = cv2.arcLength(screenCnt, True)
# 对最大轮廓进行多边形逼近,以减少轮廓上的点数,第二个参数为逼近精度
screenCnt = cv2.approxPolyDP(screenCnt, 0.02 * peri, True)
# 打印逼近后轮廓的形状信息
print(screenCnt.shape)

# 在图像副本上绘制逼近后的最大轮廓,颜色为绿色,线条宽度为2像素
image_contour = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 255, 0), 2)

# 展示绘制了最大逼近轮廓的图像,窗口名为'image_contour'
cv2.imshow("image_contour", image_contour)
# 等待用户按键,防止窗口立即关闭
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

进行透视转换

# 调用之前定义的 four_point_transform 函数对原始图像进行四点透视变换
# screenCnt.reshape(4, 2) * ration 是将之前获取的轮廓点恢复到原始图像的尺寸
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ration)
# 将透视变换后的图像保存为 invoice_new.jpg
cv2.imwrite("invoice_new.jpg", warped)
# 创建一个名为 "xxxxx" 的窗口,并且该窗口大小可以调整
cv2.namedWindow("xxxxx", cv2.WINDOW_NORMAL)
# 在 "xxxxx" 窗口中显示透视变换后的图像
cv2.imshow("xxxxx", warped)
# 等待用户按键,防止窗口立即关闭
cv2.waitKey(0)

# 将透视变换后的图像从 BGR 颜色空间转换为灰度颜色空间
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
# 调用 resize 函数将灰度图像的宽度调整为 400 像素
warped = resize(warped, 400)
# 对调整大小后的灰度图像使用 Otsu's 算法进行二值化处理
warped = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# 调用自定义的 cv_show 函数显示二值化后的图像,窗口名为 "1111"
cv_show("1111", warped)

# 创建一个 1x1 的矩形结构元素,用于形态学操作
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
# 对二值化后的图像进行闭运算,填充小孔和连接相邻物体
closeX = cv2.morphologyEx(warped, cv2.MORPH_CLOSE, rectKernel)
# 调用自定义的 cv_show 函数显示闭运算后的图像,窗口名为 'gradX'
cv_show('gradX', closeX)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

结果显示

在这里插入图片描述

invoice_new.jpg
在这里插入图片描述

在这里插入图片描述

如果不想使用这张照片,换其他图片也是可以的,处理步骤都是相同的

注:本文转载自blog.csdn.net的Kai HVZ的文章"https://blog.csdn.net/lou0720/article/details/145328782"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

114
音视频
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top