【OpenCV】广告屏换图 文稿矫正 透视变换 C++ 案例实现

目录

前言

一、透视变换的概念

二、透视变换工作原理

三、相关函数

1.findHomography函数

2.warpPerspective函数

3.getPerspectiveTransform函数

四、透视变换案例

案例1:文稿矫正

案例2:广告屏换图

五、总结


前言

本文以实现广告屏换图为目标,学习OpenCV透视变化相关知识,核心的内容包括:OpenCV透视变化概念透视变化工作原理,以及广告屏换图文稿矫正实现 

一、透视变换的概念

  • 仿射变换透视变换在图像还原、图像局部变化处理方面有重要意义
  • 通常情况下,在2D平面中,仿射变换的应用较多,在3D平面中,透视变换又有了自己的一席之地,两种变换原理相似,结果也类似,可针对不同的场合使用适当的变换
  • 仿射变换透视变换的数学原理不需深究,在应用层面,仿射变换是图像基于3个固定顶点的变换,如下图所示:

二、透视变换工作原理

  • 透视变换:本质是将图像投影到一个新的视平面
  • 其通用变换公式,如下图所示:

  • (u,v)为原始图像像素坐标,(x=x’/w’,y=y’/w’)为变换之后的图像像素坐标
  • 相关公式,本文不做过多阐述,图解如下:

  • 仿射变换:可以理解为透视变换的特殊形式
  • 数学表达式,如下图所示:

 

  • 所以,给定透视变换对应的四对像素点坐标,即可求得透视变换矩阵
  • 反之,给定透视变换矩阵,即可对图像或像素点坐标完成透视变换
  • 如下图所示:

 

三、相关函数

1.findHomography函数

📌函数功能:找到两个平面之间的变换矩阵

📌参数:如下表所示

2.warpPerspective函数

📌函数功能:对图像进行透视变换,变形

📌参数:

  • src – 输入图像
  • dst – 大小为dsize且类型与src相同的输出图像
  • M – 3×3变换矩阵
  • dsize – 输出图像的大小
  • 下图中红点即为固定顶点,在变换先后固定顶点的像素值不变
  • 图像整体则根据变换规则进行变换同理,透视变换是图像基于4个固定顶点的变换

3.getPerspectiveTransform函数

  • C++方式1:Mat getPerspectiveTransform(InputArray src, InputArray dst)  
  • C++方式2:Mat getPerspectiveTransform(const Point2f src[], const Point2f dst[]) 

📌函数功能:根据源图像和目标图像上的四对点坐标来计算从原图像透视变换到目标头像的透视变换矩阵

📌参数:

  • src – 源图像中四边形顶点的坐标    
  • dst – 目标图像中相应四边形顶点的坐标
  • 该函数计算透视变换的3乘3矩阵,以便实现以下计算:

四、透视变换案例

  • 首先,先试想一下,我们要将下图单独取一张平面出来(例如:A)该如何实现呢? 

案例1:文稿矫正

  • 这是本案例所用到的图片素材

  • 实现效果

  • 其他奇奇怪怪的东西的效果

案例1 完整代码

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

struct imagedata
{
    Mat img;//目标图像
    vector <Point2f> points;//3D点
};

//鼠标操作函数:用于选择四个角的点(使用方法有顺序的,从左上角顺时针选择,选完之后回车)
void mouseHundle(int event,int x,int y,int flag,void *per)
{
    struct imagedata * d=(struct imagedata*)per;
    if(event==EVENT_LBUTTONDOWN)
    {
        //确定按下的是鼠标左键
        //用圆形标记一下鼠标按下左键标记的位置
        circle(d->img,Point(x,y),3,Scalar(0,255,0),3,CV_AA);//在图上标记,圆心为点击的位置
        imshow("image",d->img);//原窗口上显示
        if(d->points.size()<4)
        {
            d->points.push_back(Point2f(x,y));//把点击的点存起来
        }
    }
}

