【学习笔记】OpenCV+C++(二)

Mat对象
    Mat对象与IplImage对象
        Mat对象OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构,分了两部分,头部和数据部分。
        IplImage是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序使用它容易导致内存泄漏问题。

//Mat对象构造函数与常用方法
//           Mat()
//          Mat(int rows,int cols,int type)
//          Mat(Size size,int type)
//          Mat(int rows,int cols,int type,const Scalar &s)
//          Mat(Size size,int type,const Scalar &s)
//          Mat(int ndims,const int *sizes,int type)
//          Mat(int ndims,const int *sizes,int type,const Scalar &s)
//
//           常用方法:
//              void copyTo(Mat mat)
//              void convertTo(Mat dst,int type)
//              Mat clone()
//              int channels()
//              int depth()
//              bool empty()
//              uchar* ptr(i=0)

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;
int main(int argc,char** argv){
    Mat src;
    src = imread("");
    if(src.empty()){
        cout<<"could not load image..."<<endl;
        return -1;
    }
    namedWindow("input",CV_WINDOW_AUTOSIZE);
    imshow("input",src);
    /*
    Mat dst;
    dst = Mat(src.size(),src.type());
    dst = Scalar(127,0,255);//给图像赋值
    namedWindow("output",CV_WINDOW_AUTOSIZE);
    imshow("output",dst);
    */
    Mat dst = src.clone();//克隆
    src.copyTo(dst);//复制
    cvtColor(src,dst,CV_GRAY2GRAY);
    src.channels();//多少通道,函数返回是一个值
    const uchar* firstRow = dst.ptr<uchar>(0);
    cout<<"first pixel value:"<<*firstRow<<endl;

    int cols = dst.cols;
    int rows = dst.rows;
    namedWindow("output",CV_WINDOW_AUTOSIZE);
    imshow("output",dst);

    //Mat(int rows,int cols,int type,const Scalar &s)的用法
    Mat M(3,3,CV_8UC3,Scalar(0,0,255));
    //cout<<"M="<<endl<<M<<endl;//注释掉,不然很费性能
    imshow("output",M);
    waitKey(0);
    return 0;
}

   Mat对象使用
        部分复制:一般情况下只会复制Mat对象的头和指针部分,不会复制数据部分
                Mat A = imread(imgFilePath);
                Mat B(A);//只复制
        完全复制:如果想把Mat对象的头和数据部分一起复制,可以通过如下两个API实现
                Mat F = A.clone();或Mat G; A.copyTo(G);
        四个要点:
            输出图像的内存是自动分配的
            使用OpenCV的C++接口,不需要考虑内存分配问题
            复制操作和拷贝构造函数只会复制头部分
            使用clone与copyTo两个函数实现数据完全复制
    Mat对象创建:
        cv::Mat::Mat构造函数
        Mat M(2,2,CV_8UC3,Scalar(0,0,255));
        其中前两个参数分别表示行(row)跟列(column)、第三个参数CV_8UC3中的8表示每个通道占8位,UC表示unchar无符号的char类型,3表示3个通道。第四个参数是向量表示初始化每个像素值是多少,向量长度对应通道数目一致
        创建多维数组cv::Mat::create
        int sz[3] = {2,2,2};
        Mat L(3,sz,CV_8UC1,Scalar::all(0));
        代码:
            Mat m1;
            m1.create(src.size(),src.type());
            m1=Scalar(0,0,255);
            Mat M;
            M.create(4,3,CV_8UC2);
            M = Scalar(127,127);
            cout<<"M="<<endl<<" "<<M<<endl<<endl;
            uchar* firstRow = M.ptr<uchar>(0);
            printf("%d",*firstRow);
    Mat定义数组
        Mat C = (Mat_<float>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
        filter2D(src,dst,src.depth(),kernel);

    小技巧:输出成纯黑色的图片
    Mat m2 = Mat::zeros(src.size(),src.type());
    调整大小
    Mat m = Mat::zeros(2,2,CV_8UC1);
    输出对角线为1的对称矩阵
    Mat m1 = Mat::eye(2,2,CV_8UC1)

      图像操作
         读写图像
             imread可以指定加载为灰度或者RGB图像
             imwrite保存图像文件,类型由扩展名决定
         读写像素
            读一个GRAY像素点的像素值(CV_8UC1)
            Scalar intensity = img.at<uchar>(y,x)   或者    Scalar intensity = img.at<uchar>(Point(x,y))

            读一个RGB像素点的像素值
            Vec3f intensity = img.at<Vec3f>(y,x);
            float blue = intensity.val[0];
            float green = intensity.val[1];
            float red = intensity.val[2];

namedWindow("input",CV_WINDOW_AUTOSIZE);
        imshow("input",src);
        //单通道
        cvtColor(src,gray_src,CV_BGR2GRAY);
        namedWindow("output",CV_WINDOW_AUTOSIZE);
        imshow("output",gray_src);
        int height = gray_src.rows;
        int width = gray_src.cols;
        for(int row = 0; row < height; row++){
            for(int col = 0; col < width; col++){
                int gray = gray_src.at<uchar>(row,col);
                gray_src.at<uchar>(row,col) = 255 - gray;//反插
            }
        }
        //三通道
        Mat dst;
        dst.create(src.size(),src.type());
        height = src.rows;
        width = src.cols;
        int nc = src.channels();//获取通道数
        for(int row = 0; row < height; row++){
            for(int col = 0; col < width; col++){
                if(nc == 1){
                    int gray = gray_src.at<uchar>(row,col);
                    gray_src.at<uchar>(row,col) = 255 - gray;//反插
                }else if(nc == 3){
                    int b = dst.at<Vec3b>(row,col)[0];
                    int g = dst.at<Vec3b>(row,col)[1];
                    int r = dst.at<Vec3b>(row,col)[2];
                    dst.at<Vec3b>(row,col)[0] = 255 - b;
                    dst.at<Vec3b>(row,col)[1] = 255 - g;
                    dst.at<Vec3b>(row,col)[2] = 255 - r;

                    gray_src.at<uchar>(row,col) = max(r,max(b,g));//将gray_src的灰度取值最大
                    gray_src.at<uchar>(row,col) = min(r,min(b,g));//将gray_src的灰度取值最小
                }
            }
        }

        注意:
             Vec3b  byte类型
             Vec3f  float类型
        Vec3b与Vec3f
             Vec3b对应三通道顺序是blue,green,red的uchar类型数据
             Vec3f对应三通道的float类型数据
             把CV_8UC1转换到CV32F1实现如下:
                  src.convertTo(dst,CV_32F);
        //获取像素,反插函数
        bitwise_not(src.dst);
        修改像素值  

 图像混合
    理论-线性混合操作
        g(x)=(1-a)f0(x)+af1(x)   其中a的取值范围0~1之间
    相关API(addWeighted)
      void cv::addWeighted(InputArray src1,  参数1:输入图像Mat-src1
                           double alpha,     参数2:输入图像src1的alpha值
                           InputArray src2,  参数3:输入图像Mat-src2
                           double beta,      参数4:输入图像src2的alpha值
                           double gamma,     参数5:gamma值
                           OutputArray dst,  参数6:输出混合图像
                           int dtype=-1)

        dst(I) = saturate(src1(I)*alpha + src2(I)*beta + gamma)
            注意:两张图像的大小和类型必须一致才可以

    #include<opencv2/opencv.hpp>
    #include<iostream>
    using namespace std;
    using namespace cv;
    int main(int argc,char** argv){
        Mat src1,src2,dst;
        double alpha = 0.5;
        src1 = imread("");
        src2 = imread("");
        if(!src1.data){
            cout<<"could not load image..."<<endl;
            return -1;
        }
        if(!src2.data){
            cout<<"could not load image..."<<endl;
            return -1;
        }
        if(src1.rows==src2.rows && src1.cols==src2.cols && src1.type() == src2.type()){
            addWeighted(src1,alpha,src2,(1.0-alpha),0,0,dst);
            //直接相加
            //add(src1,src2,dst,Mat());
            //相乘
            //multiply(src1,src2,dst,1.0)
            namedWindow("src1",CV_WINDOW_AUTOSIZE);
            imshow("src1",src1);
            namedWindow("src2",CV_WINDOW_AUTOSIZE);
            imshow("src2",src2)
            namedWindow("blend demo",CV_WINDOW_AUTOSIZE);
            imshow("blend demo",dst);
        }else{
            printf("could not blend images, the size is not same...\n");
            return -1;
        }
        waitKey(0);
        return 0;
    }  
扫描二维码关注公众号,回复: 8998691 查看本文章
发布了10 篇原创文章 · 获赞 1 · 访问量 252

猜你喜欢

转载自blog.csdn.net/Qsouler/article/details/104216109