#include
#include
using namespace cv;
using namespace std;
void waterSegment(InputArray& _src, OutputArray& _dst, int& noOfSegment);
int main(int argc, char** argv) {
Mat inputImage = imread('coins.jpg');
assert(!inputImage.data);
Mat graImage, outputImage;
int offSegment;
waterSegment(inputImage, outputImage, offSegment);
waitKey(0);
return 0;
}
void waterSegment(InputArray& _src,OutputArray& _dst,int& noOfSegment)
{
Mat src = _src.getMat();//dst = _dst.getMat();
Mat grayImage;
cvtColor(src, grayImage,CV_BGR2GRAY);
threshold(grayImage, grayImage, 0, 255, THRESH_BINARY | THRESH_OTSU);
Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9), Point(-1, -1));
morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);
distanceTransform(grayImage, grayImage, DIST_L2, DIST_MASK_3, 5);
normalize(grayImage, grayImage,0,1, NORM_MINMAX);
grayImage.convertTo(grayImage, CV_8UC1);
threshold(grayImage, grayImage,0,255, THRESH_BINARY | THRESH_OTSU);
morphologyEx(grayImage, grayImage, MORPH_CLOSE, kernel);
vector<>> contours;
vector hierarchy;
Mat showImage = Mat::zeros(grayImage.size(), CV_32SC1);
findContours(grayImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));
for (size_t i = 0; i < contours.size();="">
{
//这里static_cast(i+1)是为了分水岭的标记不同,区域1、2、3。。。。这样才能分割
drawContours(showImage, contours, static_cast(i), Scalar::all(static_cast(i+1)), 2);
}
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(src, src, MORPH_ERODE, k);
watershed(src, showImage);
//随机分配颜色
vector colors;
for (size_t i = 0; i < contours.size();="" i++)="">
int r = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int b = theRNG().uniform(0, 255);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
// 显示
Mat dst = Mat::zeros(showImage.size(), CV_8UC3);
int index = 0;
for (int row = 0; row < showimage.rows;="" row++)="">
for (int col = 0; col < showimage.cols;="" col++)="">
index = showImage.at(row, col);
if (index > 0 && index <= contours.size())="">=>
dst.at(row, col) = colors[index - 1];
}
else if (index == -1)
{
dst.at(row, col) = Vec3b(255, 255, 255);
}
else {
dst.at(row, col) = Vec3b(0, 0, 0);
}
}
}
}
分水岭合并代码:
void segMerge(Mat& image, Mat& segments, int& numSeg)
{
vector samples;
int newNumSeg = numSeg;
//初始化变量长度的Vector
for (size_t i = 0; i < newnumseg;="">
{
Mat sample;
samples.push_back(sample);
}
for (size_t i = 0; i < segments.rows;="">
{
for (size_t j = 0; j < segments.cols;="">
{
int index = segments.at(i, j);
if (index >= 0 && index <=>=>
{
if (!samples[index].data)//数据为空不能合并,否则报错
{
samples[index] = image(Rect(j, i, 1, 1));
}
else//按行合并
{
vconcat(samples[index], image(Rect(j, i, 2, 1)), samples[index]);
}
}
//if (index >= 0 && index <=>=>
// samples[index].push_back(image(Rect(j, i, 1, 1)));
}
}
vector hist_bases;
Mat hsv_base;
int h_bins = 35;
int s_bins = 30;
int histSize[2] = { h_bins , s_bins };
float h_range[2] = { 0,256 };
float s_range[2] = { 0,180 };
const float* range[2] = { h_range,s_range };
int channels[2] = { 0,1 };
Mat hist_base;
for (size_t i = 1; i < numseg;="">
{
if (samples[i].dims > 0)
{
cvtColor(samples[i], hsv_base, CV_BGR2HSV);
calcHist(&hsv_base, 1, channels, Mat(), hist_base, 2, histSize, range);
normalize(hist_base, hist_base, 0, 1, NORM_MINMAX);
hist_bases.push_back(hist_base);
}
else
{
hist_bases.push_back(Mat());
}
}
double similarity = 0;
vector merged;//是否合并的标志位
for (size_t i = 0; i < hist_bases.size();="">
{
for (size_t j = i+1; j < hist_bases.size();="">
{
if (!merged[j])//未合并的区域进行相似性判断
{
if (hist_bases[i].dims > 0 && hist_bases[j].dims > 0)//这里维数判断没必要,直接用个data就可以了
{
similarity = compareHist(hist_bases[i], hist_bases[j], HISTCMP_BHATTACHARYYA);
if (similarity > 0.8)
{
merged[j] = true;//被合并的区域标志位true
if (i != j)//这里没必要,i不可能等于j
{
newNumSeg --;//分割部分减少
for (size_t p = 0; p < segments.rows;="">
{
for (size_t k = 0; k < segments.cols;="">
{
int index = segments.at(p, k);
if (index == j) segments.at(p, k) = i;
}
}
}
}
}
}
}
}
numSeg = newNumSeg;//返回合并之后的区域数量
}
参考:
http://blog.csdn.net/iracer/article/details/49225823
http://www.cnblogs.com/mikewolf2002/p/3304118.html
http://lib.csdn.net/article/opencv/22776
《opencv图像处理编程实例》
代码参考贾老师视频,原理早就看了毛星云的书本,但是当时一知半解,现在从头看一下子就懂了。