void example_1()
{
    Mat image=imread("C:/Users/86177/Desktop/image/777.jpg");
    Mat result=Mat::zeros(400,500,CV_8UC1);//400*500的大小,但是里面没有东西

    //存放四个转换以后的坐标
    vector <Point2f>obj;
    obj.push_back(Point2f(0,0));
    obj.push_back(Point2f(500,0));
    obj.push_back(Point2f(500,400));
    obj.push_back(Point2f(0,400));//转换后的坐标

    imshow("image",image);
    struct imagedata data;
    data.img=image;

    setMouseCallback("image",mouseHundle,&data);//鼠标处理的回调函数

    waitKey(0);//按任意键关闭当前显示的窗口,显示下一个窗口

    Mat res=findHomography(data.points,obj,CV_RANSAC);//利用RANSAC算法计算出来一个小矩阵

    warpPerspective(image,result,res,result.size());  //结果转换

    imshow("result",result);

    waitKey(0);
}

int main(int argc, char *argv[])
{
    example_1();
    return 0;
}

案例2:广告屏换图

  • 这是本案例所用到的图片素材 

  • 实现效果

  • 变换过程,如下图所示: 

案例2 完整代码

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

struct imagedata
{
    Mat img;//目标图像
    vector <Point2f> points;//3D点
};

//鼠标操作函数:用于选择四个角的点(使用方法有顺序的,从左上角顺时针选择,选完之后回车)
void mouseHundle(int event,int x,int y,int flag,void *ptr)
{
    struct imagedata * d=(struct imagedata*)ptr;
    if(event==EVENT_LBUTTONDOWN)
    {
        //确定按下的是鼠标左键
        //用圆形标记一下鼠标按下左键标记的位置
        circle(d->img,Point(x,y),3,Scalar(0,255,0),3,CV_AA);//在图上标记,圆心为点击的位置
        //imshow("image",d->img);//原窗口上显示
        imshow("dst",d->img);//原窗口上显示

        if(d->points.size()<4)//只存下来,最先点的前四个点
        {
            d->points.push_back(Point2f(x,y));//把鼠标操作点击的点存起来
        }
    }
}

void example_2()
{
    Mat image1=imread("C:/Users/86177/Desktop/image/2222.jpg");//广告屏替换图片路径
    Mat image2=imread("C:/Users/86177/Desktop/image/city.jpg");//背景图片路径

    Mat dst=image2.clone();//克隆

    vector <Point2f>obj;
    obj.push_back(Point2f(0,0));
    obj.push_back(Point2f(image1.cols,0));
    obj.push_back(Point2f(image1.cols,image1.rows));
    obj.push_back(Point2f(0,image1.rows));//转换后的坐标

    imshow("dst",dst);
    struct imagedata data;
    data.img =dst;

    setMouseCallback("dst",mouseHundle,&data);//鼠标处理的回调函数

    waitKey(0);//按任意键关闭当前显示的窗口,显示下一个窗口

    Mat res=findHomography(obj,data.points,CV_RANSAC);//利用RANSAC算法,3*3变换矩阵

    warpPerspective(image1,dst,res,dst.size());//透视转换

    imshow("warpPerspective",dst);

    Point pts[4];
    for(int i=0;i<4;i++)
    {
        pts[i]=data.points[i];
    }
    fillConvexPoly(image2,pts,4,Scalar(0),CV_AA);

    image2+=dst;

    imshow("final",image2);

    waitKey(0);
}

int main(int argc, char *argv[])
{
    example_2();
    return 0;
}

PS: 案例代码使用说明,需要选择四个点,且必须顺时针选择,因为代码中只设置存储4个点,超出选择无效,选择完毕后按 Enter 即可显示效果

五、总结

  • 本文核心内容包括:OpenCV透视变化概念透视变化工作原理
  • 广告屏换图文稿矫正实现为例子,讲解了OpenCV透视变化的实战案例,案例完成的效果还是挺有意思的!
  • 在我们的日常生活中,已经有很多软件用到了我们的透视变换的知识,例如,我们办公扫描文件时用的扫描软件,很大程度上,节省了我们的时间,提高了工作效率!

以上就是本文的全部内容啦!如果对您有帮助,麻烦点赞啦!收藏啦!欢迎各位评论区留言!! !

  • 62
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 56
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 56
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猿力猪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值