[opencv] 将摄像头图像做镜像变换(split, merge, 矩阵相乘)

来源:互联网 发布:软件功能过期怎么办 编辑:程序博客网 时间:2024/06/18 05:14

摄像头采集到的图像进行镜像变换,最简单的方法是逐点扫描然后重新赋值给一个新的矩阵。但是一张普通质量的图像也有十万级个像素点,这种方式做镜像变换,速度应该会很慢。

但是如果可以以矩阵的方式进行处理,访问图像更快,程序执行的速度也就更快。

以矩阵的方式操作原理如下:
比如有矩阵A,

A=147258369

想要将A镜像变换成B:
B=369258147

只需要在A右侧乘以一个反对角矩阵T:
T=001010100

B=AT=147258369001010100

所以,在程序中先生成一张反对角矩阵,然后在每一帧图像右乘它,就可以了。但是在代码实现时,要注意矩阵相乘要保证数据类型一致(opencv要求CV_32FC1, CV_64FC1等等),可以用Mat::convertTo()来实现。而且图像采集进来是三通道的,我们要把三个通道分别处理以后,再重新组合成一张彩色图。这就需要用到split()和merge()函数。

#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;int main(){    //生成右乘矩阵    Mat inverse(300,300,CV_32F);    for(int i=0;i<inverse.rows;i++){        for(int j=0;j<inverse.cols;j++){            if(i+j==inverse.rows-1) inverse.at<float>(i,j)=1;            else inverse.at<float>(i,j)=0;        }    }    VideoCapture capture(0);    capture.set(CAP_PROP_FRAME_WIDTH,300);    capture.set(CAP_PROP_FRAME_HEIGHT,180);    Mat frame(180,300,CV_32FC3);    Mat frameDisp(800,1440,CV_32FC3);    vector<Mat> fms;    cout<<"inverse matrix created!"<<endl;    if(!capture.isOpened())    {        cout<<"fail to open"<<endl;        return -1;    }    namedWindow("frames");    //CV_WINDOW_NORMAL CV_WINDOW_AUTOSIZE    //CV_WINDOW_FULLSCREEN    //CV_WINDOW_FREERATIO CV_WINDOW_KEEPRATIO    setWindowProperty("frames",CV_WND_PROP_FULLSCREEN,CV_WINDOW_FULLSCREEN);    //CV_WND_PROP_FULLSCREEN CV_WND_PROP_AUTOSIZE CV_WND_PROP_ASPECTRATIO    while(1){        capture>>frame;        frame.convertTo(frame,CV_32FC3,1/255.0); //转换成可以相乘的矩阵数据类型        split(frame,fms);        fms.at(0)=fms.at(0)*inverse;        fms.at(1)=fms.at(1)*inverse;        fms.at(2)=fms.at(2)*inverse;        merge(fms,frame);        resize(frame,frameDisp,frameDisp.size());        cout<<"frame channels : "<<frame.channels()<<endl;        imshow("frames",frameDisp);        if(waitKey(5)==' ') return 0;    }    return 0;}

Tips:

  • Mat::convertTo()函数使用时,把彩色图像(CV_8UC3)转换成(CV_32FC3)时应该注意,convertTo()的第三个参数应该设置转换比例,此处是1/255.0(如果是反向转换,则应是255.0)。这是因为,imshow()函数显示(CV_8UC3)类型的图像时,数据范围是0~255,但是显示(CV_32FC3)时,数据范围是0~1.0。convertTo()第三个参数如果不设置,会把0~255的(CV_8UC3)图像转换成0~255.0(CV_32FC3),这样显示出来就是一片白色。
  • 右乘的那个矩阵数据类型要选(CV_32F或者CV_32FC1)
  • split()函数第二个参数,数据类型是vector<mat>
  • 显示窗口我还没有调出全屏效果,不知什么原因,有待研究。

补充:
在opencv里面,有一个flip()函数,可以进行图像的翻转。
其描述如下:

C++: void flip(InputArray src, OutputArray dst, int flipCode)Python: cv2.flip(src, flipCode[, dst]) → dstC: void cvFlip(const CvArr* src, CvArr* dst=NULL, int flip_mode=0 )Python: cv.Flip(src, dst=None, flipMode=0) → NoneParameters:     src – input array.    dst – output array of the same size and type as src.    flipCode – a flag to specify how to flip the array; 0 means flipping around the x-axis and positive value (for example, 1) means flipping around y-axis. Negative value (for example, -1) means flipping around both axes (see the discussion below for the formulas).
0 0
原创粉丝点击