读书笔记-opencv-投影变换

article/2025/10/1 17:26:06

读书笔记-opencv-投影变换

原理解析

​ 透视变换是将图片投影到一个新的视平面,也称作投影映射.它是二维(x,y)到三维(X,Y,Z),再到另一个二维(x′,y′)空间的映射.相对于仿射变换,它提供了更大的灵活性,将一个四边形区域映射到另一个四边形区域(不一定是平行四边形).它不止是线性变换.但也是通过矩阵乘法实现的,使用的是一个3x3的矩阵,矩阵的前两行与仿射矩阵相(m11,m12,m13,m21,m22,m23),也实现了线性变换和平移,第三行用于实现透视变换
在这里插入图片描述

​ 在公式两边同时除以m33,得到一个有关8个未知数的方程组,只需要四个点就可以求出相关系数。
具体的推理过程,可以参见单应性变换,透视变换相关帖子。

代码示例

​ opencv提供相关的函数:

cv2.getPerspectiveTransform(src, dst)

​ 其中src是变换前坐标,dst是变换后的坐标,返回33的矩阵src和dst是4 * 2的二维ndarry,数据必须为32位浮点型

python实例

src_points = np.array([[165., 270.], [835., 270.], [360., 125.], [615., 125.]], np.float32)
dst_points = np.array([[165., 270.], [835., 270.], [165., 30.], [835., 30.]], dtype = "float32")
M = cv2.getPerspectiveTransform(src_points, dst_points)print(M)

​ 返回矩阵M是float64的数据类型

​ 对图片进行处理

if __name__ == "__main__":image_path = "c:\\users\\pictures\\saved pictures\\1.jpg"image = cv2.imread(image_path)#原图的宽高h,w = image.shape[:2]#原图的四个点与投影变换对应的点src = np.array([[0.0, 0.0],[w-1, 0], [0, h-1], [w-1, h-1]], np.float32)dst = np.array([[50, 50], [w/3, 50], [50, h-1], [w-1, h-1]], np.float32)#计算投影变换矩阵p = cv2.getPerspectiveTransform(src, dst)#利用计算出来的投影变换矩阵计算图像的投影变换r = cv2.warpPerspective(image, p, (w,h), borderValue=125)#显示原图和投影效果cv2.imshow("image", image);cv2.imshow("warpPersperctive", r)cv2.waitKey(0)cv2.destroyAllWindows()

​ 结果处理的图片:
在这里插入图片描述

C++实例

//method 1
//原矩阵Point2f src[] = { Point2f(0,0), Point2f(200.0, 0), Point2f(0,200.0), Point2f(200.0, 200.0) };//投影变换后的矩阵Point2f dst[] = { Point2f(100.0, 20.0), Point2f(200.0, 20.0), Point2f(50, 70), Point2f(250.0, 70.0) };//投影变换矩阵Mat M = getPerspectiveTransform(src, dst);//method 2
//原矩阵Mat src = (Mat_<float>(4, 2) << 0, 0, 200, 0, 0, 200, 200, 200);//投影变换后的矩阵Mat dst = (Mat_<float>(4, 2) << 100, 20, 200, 20, 50, 70, 250, 70);//投影变换矩阵Mat M = getPerspectiveTransform(src, dst);

