C++ Opencv之3D透视变换

前言:

各位小伙伴们是不是经常出现拍摄角度不佳,看着特别难受,想把图片中的某个物体翻转一下呢?

本文就以下面这本书为例,只需要鼠标按照顺时针点击书的四个脚就可以完成变换:

侧着看好难受哦,想看正面怎么办?

效果:

舒服了!!!

目录

流程讲解:

1.先读取一个需要3D透视变换的图片,并创建一个MAT类型的图片变量,用来装处理后的图片

2.创建一个向量,用来存放鼠标点击的四个坐标点在处理后的图片变量中的位置

3.由于涉及到鼠标左键点击,需要创建一个结构体

4.创建一个刚才定义的结构体,并将读取到的原图片的图片变量保存给结构体,并调用鼠标点击函数

5.把点击的位置丢给计算函数,让其使用RANSAC算法,得出计算结果

6.结果转换,并将结果显示

7.如何使用:

所有的代码:


流程讲解:

1.先读取一个需要3D透视变换的图片,并创建一个MAT类型的图片变量,用来装处理后的图片

    Mat image=imread("D:/Qt_Opencv_Project/book1.png");
    Mat result=Mat::zeros(400,500,CV_8UC1);//400*500的大小,但是里面没有东西

2.创建一个向量,用来存放鼠标点击的四个坐标点在处理后的图片变量中的位置

听着可能有点乱,但是没事,往下看就懂了,顺便show一下原图片,方便后续的鼠标操作

    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);

3.由于涉及到鼠标左键点击,需要创建一个结构体

结构体中需要有一个放原图片(方便点击产生的小点能直接显示在图片上,看起来比较直观),另一个存放鼠标点击的坐标点

struct imagedata
{
    Mat img;
    vector <Point2f> points;
};

4.创建一个刚才定义的结构体,并将读取到的原图片的图片变量保存给结构体,并调用鼠标点击函数

注意这个鼠标处理函数的参数为:

窗口名   鼠标处理的回调函数  处理结果产生数据保存给哪个变量

    struct imagedata data;
    data.img=image;
    setMouseCallback("image",mouseHundle,&data);//鼠标处理的回调函数
    waitKey(0);//按任意键关闭当前显示的窗口,显示下一个窗口

调用的回调函数:

第一个参数为鼠标点击的命令

第二、三个参数为点击的坐标

第四个参数为标记(保留,本次没有使用到)

第五个参数为传入的数据,将处理好的图片信息保存到这里,根据上面的代码,我们所传入的是一个第三点中自己创建的结构体

此回调函数的内容:

判断点击的是否为鼠标左键,如果是,则在点击位置画一个小红点,如果已经保存的小红点数目小于4个则保存小红点(为什么是4个?因为本文以书本为例,以书本的四个角来确定一本书在图片中的位置)

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,0,255),3,CV_AA);//在图上标记,圆心为点击的位置
        imshow("image",d->img);//原窗口上显示
        if(d->points.size()<4)
        {
            d->points.push_back(Point2f(x,y));//把点击的点存起来
        }
    }
}

5.把点击的位置丢给计算函数,让其使用RANSAC算法,得出计算结果

作用:将四个鼠标点击的坐标及其框的内容,转换成刚才第二点中保存的结果图片的坐标

函数参数:  四个鼠标点击的坐标  需要转换的四个坐标  RANSAC算法的宏定义

返回值:图片变量(可以理解成保存刚才那张图片处理的格式,在下一点中可以将原图以这个规则转换成结果图)

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

6.结果转换,并将结果显示

将原图按照上一点中得到的计算结果,进行转换

参数:  原图   装效果图的图片变量  图片计算结果  装效果图的图片变量的大小

    warpPerspective(image,result,res,result.size());  //结果转换
    imshow("result",result);
    waitKey(0);

7.如何使用:

导入图片以后,按照顺时针点击你想要3D变换的目标(比如本例是那本书)的四个角,然后按下任意键(别是关机键。。)结果就会跳出来啦!

所有的代码:

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

struct imagedata
{
    Mat img;
    vector <Point2f> points;
};

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,0,255),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("D:/Qt_Opencv_Project/book1.png");
    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;
}

看完别忘三连哦!您的支持是对我最大的鼓励!

博主往期的其他实用文章:

C++使用opencv调用级联分类器来识别目标物体_一个不同的ID的博客-CSDN博客前言:相较于帧差法捕捉目标物体识别,级联分类器识别目标物体更加具有针对性,使用前者只要是动的物体都会被捕捉识别到,画面里有一点风吹草动,都会被捕捉识别下来,如果我想识别具体的人或者物,都无法做到精准的目标识别,所以有了级联分类器识别(即模型识别),会按照训练好的级联分类器(模型)来进行目标识别流程讲解:1.创建一个级联分类器对象创建一个级联分类器对象,并读取已经已经训练好的模型 CascadeClassifier cascade;//级联分类器(模型) cascadehttps://blog.csdn.net/baidu_38326512/article/details/124271434?spm=1001.2014.3001.5502C++调用opencv完成运动目标捕捉_一个不同的ID的博客-CSDN博客一、原理说明:差帧识别原理:将这一帧的图像和上一帧的图像进行比对,产生变化的即为运动的目标像素块二、过程详解:1.将传入的两帧先进行灰度处理,转化将rgb类型图片转化为灰度图,可大大降低处理时间和资源消耗将转换后的图片转存至frontGray和afterGray cvtColor(frontFrame,frontGray,CV_BGR2GRAY); cvtColor(afterFrame,afterGray,CV_BGR2GRAY);2.将两帧图片进行...https://blog.csdn.net/baidu_38326512/article/details/124236389?spm=1001.2014.3001.5502

  • 40
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 57
    评论
评论 57
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一个不同的ID

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

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

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

打赏作者

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

抵扣说明:

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

余额充值