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

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

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

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

A=147258369

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

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

B=AT=147258369001010100

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

#include 

#include 
using namespace std;
using namespace cv;

int main(){
    //生成右乘矩阵
    Mat inverse(300,300,CV_32F);
    for(int i=0;ifor(int j=0;jif(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 fms;

    cout<<"inverse matrix created!"<if(!capture.isOpened())
    {
        cout<<"fail to open"<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 : "<"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
  • 显示窗口我还没有调出全屏效果,不知什么原因,有待研究。

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

C++: void flip(InputArray src, OutputArray dst, int flipCode)
Python: cv2.flip(src, flipCode[, dst]) → dst
C: void cvFlip(const CvArr* src, CvArr* dst=NULL, int flip_mode=0 )
Python: cv.Flip(src, dst=None, flipMode=0) → None
Parameters: 
    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).

你可能感兴趣的:(opencv)