对图片进行处理:

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui_c.h> 
#include<iostream>
#include<string>
using namespace cv;/************************************************************************/
/* 注意CV_EVENT_LBUTTONDOWN需要加载头文件 <opencv2/highgui/highgui_c.h> 
void circle(Mat & img, Point center, int radius, const Scalar & color, int thickness = 1, int lineType = 8, int shift = 0
该函数在途中用来画圆, img 代表输入图像, center代表圆心,color代表颜色, thickness代表线条的粗细, linetype线的类型,
opencv还提供rectangle, ellipse,line在图上画相应的线段*/
/************************************************************************/Mat InitImage;					//原图
Mat convertImage;				//转换后的图像Point2f IPoint, pIPoint;
int i = 0, j = 0;
Point2f src[4];					//存储原坐标
Point2f dst[4];					//存储对应的变换的坐标//通过以下鼠标事件,在要原图上面取四个坐标
/**
* @鼠标点击事件
* @return void
*/
void mouse_I(int event, int x, int y, int flags, void *param)
{switch (event){//记录左键case CV_EVENT_LBUTTONDOWN:IPoint = Point2f(x, y);					//记录坐标break;case CV_EVENT_LBUTTONUP:src[i] = IPoint;circle(InitImage, src[i], 7, Scalar(0), 3);		//标记i += 1;break;default:break;}
}//通过以下鼠标事件,在要输出的画布上面取四个对应坐标
/**
* @鼠标点击事件,在要输出的画布上面取四个对应坐标
* @return void
*/
void mouse_pI(int event, int x, int y, int flags, void *param)
{switch (event){case CV_EVENT_LBUTTONDOWN:pIPoint = Point2f(x, y);break;case CV_EVENT_LBUTTONUP:dst[j] = pIPoint;circle(convertImage, dst[j], 7, Scalar(0), 3);j += 1;break;default:break;}
}int main()
{//加载图片,imread(),第二个参加代表以何种方式加载,具体可以看Opencv的imread()函数解析std::string iamgePath = "C:\\Users\\huangxin\\Pictures\\Saved Pictures\\1.jpg";InitImage = imread(iamgePath, 1);if (!InitImage.data){return -1;}//输出图像convertImage = 255 * Mat::ones(InitImage.size(), CV_8UC1);//在原图定义,鼠标事件namedWindow("InitImage", 1);setMouseCallback("InitImage", mouse_I, NULL);//在输出窗口定义,鼠标事件namedWindow("ConvertImage", 1);setMouseCallback("ConvertImage", mouse_pI, NULL);imshow("InitImage", InitImage);imshow("ConvertImage", convertImage);while (!(i == 4 && j == 4)){imshow("InitImage", InitImage);imshow("ConvertImage", convertImage);if (waitKey(50) == 'q'){break;}}imshow("InitImage", InitImage);imshow("ConvertImage", convertImage);//移除鼠标事件setMouseCallback("InitImage", NULL, NULL);setMouseCallback("ConvertImage", NULL, NULL);//计算投影变换矩阵Mat p = getPerspectiveTransform(src, dst);//投影变化Mat resultMat;warpPerspective(InitImage, resultMat, p, convertImage.size());imshow("result: ", resultMat);waitKey(0);return 0;}

​ 在原图点击四个点,作为输入矩阵,在convertImage上面点击四个点作为输出矩阵,通过两个矩阵建立投影变换矩阵。

​ 处理的结果图片:
在这里插入图片描述


http://chatgpt.dhexx.cn/article/Td5TuhhD.shtml

相关文章

计算机图形学 | 投影变换

计算机图形学 | 投影变换 计算机图形学 | 投影变换7.1 有趣的投影投影的概念平行投影正投影斜投影 透视投影 7.2 规范化的投影变换观察的要素观察空间规范化的投影变换 华中科技大学《计算机图形学》课程 MOOC地址&#xff1a;计算机图形学&#xff08;HUST&#xff09; 计算…

使用 OpenCV 进行图像投影变换

投影变换&#xff08;仿射变换&#xff09; 在数学中&#xff0c;线性变换是将一个向量空间映射到另一个向量空间的函数&#xff0c;通常由矩阵实现。如果映射保留向量加法和标量乘法&#xff0c;则映射被认为是线性变换。 要将线性变换应用于向量&#xff08;即&#xff0c;一…

Opencv之投影变换

学习资料参考&#xff1a; 张平.《OpenCV算法精解&#xff1a;基于Python与C》.[Z].北京.电子工业出版社.2017. 原理 平面的物体若在三维空间发生了旋转&#xff0c;那么这就是投影变换。平面的物体可以借助二维投影变换进行三维变换模型化得到修正。 处理函数 c中的getPersp…

ArcMap 投影变换

在投影变换之前&#xff0c;首先需要理清出我们拿到的工程数据到底是哪一个投影坐标系&#xff0c;只有清楚是哪一个坐标系才能给我们矢量化出来的数据进行定义投影&#xff08;如果是当地的投影坐标系&#xff0c;可以查看自定义投影坐标系文章&#xff0c;新建出当地的投影坐…

OpenCV : 投影变换

投影变换 物体在三维空间发生了旋转,叫做投影变换.由于可能出现阴影或遮挡,所以变换后较难复原.如果物体时平面的,就可以通过投影变换物体三维变换进行模型化,这叫做专用的二维投影变换. 矩阵表示: [ x ~ y ~ z ~ ] [ a 11 a 12 a 13 a 21 a 22 a 23 a 31 a 32 a 33 ] [ x …

Halcon 第七章『图像的几何变换』◆第2节:投影变换

一、介绍 投影变换也叫透射变换、投影映射。透射变换是将图像投影到一个新的视平面&#xff0c;是一种二维坐标到三维坐标的变换。 透射变换是仿射变换的延续&#xff0c;也可以说仿射变换是透射变换的一种特殊形式。其特殊性在于变换后图像的形状仍然维持原状。投影变换包括的…

投影变换原理和用法

一、定义&#xff1a;投影变换也叫透射变换、投影映射。透射变换是将图像投影到一个新的视平面&#xff0c;是一种二维坐标到三维坐标的变换。 透射变换是仿射变换的延续&#xff0c;也可以说仿射变换是透射变换的一种特殊形式。其特殊性在于变换后图像的形状仍然维持原状。投影…

基于libVLC的视频播放器之四:直接使用libVLC

一.效果 播放本地文件 播放网络url:rtsp://3.84.6.190/vod/mp4:BigBuckBunny_115k.mov 二.实现 既然有VLC-Qt,为什么还要直接调用libVLC呢,因为直接调用会加深对整个播放流程的理解,方便后面修改VLC-Qt源码。

MFC调用vlc动态库libvlc.dll实现简单播放器 中文路径处理

一、简单说明 本文讲解利用MFC调用vlc&#xff08;2.0.0&#xff09;的动态库实现简单的播放器&#xff0c;实现播放、暂停、停止、音量控制、进度控制&#xff0c;支持中文路径等。 VLC 中文路径转码问题<转> 最近用MFC编写调用libVLC的程序时碰到中文路径不能打开的问题…

VLC-Android编译

1.环境 硬核条件----------linux(这里用ubuntu代替)15.5.1 build-15018445 PS&#xff1a;这里安装好虚拟机以后&#xff0c;尽可能分配大内存(8GB起步)&#xff0c;如果电脑本地不允许开这么大的内存给虚拟机&#xff0c;则本博文后面的内容可能帮助不大。 安装好虚拟机后&am…

VLC介绍以及库的使用

VLC原指VideoLAN客户端(VideoLANClient)&#xff0c;是一款开源的、跨平台的、可扩展的、多媒体播放器、流媒体服务器及框架&#xff0c;可播放大多数多媒体文件&#xff0c;以及DVD、音频CD、VCD及各类流媒体协议&#xff0c;现更名为VLC media player&#xff0c;最新版本为2…

LibVLC —— 常用函数解析

函数 ● LIBVLC_API libvlc_instance_t *libvlc_new( int argc , const char *const *argv ); 功能&#xff1a;创建libvlc_instance_t对象。 用法&#xff1a; libvlc_instance_t *VlcInstance libvlc_new(0, nullptr);参数&#xff1a;                具体…

【玩转VLC】--- 基于libvlc写个最简单的播放器

通过【玩转VLC】--- ubuntu下编译vlc 我们已经把vlc编译哦了。生成了一系列的bin和libvlc.so. 接下来我们就用编译好的libvlc.so搞一个最简单的播放器。 我认为vlc的伟大之处有一点就是他并没有把整个播放器写成一个硬生生的bin。而是独立出来个libvlc库&#xff0c;其他的玩…

最简单的基于libVLC的例子:最简单的基于libVLC的推流器

最简单的基于libVLC的例子文章列表&#xff1a; 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器&#xff08;图形界面版&#xff09; 最简单的基于libVLC的例子&#xff1a;最简…

C++调用libVLC播放视频

1、下载libVLC的sdk Index of /pub/videolan/vlc/ 注意下载.7z结尾的 2、Visual Studio建立C的windows控制台项目 3、文件准备 &#xff08;1&#xff09;sdk文件夹解压缩到项目文件夹下 &#xff08;2&#xff09;在Debug下方压缩包内的几个文件 、 4、配置项目属性 注意…

最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器(图形界面版)

最简单的基于libVLC的例子文章列表&#xff1a; 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器&#xff08;图形界面版&#xff09; 最简单的基于libVLC的例子&#xff1a;最简…

基于libVLC的视频播放器之二:使用VLC-Qt播放RTSP流

此篇是 使用VLC浏览器插件播放RTSP流的姊妹篇。 一.直接使用libVLC libVLC是VLC media player多媒体框架的核心引擎和接口&#xff0c;开发者使用它能轻松的创建大量具有VLC特性的应用。 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器详细介绍了libVL…

最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器

最简单的基于libVLC的例子文章列表&#xff1a; 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器 最简单的基于libVLC的例子&#xff1a;最简单的基于libVLC的视频播放器&#xff08;图形界面版&#xff09; 最简单的基于libVLC的例子&#xff1a;最简…

用VLC开发视频播放器/组件(两种方式:libVLC / VLC-Qt)

测试环境 MSVC-2015Qt 5.14.2QCreator 1. libVLC&#xff08;关键步骤&#xff09; 参考&#xff1a;心流剑 libVLC 各版本 下载链接 我的下载版本为&#xff1a;3.0.11 sdk/lib文件夹目录 qmake vlc 部分的配置&#xff08;路径根据自己的修改&#xff09;只需要&#…

idea如何取消debug所有断点

1、debug模式下&#xff0c;在idea左下方找到【View Breakpoints】按钮或者直接按【CtrlShiftF8】快捷键&#xff0c;如下图&#xff1a; 2、在左侧窗口中&#xff0c;点击【Java Line Breakpoints】前方的全选框&#xff0c;如下图&#xff1a; 3、取消 【Java Line Breakp…