上一篇文章中介绍了GrabCut的交互性分割,在这篇文章中,实现了对图像的自动分割。ios
首先,在GrabCut的交互分割中,咱们经过用户本身画框,来框出包含目标的区域。因此,只要咱们可以肯定这个区域,再使用GrabCut算法就能够分割了。算法
原本想结合分水岭实现图割算法的,因此你会在下面代码段中看到WatershedSegment.h,但实际上并无用到,只是用到了其头文件中的两个函数,因此你必须在main函数中包含这个头文件。否则会报错,固然你也能够把有关图割的代码注释掉,尝试一下分水岭算法,能够参考这篇博文。函数
/*WatershedSegment.h*/ #if !defined WATERSHS #define WATERSHS #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.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; //在变换前,把每一个像素p转换为255p+255(在conertTo中实现) markers.convertTo(tmp, CV_8U, 255, 255); return tmp; } }; #endif /*Main.cpp*/ #include "WatershedSegment.h" #include <string> #include <iostream> using namespace std; using namespace cv; Mat g_image1; //原图 Mat g_binary; //二值化图像 Mat g_fg1;//前景像素 Mat g_bg1;//背景像素 Mat g_markers1;//合成的标记图像 Rect g_maxRect;//目标的最大连通区域 /*进行GrabCut须要的参数*/ Mat bgModel, fgModel, mask; /*读取原图*/ void ReadOriginalImg(string _filename) { // Read input image g_image1 = imread(_filename); if (!g_image1.data) { /*printf("读取%s失败!", _filename);*/ cout << "读取" + _filename + "失败!" << endl; system("pause"); return; } // Display the color image /*cv::resize(g_image1, g_image1, cv::Size(), 0.7, 1);*/ cv::namedWindow("Original Image1"); cv::imshow("Original Image1", g_image1); } /*获取目标像素*/ void GetObjectPix(Mat _src) { // Identify image pixels with object cv::cvtColor(_src, g_binary, COLOR_BGRA2GRAY); cv::threshold(g_binary, g_binary, 30, 255, CV_THRESH_BINARY|THRESH_OTSU);//阈值分割原图的灰度图,得到二值图像 // Display the binary image /*cv::namedWindow("binary Image1"); cv::imshow("binary Image1", g_binary);*/ // CLOSE operation cv::Mat element5(5, 5, CV_8U, cv::Scalar(1));//5*5正方形,8位uchar型,全1结构元素 cv::morphologyEx(g_binary, g_fg1, cv::MORPH_CLOSE, element5, Point(-1, -1), 2);// 闭运算填充物体内细小空洞、链接邻近物体 // Display the foreground image cv::namedWindow("Foreground Image"); cv::imshow("Foreground Image", g_fg1); } /*标记背景和未知区域*/ bool MarkBkgUkg(Mat _binary) { // Identify image pixels without objects cv::dilate(_binary, g_bg1, cv::Mat(), cv::Point(-1, -1), 5);//膨胀4次,锚点为结构元素中心点 cv::threshold(g_bg1, g_bg1, 1, 128, cv::THRESH_BINARY_INV);//>=1的像素设置为128(即背景) // Display the background image cv::namedWindow("Background Image"); cv::imshow("Background Image", g_bg1); return true; } bool GetMarker(Mat _fg,Mat _bg) { //Get markers image g_markers1 = _fg + _bg; //使用Mat类的重载运算符+来合并图像。 cv::namedWindow("markers Image"); cv::imshow("markers Image", g_markers1); return true; } void SegmentImg(Mat _src) { // Apply watershed segmentation WatershedSegmenter segmenter1; //实例化一个分水岭分割方法的对象 segmenter1.setMarkers(g_markers1);//设置算法的标记图像,使得水淹过程从这组预先定义好的标记像素开始 segmenter1.process(_src); //传入待分割原图 // Display segmentation result cv::namedWindow("Segmentation1"); cv::imshow("Segmentation1", segmenter1.getSegmentation());//将修改后的标记图markers转换为可显示的8位灰度图并返回分割结果(白色为前景,灰色为背景,0为边缘) waitKey(); // Display watersheds cv::namedWindow("Watersheds1"); cv::imshow("Watersheds1", segmenter1.getWatersheds());//以图像的形式返回分水岭(分割线条) } /*找到最大连通区域*/ void FindMaxArea(Mat _binnary) { vector<vector<cv::Point>> contours; findContours(g_binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); // 寻找最大连通域 double maxArea = 0; vector<cv::Point> maxContour; for (size_t i = 0; i < contours.size(); i++) { double area = cv::contourArea(contours[i]); if (area > maxArea) { maxArea = area; maxContour = contours[i]; } } // 将轮廓转为矩形框 g_maxRect = cv::boundingRect(maxContour); g_maxRect.width += 10; g_maxRect.height += 10; g_maxRect.x -= 5; g_maxRect.y -= 5; cout << "Corner 1 recorded at (" << g_maxRect.x << "," << g_maxRect.y <<")"<< endl; cout << "Corner 2 recorded at (" << g_maxRect.x + g_maxRect.width << "," << g_maxRect.y + g_maxRect.height << ")" << endl; Mat local_img = g_image1.clone(); rectangle(local_img, g_maxRect, Scalar(0, 0, 255), 1); namedWindow("MaxArea"); imshow("MaxArea", local_img); } /*利用图割算法进行分割*/ void MyGrabCut(Mat _src,Rect _Box) { grabCut(_src, mask, _Box, bgModel, fgModel, 5, cv::GC_INIT_WITH_RECT); compare(mask, GC_PR_FGD, mask, cv::CMP_EQ); namedWindow("Crop"); Mat imageROI; imageROI.create(_src.size(), _src.type()); /*imageROI = img(Rect(box));*/ imageROI.setTo(Scalar(255, 255, 255)); _src.copyTo(imageROI, mask); Mat crop(imageROI, _Box); imshow("Crop", crop); } int main() { ReadOriginalImg("flower.jpg"); GetObjectPix(g_image1); /*MarkBkgUkg(g_binary); GetMarker(g_fg1, g_bg1); SegmentImg(g_image1);*/ FindMaxArea(g_fg1); MyGrabCut(g_image1, g_maxRect); waitKey(0); }
程序有点慢,大约53s.ui