在OpenCV中,仿射变更(Affine Transformation)和透视变更(Perspective Transformation)是两种常用的图像多少变更方法。
变更方法实用场景仿射变更简朴的多少变更(平移、旋转、缩放、剪切)。透视变更改变图像视角和模拟3D投影结果。 变更方法解释特点应用场景实现方法仿射变更仿射变更是一种线性变更,它保持了图像中直线的直线性和平行线的平行性。常见的仿射变更包括平移、旋转、缩放、剪切等。输入空间和输出空间之间存在线性关系。
直线和平行性在变更后保持不变,但角度和长度可能发生改变。图像平移、旋转或缩放。
图像对齐(如在模板匹配中的坐标对齐)。
简朴的多少变形,如剪切变更。准备变更矩阵(2x3)。
使用 OpenCV 的 cv2.warpAffine() 方法举行变更。透视变更透视变更是一种非线性变更,用于将图像从一个平面映射到另一个平面。它答应改变图像的视角,从而得到三维的透视结果。输入空间和输出空间之间是非线性的。
直线保持直线,但平行线不再平行。
需要 4 对点来定义变更关系。图像校正(如将拍摄的书本照片调整为平面图)。
视角转换(如模拟3D结果或鸟瞰视图)。
投影变更(如在增强实际中的投影映射)。定义输入和输出平面上的 4 个对应点。
使用 cv2.getPerspectiveTransform() 获取 3x3 的透视变更矩阵。
使用 cv2.warpPerspective() 方法举行变更。 1 添加依赖
2 测试代码
- package com.xu.com.xu.trans
- import org.bytedeco.javacpp.Loader
- import org.bytedeco.javacpp.Pointer
- import org.bytedeco.opencv.global.opencv_core
- import org.bytedeco.opencv.global.opencv_highgui
- import org.bytedeco.opencv.global.opencv_imgcodecs
- import org.bytedeco.opencv.global.opencv_imgproc
- import org.bytedeco.opencv.opencv_core.Mat
- import org.bytedeco.opencv.opencv_core.Point
- import org.bytedeco.opencv.opencv_core.Point2f
- import org.bytedeco.opencv.opencv_core.Scalar
- import org.bytedeco.opencv.opencv_highgui.MouseCallback
- object Restore {
- init {
- Loader.load(opencv_core::class.java)
- }
- @JvmStatic
- fun main(args: Array<String>) {
- restore(1)
- }
- /**
- * 透视变换 图像修改
- *
- * @since 2025年1月20日12点33分
- */
- private fun restore(type: Int) {
- // 读取图像
- val src = opencv_imgcodecs.imread("C:\\Users\\xuyq\\Desktop\\11.png")
- if (src == null || src.empty()) {
- return
- }
- // 创建源点矩阵4个点
- val org = Mat(1, 4, opencv_core.CV_32FC2)
- org.ptr(0, 0).put<Pointer>(Point2f(0f, 0f))
- org.ptr(0, 1).put<Pointer>(Point2f(src.cols().toFloat(), 0f))
- org.ptr(0, 2).put<Pointer>(Point2f(src.cols().toFloat(), src.rows().toFloat()))
- org.ptr(0, 3).put<Pointer>(Point2f(0f, src.rows().toFloat()))
- // 创建目标点矩阵4个点
- val dst = Mat(1, 4, opencv_core.CV_32FC2)
- if (1 == type) {
- val target = click(src)
- for (i in target.indices) {
- dst.ptr(0, i).put<Pointer>(target[i])
- }
- } else {
- dst.ptr(0, 0).put<Pointer>(Point2f(21f, 20f))
- dst.ptr(0, 1).put<Pointer>(Point2f(953f, 74f))
- dst.ptr(0, 2).put<Pointer>(Point2f(847f, 574f))
- dst.ptr(0, 3).put<Pointer>(Point2f(109f, 643f))
- }
- // 获取透视变换矩阵
- val matrix = opencv_imgproc.getPerspectiveTransform(dst, org)
- // 应用透视变换
- val images = Mat()
- opencv_imgproc.warpPerspective(src, images, matrix, src.size())
- // 显示结果
- opencv_highgui.imshow("RESTORE", images)
- opencv_highgui.waitKey(0)
- }
- private fun click(image: Mat): List<Point2f> {
- // 创建画布(白色背景)
- val window = "Click"
- // 创建窗口
- opencv_highgui.namedWindow(window, opencv_highgui.WINDOW_AUTOSIZE)
- val points = listOf<Point2f>().toMutableList()
- // 创建鼠标回调对象
- val callback = object : MouseCallback() {
- override fun call(event: Int, x: Int, y: Int, flags: Int, params: Pointer?) {
- when (event) {
- opencv_highgui.EVENT_LBUTTONDOWN -> {
- println("点击点: ($x, $y)")
- points.add(Point2f(x.toFloat(), y.toFloat()))
- // 在原图上绘制点
- opencv_imgproc.circle(
- image, Point(x, y), 5,
- Scalar(0.0, 0.0, 255.0, 0.0), -1, opencv_imgproc.LINE_AA, 0
- )
- opencv_highgui.imshow(window, image)
- }
- }
- }
- }
- // 设置鼠标回调
- opencv_highgui.setMouseCallback(window, callback, null)
- // 主循环
- while (true) {
- opencv_highgui.imshow(window, image)
- if (opencv_highgui.waitKey(1).toChar() == 27.toChar() || points.size >= 4) {
- opencv_highgui.destroyWindow(window)
- break
- }
- }
- return points
- }
- }
复制代码 3 测试结果
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |