码迷,mamicode.com
首页 > 其他好文 > 详细

OpenCV

时间:2015-07-28 17:28:13      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:

  • 输入/输出
    • 图片
      • 从文件中读入图片:
        Mat img = imread(filename)
        ;
        如果读入的图片是
        jpg文件,默认为三通道的图像(RGB),如果你想要灰度图像,使用:

        Mat img = imread(filename, 0);
        注:图片文件的格式由文件内容(头几个字节)决定。
        ?
      • 保存图片到文件:
        imwrite(filename, img);
        注:文件格式由扩展名决定。
        注:如果要从内存中读取
        /存储图像使用imdecodeimencode
        ?
  • 图像的基本操作
    ?
    • 图像像素值的获取
      • 想要获取图像的像素强度值,首先要知道图像的类型和通道数。下面是获取单通道灰度图像(8UC1)在坐标xy(坐标原点一般在图像左上角的点,处理前最好确定一下)处的像素强度值:

        Scalar intensity = img.at<uchar>(y, x);

        intensity.val[0]的取值范围为0255。注意到xy的顺序。OpenCV中图像的存储结构类似于矩阵,两者的惯例一样——行系数(或者y轴)在前,列系数(或x轴)在后。你也可以使用下面的表达形式,实现效果一样的:
        Scalar intensity = img.at<uchar>(Point(x, y));
        ?
      • 现在看三通道的彩色图像,通道顺序为BGRimread默认返回顺序):

        Vec3b intensity = img.at<Vec3b>(y, x);

        uchar blue = intensity.val[0];

        uchar green = intensity.val[1];

        uchar red = intensity.val[2];
        ?

      • 类似的,浮点型图像像素值获取方法:(浮点型图像可由Sobel算子对三通道的图像处理得到)

        Vec3f intensity = img.at<Vec3f>(y, x);

        float blue = intensity.val[0];

        float green = intensity.val[1];

        float red = intensity.val[2];
        ?

      • 此方法也可用改变像素的值:

        img.at<uchar>(y, x) = 128;
        ?
      • 有一些函数,特别是在calib3d module中,例如projectPoints,输入是Mat类型的2D3D点的数组。矩阵只有一列,每一行对应一个点,矩阵数据类型是32FC232FC3,这样的矩阵可以很容易用std::vector构建:

        vector<Point2f> points;

        //... fill the array

        Mat pointsMat = Mat(points);
        ?

        想取得这个矩阵里的点可以使用Mat:: at
        ?

        Point2f point = pointsMat.at<Point2f>(i, 0);
        ?

    • 内存管理和引用计数
      • Mat可解理解为一个结构体,里面保存了矩阵/图像的特征(例如:行列数,数据类型等等)和数据。多个Mat实例可以对应同一个数据。每一个Mat对象都有一个引用计数,当一个实例被释放时,引用计数告诉我们数据是否要被清除。下面的例子创建两个矩阵,实际上共享同样的数据:

        std::vector<Point3f> points;

        // .. fill the array

        Mat pointsMat = Mat(points).reshape(1);

        执行上面的语句,我们就可以将一列的
        32FC3矩阵转换成三列的32FC3矩阵。pointsMat使用的数据就是points的数据,也就是说当清除pointsMat时,数据并没有被清除。在这个例子中,使用者需要确保points的生命周期比pointsMat长。如果我们要复制数据,可以使用Mat::copyTo or Mat::clone:

        Mat img = imread("image.jpg");

        Mat img1 = img.clone();
        ?

      • C语言中,输出图像由开发者创建,在C++中,一个空的Mat类型输出对象对可被任何函数使用。每一次执行输出都要调用Mat::create。如果这个类是空的,就分配内存,如果不为空,且大小和类型和我们调用输入的参数相同,那就什么也不做,否则重新分配输出,原来的数据就丢失了,例如:
        ?

        Mat img = imread("image.jpg");

        Mat sobelx;

        Sobel(img, sobelx, CV_32F, 1, 0);
        ?

        注:reference count(引用计数):每个对象都有一个引用计数用来表明有多少其它对象正在保留一个对它的引用,对象A想要引用对象BA就把B的引用计数加一,当A结束了对B的引用,A就把B的引用计数减一,当没有对象再引用B时,B的引用计数就为0B就被清除(deallocate)。
        ?

    • 基本操作
      ?

      有一些定义在矩阵层面上的操作。

      • 从已存在的灰度图得到一张黑色的图象:
        ?

      img = Scalar(0);

      ? ?

      Selecting a region of interest:

      Rect r(10, 10, 100, 100);

      Mat smallImg = img(r);

      ? ?

      • Mat对象转换为C接口的数据结构:

      ? ?

      Mat img = imread("image.jpg");

      IplImage img1 = img;

      CvMat m = img;

      ? ?

      注意:上面的语句并没有复制数据。

      ? ?

      • 把彩色图转换为灰度图:

      ? ?

      Mat img = imread("image.jpg"); // loading a 8UC3 image

      Mat grey;

      cvtColor(img, grey, CV_BGR2GRAY);

      ? ?

      把图像类型从8UC1 8比特无符号单通道类型)转换到32FC132比特浮点单通道类型):

      ? ?

      src.convertTo(dst, CV_32F);

    • 显示图像
      ?

      在开发过程中,显示你的算法的中间结果也是很实用的技巧。OpenCV提供了一个很方便的方法。一个8U类型的图像显示方法:
      ?

      Mat img = imread("image.jpg");

      namedWindow("image", CV_WINDOW_AUTOSIZE);

      imshow("image", img);

      waitKey();

      ? ?

      调用waitKey()程序会等待用户的键盘输入(在image窗口)。32F类型型的图像显示要转换成8U类型的。下面是一个例子:
      ?

      Mat img = imread("image.jpg");

      Mat grey;

      cvtColor(img, grey, CV_BGR2GRAY);

      Mat sobelx;

      Sobel(grey, sobelx, CV_32F, 1, 0);

      double minVal, maxVal;

      minMaxLoc(sobelx, &minVal, &maxVal); //find minimum and maximum intensities

      Mat draw;

      sobelx.convertTo(draw, CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal));

      namedWindow("image", CV_WINDOW_AUTOSIZE);

      imshow("image", draw);

      waitKey();

      ? ?

  • 二维特征点(Features2D)
    ?
    • 特征点的检测
      ?
    • 特征点描述(描述符)
      ?
    • 特征点的匹配
      ?
      • 代码

        这个小例子原文件在opencv/samples/cpp/matcher_simple.cpp(装了
        OpenCV之后)
        ?

        Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);

        Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);

        if(img1.empty() || img2.empty())

        {

        printf("Can‘t read one of the images\n");

        return -1;

        }
        ?

        // detecting keypoints

        SurfFeatureDetector detector(400);

        vector<KeyPoint> keypoints1, keypoints2;

        detector.detect(img1, keypoints1);

        detector.detect(img2, keypoints2);
        ?

        // computing descriptors

        SurfDescriptorExtractor extractor;

        Mat descriptors1, descriptors2;

        extractor.compute(img1, keypoints1, descriptors1);

        extractor.compute(img2, keypoints2, descriptors2);
        ?

        // matching descriptors

        BruteForceMatcher<L2<float> > matcher;

        vector<DMatch> matches;

        matcher.match(descriptors1, descriptors2, matches);
        ?

        // drawing the results

        namedWindow("matches", 1);

        Mat img_matches;

        drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches);

        imshow("matches", img_matches);

        waitKey(0);

        ? ?

      • 代码解释
        ?
        • 代码一段一段地看
          ?

          Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);

          Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);

          if(img1.empty() || img2.empty())

          {

          printf("Can‘t read one of the images\n");

          return -1;

          }

          载入两幅图像,并且检查是否成功载入。
          ?

          // detecting keypoints

          FastFeatureDetector detector(15);

          vector<KeyPoint> keypoints1, keypoints2;

          detector.detect(img1, keypoints1);

          detector.detect(img2, keypoints2);

          首先创建一个特征点检测的对象。对象继承了FeatureDetector类的抽象接口,但结构还是取决于算法。detector对象的第一个参数用于平衡检测到的特征点的数量和质量(稳定性)。不同的检测方法这个参数的取值也不同(例如:
          FAST算子的阈值有像素强度差值的意义,取值通常在040SURF算子的阈值应用在卷积图像的Hessian矩阵上,取值通常大于100),这里我们取的默认值。
          ?

          // computing descriptors

          SurfDescriptorExtractor extractor;

          Mat descriptors1, descriptors2;

          extractor.compute(img1, keypoints1, descriptors1);

          extractor.compute(img2, keypoints2, descriptors2);

          ? ?

          创建一个描述符提取(descriptor extractor)对象。OpenCV中大多数描述符(descriptors)继承了DescriptorExtractor的抽象接口。然后为每一个特征点计算描述符(descriptors)。DescriptorExtractor::compute方法输出为Mat,每一行是一个特征点的描述符,第i行描述符对应一第i个特征点。这里要注意的是这个方法会修改
          存储keypoints的vector对象(keypoints vector),他会删除一些特征点,自然这些特征点的描述符就不会被创建(通常被删除的点都是图像边缘的点)。这样就可以确保输出的特征点和描述符一一对应(特征点的数量和秘书符的数量是相等的)。
          ?

          // matching descriptors

          BruteForceMatcher<L2<float> > matcher;

          vector<DMatch> matches;

          matcher.match(descriptors1, descriptors2, matches);

          现在我们有了两幅图像的描述符,就可以对他们执行匹配。先创建一个matcher对象,对image 2的每个描述子用欧几里德向量穷举搜索image 1中与它最近的描述子。

          曼哈坦距离(Manhattan distance)和汉明距离(Hamming distance)同时使用以获得简要结果。输出的matches包含一对对的索引,每对索引就是匹配好的描述符。
          ?

          // drawing the results

          namedWindow("matches", 1);

          Mat img_matches;

          drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches);

          imshow("matches", img_matches);

          waitKey(0);

          最后的部分就是将处理结果显示出来。

OpenCV

标签:

原文地址:http://www.cnblogs.com/programnote/p/4682882.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!