4.OpenCV之透视转换

Q1:引用传参VS指针传参的区别?

A1:关键点:区分指针和引用的区别。

指针 引用
变量,独立,可变,可空,替身,无类型检查 别名,依赖,不变,本体,有类型检查

C/C++引用与指针的联系

一、仿射变换和透视变换详解

二、透视变换

(一)重要函数

1. findHomography函数

  计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法。
  函数功能:找到两个平面之间的变换矩阵。

Mat cv::findHomography ( InputArray srcPoints,
InputArray dstPoints,
int method = 0,
double ransacReprojThreshold = 3,
OutputArray mask = noArray(),
const int maxIters = 2000,
const double confidence = 0.995
)

4.OpenCV之透视转换_第1张图片

2. warpPerspective函数

void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
参数说明:
src – 输入图像
dst – 大小为dsize且类型与src相同的输出图像
M – 3×3变换矩阵
dsize – 输出图像的大小
  图中红点即为固定顶点,在变换先后固定顶点的像素值不变,图像整体则根据变换规则进行变换。同理,透视变换是图像基于4个固定顶点的变换,如图所示:

4.OpenCV之透视转换_第2张图片

#include 
#include 

using namespace std;
using namespace cv;

struct imgdata
{
    Mat img;
    vector<Point2f> points;//存储操作点
};

void mouseHandle(int event, int x, int y, int flag, void *ptr)
{
    struct imgdata *data = (struct imgdata *)ptr;
    //鼠标事件获取
    if(event == EVENT_LBUTTONDOWN)//按压鼠标左键
    {
        //绘制一个标记点:BGR
        circle(data->img, Point(x, y),3,Scalar(0,0,255),3,CV_AA);
        imshow("img",data->img);
        //判断是否存储足够的标记点
        if(data->points.size()<4)
            data->points.push_back(Point2f(x,y));
    }
}
void eg1()
{
    Mat img = imread("book.webp");
    imshow("img", img);

    Mat resimg = Mat::zeros(img.rows,img.cols,CV_8UC1);//8通道

    //存储透视转换后的坐标:与原坐标相反(镜像效果
    vector<Point2f> obj;
    obj.push_back(Point2f(0,0));
    obj.push_back(Point2f(img.cols/2,0));
    obj.push_back(Point2f(img.cols/2,img.rows/2));
    obj.push_back(Point2f(0,img.rows/2));
    
    struct imgdata data;
    data.img = img;

    setMouseCallback("img", mouseHandle, &data);

    waitKey(0);//等待键盘操作
    //操作四个标记点:计算变换矩阵
    Mat res = findHomography(data.points,obj,CV_RANSAC);
    imshow("res",res);

    //透视转换
    warpPerspective(img,resimg,res,resimg.size());

    imshow("resimg", resimg);
    waitKey(0);
}
int main()
{
    eg1();
    return 0;
}

(二)具体实现

  透视变换结合图像处理。将一张背景图片中的某块区域替换为另一张图片透视转换后的效果图。

1. 效果展示

2. 核心代码

#include 
#include 

using namespace std;
using namespace cv;

struct imgdata
{
    Mat img;
    vector<Point2f> points;//存储操作点
};

void mouseHandle(int event, int x, int y, int flag, void *ptr)
{
    struct imgdata *data = (struct imgdata *)ptr;
    //鼠标事件获取
    if(event == EVENT_LBUTTONDOWN)//按压鼠标左键
    {
        //绘制一个标记点:BGR
        circle(data->img, Point(x, y),3,Scalar(0,0,255),3,CV_AA);
        imshow("dst",data->img);
        //判断是否存储足够的标记点
        if(data->points.size()<4)
            data->points.push_back(Point2f(x,y));
    }
}

void eg2()
{
    Mat img1 = imread("A.png");
    imshow("img1",img1);

    Mat img2 = imread("B.png");
    imshow("img2",img2);

    vector<Point2f> obj;
    obj.push_back(Point2f(0,0));
    obj.push_back(Point2f(img1.cols,0));
    obj.push_back(Point2f(img1.cols,img1.rows));
    obj.push_back(Point2f(0,img1.rows));

    struct imgdata data;
    Mat dst = img2.clone();
    data.img = dst;
    imshow("dst",dst);

    setMouseCallback("dst", mouseHandle, &data);
    waitKey(0);//等待键盘操作

    //将需要替换的图透视变换到大图进行变换2
    Mat res = findHomography(obj, data.points, CV_RANSAC);

    //透视转换
    warpPerspective(img1, dst, res, dst.size());
    imshow("warpPerspective", dst);

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

    //进行填充(0,0,0)
    fillConvexPoly(img2, pts, 4, Scalar(0), CV_AA);
    imshow("....", img2);

    //进行或操作
    img2 += dst;
    imshow("finally", img2);

    waitKey(0);
}

int main()
{
    eg2();
    return 0;
}

你可能感兴趣的:(OpenCV,计算机视觉,opencv,计算机视觉)