zoukankan      html  css  js  c++  java
  • Learning OpenCV Lecture 4 (Transforming Images with Morphological Operations)

    In this chapter, we will cover:
    • Eroding and dilating images using morphological filters
    • Opening and closing images using morphological filters
    • Detecting edges and corners using morphological filters
    • Segmenting images using watersheds 分水岭算法
    • Extracting foreground objects with the GrabCut algorithm
    Eroding、dilating、Opening、closing
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/highgui/highgui.hpp>
    
    int main()
    {
          // Read input image
         cv::Mat image= cv::imread("../binary.bmp" );
          if (!image.data)
                return 0;
    
        // Display the image
         cv::namedWindow( "Image");
         cv::imshow( "Image",image);
    
          // Erode the image
         cv::Mat eroded;
         cv::erode(image,eroded,cv::Mat());
    
        // Display the eroded image
         cv::namedWindow( "Eroded Image");
         cv::imshow( "Eroded Image",eroded);
    
          // Dilate the image
         cv::Mat dilated;
         cv::dilate(image,dilated,cv::Mat());
    
        // Display the dialted image
         cv::namedWindow( "Dilated Image");
         cv::imshow( "Dilated Image",dilated);
    
          // Erode the image with a larger s.e.
         cv::Mat element(7,7,CV_8U,cv::Scalar(1));
         cv::erode(image,eroded,element);
    
        // Display the eroded image
         cv::namedWindow( "Eroded Image (7x7)");
         cv::imshow( "Eroded Image (7x7)",eroded);
    
          // Erode the image 3 times.
         cv::erode(image,eroded,cv::Mat(),cv::Point(-1,-1),3);
    
        // Display the eroded image
         cv::namedWindow( "Eroded Image (3 times)");
         cv::imshow( "Eroded Image (3 times)",eroded);
    
          // Close the image
         cv::Mat element5(5,5,CV_8U,cv::Scalar(1));
         cv::Mat closed;
         cv::morphologyEx(image,closed,cv::MORPH_CLOSE,element5);
    
        // Display the opened image
         cv::namedWindow( "Closed Image");
         cv::imshow( "Closed Image",closed);
    
          // Open the image
         cv::Mat opened;
         cv::morphologyEx(image,opened,cv::MORPH_OPEN,element5);
    
        // Display the opened image
         cv::namedWindow( "Opened Image");
         cv::imshow( "Opened Image",opened);
    
          // Close and Open the image
         cv::morphologyEx(image,image,cv::MORPH_CLOSE,element5);
         cv::morphologyEx(image,image,cv::MORPH_OPEN,element5);
    
        // Display the close/opened image
         cv::namedWindow( "Closed and Opened Image");
         cv::imshow( "Closed and Opened Image",image);
         cv::imwrite( "binaryGroup.bmp",image);
    
          // Read input image
         image= cv::imread("../binary.bmp");
    
          // Open and Close the image
         cv::morphologyEx(image,image,cv::MORPH_OPEN,element5);
         cv::morphologyEx(image,image,cv::MORPH_CLOSE,element5);
    
        // Display the close/opened image
         cv::namedWindow( "Opened and Closed Image");
         cv::imshow( "Opened and Closed Image",image);
    
         cv::waitKey();
          return 0;
    }
    

      results:

    Detecting edges and corners using morphological filters
    morphoFeatures.h
    #if !defined MORPHOF
    #define MORPHOF
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    class MorphoFeatures {
    private:
          // threshold to produce binary image
          int threshold;
          // structuring elements used in corner detection
         cv::Mat cross;
         cv::Mat diamond;
         cv::Mat square;
         cv::Mat x;
    
    public:
    
         MorphoFeatures() : threshold(-1),
                     cross(5, 5, CV_8U, cv::Scalar(0)),
                     diamond(5, 5, CV_8U, cv::Scalar(0)),
                     square(5, 5, CV_8U, cv::Scalar(0)),
                     x(5, 5, CV_8U, cv::Scalar(0)) {
    
                // Creating the cross-shaped structuring element
                for (int i = 0; i < 5; i++) {
                     cross.at<uchar>(2, i) = 1;
                     cross.at<uchar>(i, 2) = 1;
                }
    
                // Creating the diamond-shaped structuring element
                diamond.at<uchar>(0, 0) = 0;
                diamond.at<uchar>(0, 1) = 0;
                diamond.at<uchar>(1, 0) = 0;
                diamond.at<uchar>(4, 4) = 0;
                diamond.at<uchar>(3, 4) = 0;
                diamond.at<uchar>(4, 3) = 0;
                diamond.at<uchar>(4, 0) = 0;
                diamond.at<uchar>(4, 1) = 0;
                diamond.at<uchar>(3, 0) = 0;
                diamond.at<uchar>(0, 4) = 0;
                diamond.at<uchar>(0, 3) = 0;
                diamond.at<uchar>(1, 4) = 0;
    
                // Creating the x-shaped structuring element
                for (int i = 0; i < 5; i++) {
                     x.at<uchar>(i, i) = 1;
                     x.at<uchar>(4 - i, i) = 1;
                }
         }
    
          void setThreshold(int t) {
                if (t > 0)
                     threshold = t;
         }
    
          int getThreshold() const {
                return threshold;
         }
    
         cv::Mat getEdges(const cv::Mat &image) {
                // Get the gradient image
                cv::Mat result;
                cv::morphologyEx(image, result, cv::MORPH_GRADIENT, cv::Mat());
    
                // Apply threshold to obtain a binary image
                applyThreshold(result);
                return result;
         }
    
          void applyThreshold(cv::Mat &result) {
                // Apply threshold on result
                if (threshold > 0) {
                     cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY_INV);
                }
         }
    
         cv::Mat getCorners(const cv::Mat &image) {
    
                cv::Mat result;
    
                // Dilate with a cross
                cv::dilate(image, result, cross);
    
                // Erode with a diamond
                cv::erode(result, result, diamond);
    
                cv::Mat result2;
                // Dilate with a x
                cv::dilate(image, result2, x);
    
                // Erode with a square
                cv::erode(result2, result2, square);
    
                // Corners are obtained by differencing
                // the two closed images
                cv::absdiff(result2, result, result);
    
                // Apply threshold to obtain a binary image
                applyThreshold(result);
    
                return result;
         }
    
          void drawOnImage(const cv::Mat &binary, cv::Mat &image) {
                cv::Mat_<uchar>::const_iterator it = binary.begin<uchar>();
                cv::Mat_<uchar>::const_iterator itend = binary.end<uchar>();
    
                // for each pixel
                for (int i = 0; it != itend; ++it, ++i) {
                     if (!*it) {
                          cv::circle(image,
                                cv::Point(i%image.step, i/image.step),
                                5, cv::Scalar(255, 0, 0));
                     }
                }
         }
    
    };
    
    #endif
    

      morph.cpp

    #include <iostream>
    
    #include "morphoFeatures.h"
    
    int main() {
    
         cv::Mat image = cv::imread( "../building.jpg");
         cv::cvtColor(image, image, CV_BGR2GRAY);
    
          // Create the morphological features instance
         MorphoFeatures morpho;
         morpho.setThreshold(40);
    
          // Get the edges
         cv::Mat edges;
         edges = morpho.getEdges(image);
    
         cv::namedWindow( "Edges Image", CV_WINDOW_AUTOSIZE);
         cv::imshow( "Edges Image", edges);
    
          // Get the corners
         cv::Mat corners;
         corners = morpho.getCorners(image);
          // Display the corner on the image
         morpho.drawOnImage(corners, image);
         cv::namedWindow( "Corners on Image", CV_WINDOW_AUTOSIZE);
         cv::imshow( "Corners on Image", image);
    
         cv::waitKey(0);
    
          return 0;
    
    }
    

      results:

    Segmenting images using watersheds
    watershedSegment.h
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    class WatershedSegmenter {
    private:
    
         cv::Mat markers;
    
    public:
    
          void setMarkers(const cv::Mat &markerImage) {
               
                // Convert to image of ints
                markerImage.convertTo(markers, CV_32S);
         }
    
         cv::Mat process(const cv::Mat &image) {
    
                // Apply watershed
                cv::watershed(image, markers);
    
                return markers;
         }
    
          // Return result in the form of an image
         cv::Mat getSegmentation() {
    
                cv::Mat tmp;
                // all segment with label higher than 255
                // will be assigned value 255
                markers.convertTo(tmp, CV_8U);
    
                return tmp;
         }
    
          // Return watershed in the form of an image
         cv::Mat getWatersheds() {
               
                cv::Mat tmp;
                // Each pixel p is transform into
                // 255p + 255 befor conversion
                markers.convertTo(tmp, CV_8U, 255, 255);
    
                return tmp;
         }
    };
    

      

    // Read input image
         cv::Mat image = cv::imread( "../group.jpg");
          if (!image.data) {
                return 0;
         }
    
          // Display the image
         cv::namedWindow( "Original Image");
         cv::imshow( "Original Image", image);
    
          // Get the binary image
         cv::Mat binary;
         binary = cv::imread( "../binary.bmp", 0);
    
          // Display the binary image
         cv::namedWindow( "Binary Image");
         cv::imshow( "Binary Image", binary);
    
          // Eliminate noise and smaller objects
         cv::Mat fg;
         cv::erode(binary, fg, cv::Mat(), cv::Point(-1, -1), 6);
    
          // Display the foreground image
         cv::namedWindow( "Foreground Image");
         cv::imshow( "Foreground Image", fg);
    

      results:

    // Identify image pixels without objects
         cv::Mat bg;
         cv::dilate(binary, bg, cv::Mat(), cv::Point(-1, -1), 6);
         cv::threshold(bg, bg, 1, 128, cv::THRESH_BINARY_INV);
    
          // Display the backgroud image
         cv::namedWindow( "Background Image");
         cv::imshow( "Background Image", bg);
    

      results:

    // Show markers image
         cv::Mat markers(binary.size(), CV_8U, cv::Scalar(0));
         markers = fg + bg;
         cv::namedWindow( "Markers");
         cv::imshow( "Markers", markers);
    

      

    // Create watershed segmentation object
         WatershedSegmenter segmenter;
    
          // Set markers and process
         segmenter.setMarkers(markers);
         segmenter.process(image);
    
          // Display segmentation result
         cv::namedWindow( "Segmentation");
         cv::imshow( "Segmentation", segmenter.getSegmentation());
    
          // Display watersheds
         cv::namedWindow( "Watershed");
         cv::imshow( "Watershed", segmenter.getWatersheds());
    

      

    // Open another image------------------------------------
         image = cv::imread( "../tower.jpg");
    
          // Identify background pixels
         cv::Mat imageMask(image.size(), CV_8U, cv::Scalar(0));
         cv::rectangle(imageMask, cv::Point(5, 5), cv::Point(image.cols - 5, image.rows - 5), cv::Scalar(255), 3);
          // Identify forground pixels (in the middle of the image)
         cv::rectangle(imageMask, cv::Point(image.cols / 2 - 10, image.rows / 2 - 10),
                                          cv::Point(image.cols / 2 + 10, image.rows / 2 + 10), cv::Scalar(1), 10);
    
          // Set markers and process
         segmenter.setMarkers(imageMask);
         segmenter.process(image);
    
          // Display the image with markers
         cv::rectangle(image, cv::Point(5, 5), cv::Point(image.cols - 5, image.rows - 5), cv::Scalar(255, 255, 255), 3);
         cv::rectangle(image, cv::Point(image.cols / 2 - 10, image.rows / 2 - 10),
                                     cv::Point(image.cols / 2 + 10, image.rows / 2 + 10), cv::Scalar(1, 1, 1), 10);
         cv::namedWindow( "Image with marker");
         cv::imshow( "Image with marker", image);
    
          // Display watersheds
         cv::namedWindow( "Watersheds of foreground object");
         cv::imshow( "Watersheds of foreground object", segmenter.getWatersheds());
    

      results:

    Extracting foreground objects with the GrabCut algorithm
    // Open another image
         image = cv::imread( "../tower.jpg");
    
          // define bounding rectange
         cv::Rect rectangle(50, 70, image.cols - 150, image.rows - 180);
    
         cv::Mat result;  // segmentation result (4 possible values)
         cv::Mat bgModel, fgModel; // the models (internally used)
          // GrabCut segmentation
         cv::grabCut(image,          // input image
                result,                     // segmentation result
                rectangle,            // rectangle containing foreground
                bgModel, fgModel,     // models
                1,                          //number of iterations
                cv::GC_INIT_WITH_RECT// use rectangle
                );
    
          // Get the pixles marked as likely foreground
         cv::compare(result, cv::GC_PR_FGD, result, cv::CMP_EQ);
          // Generate output image
         cv::Mat foreground(image.size(), CV_8UC3, cv::Scalar(255, 255, 255));
         image.copyTo(foreground, result); // bg pixels not copied
    
          // draw rectangle on original image
         cv::rectangle(image, rectangle, cv::Scalar(255,255,255),1);
         cv::namedWindow( "Image");
         cv::imshow( "Image",image);
    
          // display result
         cv::namedWindow( "Segmented Image");
         cv::imshow( "Segmented Image",foreground);
    

      

    // Open another image
         image= cv::imread("../group.jpg");
    
          // define bounding rectangle
         cv::Rect rectangle2(10,100,380,180);
    
         cv::Mat bkgModel,fgrModel; // the models (internally used)
          // GrabCut segmentation
         cv::grabCut(image,   // input image
                result, // segmentation result
               rectangle2,bkgModel,fgrModel,5,cv::GC_INIT_WITH_RECT);
          // Get the pixels marked as likely foreground
          //   cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
         result= result&1;
         foreground.create(image.size(),CV_8UC3);
         foreground.setTo(cv::Scalar(255,255,255));
         image.copyTo(foreground,result); // bg pixels not copied
    
          // draw rectangle on original image
         cv::rectangle(image, rectangle2, cv::Scalar(255,255,255),1);
         cv::namedWindow( "Image 2");
         cv::imshow( "Image 2",image);
    
          // display result
         cv::namedWindow( "Foreground objects");
         cv::imshow( "Foreground objects",foreground);
    

      

  • 相关阅读:
    父容器的flowover:hidden 必须配合父容器的宽高height width才能生效
    css使 同一行内的 文字和图片 垂直居中对齐?
    vim查找替换
    要让div中的float不会自动显示到下一行来?
    如何理解clear的css属性?
    div+css使多行文字垂直居中?
    VMnet1和V8
    unslider的用法详解
    json的中括号和大括号的使用?
    如何合理定价,定价定天下,必须要学会这个哦!
  • 原文地址:https://www.cnblogs.com/starlitnext/p/3861398.html
Copyright © 2011-2022 走看看