【Opencv图像处理】透视与仿射变换

透视与仿射变换

你有没有注意到,当你拍摄一个矩形平面物体的图像时,角落角度很少是90°?请添加图片描述

这种现象是透视投影的一个特征,其中 3D 场景中的点(例如,矩形角)通过针孔投影到平面(相机图像传感器)上。靠近照相机的线段比距离照相机较远的相同长度的线段显示得更长。直角可能变得尖锐或钝,平行线可能看起来会聚到消失点。

在平面物体的自动检测中,透视畸变可能是一个问题。由于我们要检查对象特征是否具有正确的形状和大小,因此我们希望"反转"透视失真。如果我们能做到这一点,我们会得到一个图像,使物体看起来好像相机轴垂直于物体的表面。请添加图片描述
上图显示了反转透视失真的效果(此处为代码)。在本例中,书的角被映射到正方形的任意点,并用红色圆圈标记。右侧的图像更适合自动检测,因为可以轻松定位特征并与模板进行比较。
OpenCV提供了两个可以做到这一点的函数:warpAffine()和warpPerspective()。它们具有相同的签名,除了 warpAffine() 需要一个 2x3 转换矩阵,而 warpPerspective() 需要一个 3x3 转换矩阵。这些矩阵分别由函数 getAffineTransform() 和 getPerspectiveTransform() 计算。前者需要三对匹配的坐标,后者需要四对匹配的坐标。直观地说,得到三对比四对更容易,所以问题出现了:在什么情况下我们可以逃脱三对坐标并使用仿射变换而不是透视变换?
为了回答这个问题,让我们考虑图 3 中的两个图像。请添加图片描述
在右侧图像中,使用距离物体约7m的摄像头,线平行度比左侧图像中的清晰度保留得更好。如果我们计算仿射和透视变换,然后相应地扭曲这些图像,我们将获下图所示的图像。仿射变换后的结果
透视变换后的结果请添加图片描述
我们应该使用的标准是保持线路平行度。仿射变换可保持线并行性。如果要检查的对象在3D世界中具有平行线,并且图像中的相应线是平行的,则仿射变换就足够了。相反,如果3D世界中的平行线在图像中发散,则仿射变换是不够的:我们需要透视变换。
仿射变换原理
透视变换原理

Opencv代码

仿射变换


void cv::warpAffine	(	InputArray 	src,
OutputArray 	dst,
InputArray 	M,
Size 	dsize,
int 	flags = , INTER_LINEAR
int 	borderMode = , BORDER_CONSTANT
const Scalar & 	borderValue = Scalar() 
)		
Python:
cv.warpAffine(	src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]	) ->	dst

参数InputArray src:输入变换前的图像;
参数OutputArray dst:输出变换后图像,需要初始化一个空矩阵用来保存结果,不用设定矩阵尺寸;
参数InputArray M:变换矩阵;
参数Size dsize:设置输出图像大小;
参数int flags=INTER_LINEAR:设置插值方式,默认方式为线性插值;
M参数的获得Opencv中也有对应的函数

Mat getAffineTransform(const Point2f* src, const Point2f* dst)

参数const Point2f* src:原图像的变换点像素坐标;
参数const Point2f* dst:输出图像的变换点像素坐标;

代码

    string path = "D:\\QT\\Opencv\\Resources\\cards.jpg";  //"D:\QT\Opencv\Resources\cards.png"
    Mat img = cv::imread(path);

    Point2f src[4]= {{529,142},{771,190},{405,395},{674,457}};
    Point2f dst[4]= {{0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h}};

    for(int i = 0; i < 4; i++)
    {
        circle(img,src[i], 10, Scalar(0, 69, 255), FILLED);
    }


    matrix1 = getAffineTransform(src, dst);
    warpAffine(img, imgWarpAffine, matrix1, Point(w,h));

    imshow("Image",img);
    imshow("Image WarpAffine",imgWarpAffine);
    waitKey(0);

原图
仿射变换后的图

透视变换


void cv::warpPerspective	(	InputArray 	src,
OutputArray 	dst,
InputArray 	M,
Size 	dsize,
int 	flags = , INTER_LINEAR
int 	borderMode = , BORDER_CONSTANT
const Scalar & 	borderValue = Scalar() 
)		
Python:
cv.warpPerspective(	src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]	) ->	dst

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

M参数的获得Opencv中也有对应的函数

Mat cv::getPerspectiveTransform	(	const Point2f 	src[],
const Point2f 	dst[] 
)	

参数const Point2f* src:原图像的变换点像素坐标;
参数const Point2f* dst:输出图像的变换点像素坐标;

代码

    string path = "D:\\QT\\Opencv\\Resources\\cards.jpg";  //"D:\QT\Opencv\Resources\cards.png"
    Mat img = cv::imread(path);

    Point2f src[4]= {{529,142},{771,190},{405,395},{674,457}};
    Point2f dst[4]= {{0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h}};

    for(int i = 0; i < 4; i++)
    {
        circle(img,src[i], 10, Scalar(0, 69, 255), FILLED);
    }

    matrix = getPerspectiveTransform(src,dst);
    warpPerspective(img, imgWarp, matrix, Point(w,h));

    imshow("Image",img);
    imshow("Image Warp",imgWarp);
    waitKey(0);

源图
透视变换后的图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点云兔子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值