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

OpenCV2学习笔记(四):两种图像分割方法比较

时间:2015-02-23 01:26:26      阅读:339      评论:0      收藏:0      [点我收藏+]

标签:qt   opencv   阈值分割   c++   形态学   

此次研究两种图像分割法,分别是基于形态学的分水岭算法和基于图割理论的GrabCut算法。OpenCV均提供了两张算法或其变种。鉴于研究所需,记录一些知识点,开发平台为OpenCV2.4.9+Qt5.3.2。

一、使用分水岭算法进行图像分割

分水岭变换是一种常用的图像处理算法,在网上很容易搜到详细的原理分析。简单来说,这是一种基于拓扑理论的数学形态学的图像分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。

分水岭算法简单,因此存在一些缺陷,如容易导致图像的过度分割。OpenCV提供了该算法的改进版本,即使用预定义的一组标记来引导对图像的分割,该算法是通过cv::watershed函数来实现的。

#ifndef WATERSHEDSEGMENTATION_H
#define WATERSHEDSEGMENTATION_H
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class WaterShedSegmentation
{
public:

    void setMarkers(const cv::Mat &markerImage); // 将原图像转换为整数图像
    cv::Mat process(const cv::Mat &image); // // 分水岭算法实现
    // 以下是两种简化结果的特殊方法
    cv::Mat getSegmentation();
    cv::Mat getWatersheds();

private:
    cv::Mat markers; // 用于非零像素点的标记
};

#endif // WATERSHEDSEGMENTATION_H
#include "watershedsegmentation.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

void WaterShedSegmentation::setMarkers(const cv::Mat &markerImage) // 将原图像转换为整数图像
{
    markerImage.convertTo(markers,CV_32S);
}

cv::Mat WaterShedSegmentation::process(const cv::Mat &image)
{
  // 使用分水岭算法
  cv::watershed(image,markers);
  return markers;
}

// 以下是两种简化结果的特殊方法
// 以图像的形式返回分水岭结果
cv::Mat WaterShedSegmentation::getSegmentation()
{
  cv::Mat tmp;
  // 所有像素值高于255的标签分割均赋值为255
  markers.convertTo(tmp,CV_8U);
  return tmp;
}

cv::Mat WaterShedSegmentation::getWatersheds()
{
  cv::Mat tmp;
  markers.convertTo(tmp,CV_8U,255,255);
  return tmp;
}

main函数:

#include <QCoreApplication>
#include "watershedsegmentation.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    // Read input image
    cv::Mat image= cv::imread("c:/gray.jpg");
    if (!image.data)
        return 0;

    // Display the image9
    cv::namedWindow("Original Image");
    cv::imshow("Original Image",image);

    // Get the binary map
    cv::Mat binary;
    binary= cv::imread("c:/gray.jpg",0);

    // Display the binary image
    cv::namedWindow("Binary Image");
    cv::imshow("Binary Image",binary);

    // 移除
    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);

    // 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 background image
    cv::namedWindow("Background Image");
    cv::imshow("Background Image",bg);

    // 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
    WaterShedSegmentation 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("Watersheds");
    cv::imshow("Watersheds",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 foreground 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());

    // Open another image
    image= cv::imread("../tower.jpg");

    // define bounding rectangle
    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 pixels 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);

    return 0;

    return a.exec();
}

OpenCV2学习笔记(四):两种图像分割方法比较

标签:qt   opencv   阈值分割   c++   形态学   

原文地址:http://blog.csdn.net/liyuefeilong/article/details/43895525

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