zoukankan      html  css  js  c++  java
  • 一些常用的opencv函数

    分配图像空间:

    IplImage* cvCreateImage(CvSize size, int depth, int channels);
          size:  cvSize(width,height);
          depth: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
                 IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F,IPL_DEPTH_64F
          channels: 1, 2, 3 or 4.

          注意数据为交叉存取.彩色图像的数据编排为b0 g0 r0 b1 g1 r1 ...

    举例:

    // 分配一个单通道字节图像
    IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    // 分配一个三通道浮点图像
    IplImage* img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);

    释放图像空间:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    cvReleaseImage(&img); 

    复制图像:

    IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    IplImage* img2;
    img2=cvCloneImage(img1);

    设定/获取兴趣区域:

    void  cvSetImageROI(IplImage* image, CvRect rect);
    void  cvResetImageROI(IplImage* image);
    vRect cvGetImageROI(const IplImage* image);
    大部分OpenCV函数都支持ROI. 

    设定/获取兴趣通道:

    void cvSetImageCOI(IplImage* image, int coi); // 0=all
    int  cvGetImageCOI(const IplImage* image);
    大部分OpenCV函数暂不支持COI.

    读取存储图像

    从文件中载入图像:

    IplImage* img=0;
    img=cvLoadImage(fileName);
    if(!img) printf("Could not load image file: %s ",fileName);

    Supported image formats: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,SR, RAS, TIFF, TIF

    载入图像默认转为3通道彩色图像. 如果不是,则需加flag:

    img=cvLoadImage(fileName,flag);

    flag: >0 载入图像转为三通道彩色图像
          =0 载入图像转为单通道灰度图像
          <0 不转换载入图像(通道数与图像文件相同). 

    图像存储为图像文件:

    if(!cvSaveImage(outFileName,img)) printf("Could not save: %s ",outFileName);

    输入文件格式由文件扩展名决定.

    存取图像元素

    假设需要读取在i行j列像点的第k通道. 其中, 行数i的范围为[0, height-1], 列数j的范围为[0, width-1], 通道k的范围为[0, nchannels-1].

    间接存取: (比较通用, 但效率低, 可读取任一类型图像数据)

    对单通道字节图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    CvScalar s;
    s=cvGet2D(img,i,j); // get the (i,j) pixel value
    printf("intensity=%f ",s.val[0]);
    s.val[0]=111;
    cvSet2D(img,i,j,s); // set the (i,j) pixel value

    对多通道浮点或字节图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
    CvScalar s;
    s=cvGet2D(img,i,j); // get the (i,j) pixel value
    printf("B=%f, G=%f, R=%f ",s.val[0],s.val[1],s.val[2]);
    s.val[0]=111;
    s.val[1]=111;
    s.val[2]=111;
    cvSet2D(img,i,j,s); // set the (i,j) pixel value

    直接存取: (效率高, 但容易出错)

    对单通道字节图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    ((uchar *)(img->imageData + i*img->widthStep))[j]=111;

    对多通道字节图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
    ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
    ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
    ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R 

    对多通道浮点图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
    ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
    ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
    ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R

    用指针直接存取 : (在某些情况下简单高效)

    对单通道字节图像:

    IplImage* img      = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    int height         = img->height;
    int width          = img->width;
    int step           = img->widthStep/sizeof(uchar);
    uchar* data        = (uchar *)img->imageData;
    data[i*step+j] = 111;

    对多通道字节图像:

    IplImage* img      = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
    int height         = img->height;
    int width          = img->width;
    int step           = img->widthStep/sizeof(uchar);
    int channels       = img->nChannels;
    uchar* data        = (uchar *)img->imageData;
    data[i*step+j*channels+k] = 111;

    对单通道浮点图像(假设用4字节调整):

    IplImage* img      = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
    int height         = img->height;
    int width          = img->width;
    int step           = img->widthStep/sizeof(float);
    int channels       = img->nChannels;
    float * data        = (float *)img->imageData;
    data[i*step+j*channels+k] = 111;

    使用 c++ wrapper 进行直接存取: (简单高效)

    对单/多通道字节图像,多通道浮点图像定义一个 c++ wrapper:

    template<class T> class Image
    {
          private:
          IplImage* imgp;
          public:
          Image(IplImage* img=0) {imgp=img;}
          ~Image(){imgp=0;}
          void operator=(IplImage* img) {imgp=img;}
          inline T* operator[](const int rowIndx) {
            return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
    };
    typedef struct

    {
      unsigned char b,g,r;
    } RgbPixel;
    typedef struct

    {
      float b,g,r;
    } RgbPixelFloat;
    typedef Image<RgbPixel>           RgbImage;
    typedef Image<RgbPixelFloat>      RgbImageFloat;
    typedef Image<unsigned char>      BwImage;
    typedef Image<float>              BwImageFloat;

    单通道字节图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
    BwImage imgA(img);
    imgA[i][j] = 111;

    多通道字节图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
    RgbImage      imgA(img);
    imgA[i][j].b = 111;
    imgA[i][j].g = 111;
    imgA[i][j].r = 111;

    多通道浮点图像:

    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
    RgbImageFloat imgA(img);
    imgA[i][j].b = 111;
    imgA[i][j].g = 111;
    imgA[i][j].r = 111;

    图像转换

    转为灰度或彩色字节图像:

    cvConvertImage(src, dst, flags=0);
          src = float/byte grayscale/color image
          dst = byte grayscale/color image
          flags = CV_CVTIMG_FLIP         (flip vertically)
                  CV_CVTIMG_SWAP_RB      (swap the R and B channels)

    转换彩色图像为灰度图像:

    使用OpenCV转换函数:

    cvCvtColor(cimg,gimg,CV_BGR2GRAY); // cimg -> gimg

    直接转换:

    for(i=0;i<cimg->height;i++) for(j=0;j<cimg->width;j++)
          gimgA[i][j]= (uchar)(cimgA[i][j].b*0.114 +
                               cimgA[i][j].g*0.587 +
                               cimgA[i][j].r*0.299);

    颜色空间转换:  

    cvCvtColor(src,dst,code); // src -> dst
          code        = CV_<X>2<Y>
          <X>/<Y> = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS
    e.g.: CV_BGR2GRAY, CV_BGR2HSV, CV_BGR2Lab

    绘图命令

    画长方体:

    // 用宽度为1的红线在(100,100)与(200,200)之间画一长方体
    cvRectangle(img, cvPoint(100,100), cvPoint(200,200), cvScalar(255,0,0), 1);

    画圆:

    // 在(100,100)处画一半径为20的圆,使用宽度为1的绿线
    cvCircle(img, cvPoint(100,100), 20, cvScalar(0,255,0), 1);

    画线段:

    // 在(100,100)与(200,200)之间画绿色线段,宽度为1
    cvLine(img, cvPoint(100,100), cvPoint(200,200), cvScalar(0,255,0), 1);

    画一组线段:

    CvPoint      curve1[]={10,10,      10,100,      100,100,      100,10};
    CvPoint      curve2[]={30,30,      30,130,      130,130,      130,30,      150,10};
    CvPoint* curveArr[2]={curve1, curve2};
    int          nCurvePts[2]={4,5};
    int          nCurves=2;
    int          isCurveClosed=1;
    int          lineWidth=1;
    cvPolyLine(img,curveArr,nCurvePts,nCurves,isCurveClosed,cvScalar(0,255,255),lineWidth);

    画内填充色的多边形:

    cvFillPoly(img,curveArr,nCurvePts,nCurves,cvScalar(0,255,255));

    添加文本:

    CvFont font;
    double hScale=1.0;
    double vScale=1.0;
    int        lineWidth=1;
    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);
    cvPutText (img,"My comment",cvPoint(200,400), &font, cvScalar(255,255,0));

    Other possible fonts:

    CV_FONT_HERSHEY_SIMPLEX, CV_FONT_HERSHEY_PLAIN,
    CV_FONT_HERSHEY_DUPLEX, CV_FONT_HERSHEY_COMPLEX,
    CV_FONT_HERSHEY_TRIPLEX, CV_FONT_HERSHEY_COMPLEX_SMALL,
    CV_FONT_HERSHEY_SCRIPT_SIMPLEX, CV_FONT_HERSHEY_SCRIPT_COMPLEX,

    综述:
    OpenCV有针对矩阵操作的C语言函数. 许多其他方法提供了更加方便的C++接口,其效率与OpenCV一样.

    OpenCV将向量作为1维矩阵处理.

    矩阵按行存储,每行有4字节的校整.

    分配矩阵空间:

    CvMat* cvCreateMat(int rows, int cols, int type);
         type: 矩阵元素类型. 格式为CV_<bit_depth>(S|U|F)C<number_of_channels>.  
    例如: CV_8UC1 表示8位无符号单通道矩阵, CV_32SC2表示32位有符号双通道矩阵.

         例程:
         CvMat* M = cvCreateMat(4,4,CV_32FC1);

    释放矩阵空间:

    CvMat* M = cvCreateMat(4,4,CV_32FC1);
    cvReleaseMat(&M);

    复制矩阵:

    CvMat* M1 = cvCreateMat(4,4,CV_32FC1);
    CvMat* M2;
    M2=cvCloneMat(M1);

    初始化矩阵:

    double a[] = { 1,     2,     3,     4,
                      5,     6,     7,     8,
                      9, 10, 11, 12 };
    CvMat Ma=cvMat(3, 4, CV_64FC1, a);

    另一种方法:

    CvMat Ma;
    cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a);

    初始化矩阵为单位阵:

    CvMat* M = cvCreateMat(4,4,CV_32FC1);
    cvSetIdentity(M); // 这里似乎有问题,不成功

    存取矩阵元素

    假设需要存取一个2维浮点矩阵的第(i,j)个元素.

    间接存取矩阵元素:

    cvmSet(M,i,j,2.0); // Set M(i,j)
    t = cvmGet(M,i,j); // Get M(i,j)

    直接存取,假设使用4-字节校正:

    CvMat* M       = cvCreateMat(4,4,CV_32FC1);
    int n          = M->cols;
    float *data = M->data.fl;
    data[i*n+j] = 3.0;

    直接存取,校正字节任意:

    CvMat* M       = cvCreateMat(4,4,CV_32FC1);
    int      step     = M->step/sizeof(float);
    float *data = M->data.fl;
    (data+i*step)[j] = 3.0;

    直接存取一个初始化的矩阵元素:

    double a[16];
    CvMat Ma = cvMat(3, 4, CV_64FC1, a);
    a[i*4+j] = 2.0; // Ma(i,j)=2.0;

    矩阵/向量操作

    矩阵-矩阵操作:

    CvMat *Ma, *Mb, *Mc;
    cvAdd(Ma, Mb, Mc);         // Ma+Mb      -> Mc
    cvSub(Ma, Mb, Mc);         // Ma-Mb      -> Mc
    cvMatMul(Ma, Mb, Mc);      // Ma*Mb      -> Mc

    按元素的矩阵操作:

    CvMat *Ma, *Mb, *Mc;
    cvMul(Ma, Mb, Mc);         // Ma.*Mb     -> Mc
    cvDiv(Ma, Mb, Mc);         // Ma./Mb     -> Mc
    cvAddS(Ma, cvScalar(-10.0), Mc); // Ma.-10 -> Mc

    向量乘积:

    double va[] = {1, 2, 3};
    double vb[] = {0, 0, 1};
    double vc[3];
    CvMat Va=cvMat(3, 1, CV_64FC1, va);
    CvMat Vb=cvMat(3, 1, CV_64FC1, vb);
    CvMat Vc=cvMat(3, 1, CV_64FC1, vc);
    double res=cvDotProduct(&Va,&Vb); // 点乘:      Va . Vb -> res
    cvCrossProduct(&Va, &Vb, &Vc);       // 向量积: Va x Vb -> Vc
    end{verbatim}

    注意 Va, Vb, Vc 在向量积中向量元素个数须相同.

    单矩阵操作:

    CvMat *Ma, *Mb;
    cvTranspose(Ma, Mb);         // transpose(Ma) -> Mb (不能对自身进行转置)
    CvScalar t = cvTrace(Ma); // trace(Ma) -> t.val[0]
    double d = cvDet(Ma);        // det(Ma) -> d
    cvInvert(Ma, Mb);            // inv(Ma) -> Mb

    非齐次线性系统求解:

    CvMat* A     = cvCreateMat(3,3,CV_32FC1);
    CvMat* x     = cvCreateMat(3,1,CV_32FC1);
    CvMat* b     = cvCreateMat(3,1,CV_32FC1);
    cvSolve(&A, &b, &x);       // solve (Ax=b) for x

    特征值分析(针对对称矩阵):

    CvMat* A     = cvCreateMat(3,3,CV_32FC1);
    CvMat* E     = cvCreateMat(3,3,CV_32FC1);
    CvMat* l     = cvCreateMat(3,1,CV_32FC1);
    cvEigenVV(&A, &E, &l);     // l = A的特征值 (降序排列)
                               // E = 对应的特征向量 (每行)

    奇异值分解SVD:

    CvMat* A     = cvCreateMat(3,3,CV_32FC1);
    CvMat* U     = cvCreateMat(3,3,CV_32FC1);
    CvMat* D     = cvCreateMat(3,3,CV_32FC1);
    CvMat* V     = cvCreateMat(3,3,CV_32FC1);
    cvSVD(A, D, U, V, CV_SVD_U_T|CV_SVD_V_T); // A = U D V^T

    标号使得 U 和 V 返回时被转置(若没有转置标号,则有问题不成功!!!).

    视频序列操作

    从视频序列中抓取一帧

    OpenCV支持从摄像头或视频文件(AVI)中抓取图像.

    从摄像头获取初始化:

    CvCapture* capture = cvCaptureFromCAM(0); // capture from video device #0

    从视频文件获取初始化:

    CvCapture* capture = cvCaptureFromAVI("infile.avi");

    抓取帧:

    IplImage* img = 0;
    if(!cvGrabFrame(capture)){                 // 抓取一帧
         printf("Could not grab a frame 7");
         exit(0);
    }
    img=cvRetrieveFrame(capture);              // 恢复获取的帧图像

    要从多个摄像头同时获取图像, 首先从每个摄像头抓取一帧. 在抓取动作都结束后再恢复帧图像.  

    释放抓取源:

    cvReleaseCapture(&capture);

    注意由设备抓取的图像是由capture函数自动分配和释放的. 不要试图自己释放它.

    获取/设定帧信息

    获取设备特性:

    cvQueryFrame(capture); // this call is necessary to get correct
                              // capture properties
    int frameH       = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
    int frameW       = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
    int fps          = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
    int numFrames = (int) cvGetCaptureProperty(capture,     CV_CAP_PROP_FRAME_COUNT);

    所有帧数似乎只与视频文件有关. 用摄像头时不对,奇怪!!!.

    获取帧信息:

    float posMsec      =          cvGetCaptureProperty(capture, CV_CAP_PROP_POS_MSEC);
    int posFrames      = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES);
    float posRatio     =          cvGetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO);

    获取所抓取帧在视频序列中的位置, 从首帧开始按[毫秒]算. 或者从首帧开始从0标号, 获取所抓取帧的标号. 或者取相对位置,首帧为0,末帧为1, 只对视频文件有效.

    设定所抓取的第一帧标号:

    // 从视频文件相对位置0.9处开始抓取
    cvSetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO, (double)0.9);

    只对从视频文件抓取有效. 不过似乎也不成功!!!

    存储视频文件

    初始化视频存储器:

    CvVideoWriter *writer = 0;
    int isColor = 1;
    int fps        = 25;     // or 30
    int frameW     = 640; // 744 for firewire cameras
    int frameH     = 480; // 480 for firewire cameras
    writer=cvCreateVideoWriter("out.avi",CV_FOURCC('P','I','M','1'),
                                  fps,cvSize(frameW,frameH),isColor);

    其他有效编码:

    CV_FOURCC('P','I','M','1')       = MPEG-1 codec
    CV_FOURCC('M','J','P','G')       = motion-jpeg codec (does not work well)
    CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec
    CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec
    CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec
    CV_FOURCC('U', '2', '6', '3') = H263 codec
    CV_FOURCC('I', '2', '6', '3') = H263I codec
    CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec

    若把视频编码设为-1则将打开一个编码选择窗口(windows系统下).

    存储视频文件:

    IplImage* img = 0;
    int nFrames = 50;
    for(i=0;i<nFrames;i++){
         cvGrabFrame(capture);             // 抓取帧
         img=cvRetrieveFrame(capture);     // 恢复图像
         cvWriteFrame(writer,img);         // 将帧添加入视频文件
    }

    若想在抓取中查看抓取图像, 可在循环中加入下列代码:

    cvShowImage("mainWin", img);
    key=cvWaitKey(20);              // wait 20 ms

    若没有20[毫秒]延迟,将无法正确显示视频序列.

    释放视频存储器:

    cvReleaseVideoWriter(&writer);

  • 相关阅读:
    GNU make manual 翻译(九十九)
    GNU make manual 翻译( 九十五)
    Shell的 for 循环小例子
    makefile中对目录遍历的小例子
    GNU make manual 翻译(九十三)
    GNU make manual 翻译( 一百)
    GNU make manual 翻译( 九十七)
    GNU make manual 翻译( 九十八)
    mapserver4.8.3 的readme.win32的中文翻译文件
    遥控器编程
  • 原文地址:https://www.cnblogs.com/feifanrensheng/p/7895380.html
Copyright © 2011-2022 走看看