opencv 分水岭算法区域的分割和合并
程序员文章站
2022-05-16 11:23:01
...
使用直方图相似性合并相似区域
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
using namespace cv;
Mat display(Mat& markers, int noOfSegment)
{
vector<Vec3b> colorTab;
for (int i = 0; i < noOfSegment; i++)
{
int b = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);
colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
Mat watershedImage(markers.size(), CV_8UC3);
for (int i = 0; i < markers.rows; i++)
{
for (int j = 0; j < markers.cols; j++)
{
int index = markers.at<int>(i, j);
if (index == -1)
watershedImage.at<Vec3b>(i, j) = Vec3b((uchar)255, (uchar)255, (uchar)255);
else if (index <= 0 || index > noOfSegment)
watershedImage.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
else
watershedImage.at<Vec3b>(i, j) = colorTab[index - 1];
}
}
return watershedImage;
}
//分水岭图像分割
Mat watershedSrgment(Mat src, int& noOfSegment)//noOfSegment表示分割的类别数
{
Mat grayMat;
Mat otsuMat;
cvtColor(src, grayMat, CV_BGR2GRAY);
threshold(grayMat, otsuMat, 0, 255, CV_THRESH_BINARY_INV + CV_THRESH_OTSU);
imshow("src", src);
imshow("otsuMat", otsuMat);
//形态学
morphologyEx(otsuMat, otsuMat, MORPH_OPEN, Mat::ones(9, 9, CV_8SC1), Point(4, 4), 2);//2表示迭代的次数,Point(4,4)表示结构元素的原点
imshow("Mor-open", otsuMat);
//距离变换
Mat disTranMat(otsuMat.rows, otsuMat.cols, CV_32FC1);
distanceTransform(otsuMat, disTranMat, CV_DIST_L2, 3);
//归一化
normalize(disTranMat, disTranMat, 0.0, 1, NORM_MINMAX);
imshow("DisTranMat", disTranMat);
//阈值分割
threshold(disTranMat, disTranMat, 0.1, 1, CV_THRESH_BINARY);
normalize(disTranMat, disTranMat, 0, 255, NORM_MINMAX);
disTranMat.convertTo(disTranMat, CV_8UC1);
imshow("TDisTranMat", disTranMat);
//计算标记的分割块
int i, j, compCount = 0;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(disTranMat, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
Mat markers(disTranMat.size(), CV_32S);
markers = Scalar::all(0);
int idx = 0;
//绘制区域块
for (; idx >= 0; idx = hierarchy[idx][0], compCount++)
{
drawContours(markers, contours, idx, Scalar::all(compCount + 1), -1, 8, hierarchy, INT_MAX);
}
imshow("markers", markers * 255);
double t = (double)getTickCount();
watershed(src, markers);
t = (double)getTickCount() - t;
cout << "time: " << t * 1000 / getTickFrequency() << endl;
Mat wash = display(markers, compCount);
imshow("watershedSrgment", wash);
noOfSegment = compCount;
waitKey(0);
return markers;
}
//分水岭图像合并
void segMerge(Mat src, Mat& segments, int& numSeg)
{
vector<Mat> samples;//每个分割区域
//统计区域更新
int newNumSeg = numSeg;
//初始化samples
for (int i = 0; i <= numSeg; i++)
{
Mat sampleImage;
samples.push_back(sampleImage);
}
//计算每个像素的归属
for (int i = 0; i < segments.rows; i++)
{
for (int j = 0; j < segments.cols; j++)
{
int index = segments.at<int>(i,j);
if (index >= 0 && index < numSeg)
samples[index].push_back(src(Rect(j,i,1,1)));
}
}
//创建直方图
vector<MatND> hist_bases;
Mat hsv_base;
int h_bins = 35;
int s_bins = 30;
int hist_size[] = {h_bins,s_bins};
float h_ranges[] = {0,256};
float s_ranges[] = {0,180};
const float* ranges[] = { h_ranges,s_ranges };
int channels[] = {0,1};
MatND hist_base;
for (int i = 0; i <= numSeg; i++)
{
if (samples[i].dims > 0)
{
cvtColor(samples[i], hsv_base, CV_BGR2HSV);
calcHist(&hsv_base, 1, channels, Mat(), hist_base, 2, hist_size, ranges);
normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());
hist_bases.push_back(hist_base);
}
else
hist_bases.push_back(Mat());
hist_base.release();
}
//计算各直方图之间的相似性
double similarity = 0;
vector<bool> merged;
for (int k = 0; k < hist_bases.size(); k++)
{
merged.push_back(false);
}
for (int c = 0; c < hist_bases.size(); c++)
{
for (int q = c + 1; q < hist_bases.size(); q++)
{
if (!merged[q])
{
if (hist_bases[c].dims > 0 && hist_bases[q].dims>0)
{
similarity = compareHist(hist_bases[c],hist_bases[q],CV_COMP_BHATTACHARYYA);
if (similarity > 0.8)
{
merged[q] = true;
if (q != c)
{
newNumSeg--;
for (int i = 0; i < segments.rows; i++)
{
for (int j = 0; j < segments.cols; j++)
{
int index = segments.at<int>(i, j);
if (index == q)
segments.at<int>(i, j) = c;
}
}
}
}
}
}
}
}
numSeg = newNumSeg;
Mat wash=display(segments, numSeg);
imshow("segMerge", wash);
waitKey(0);
}
int main()
{
//imread中0表示灰度返回,1表示原图返回
Mat srcImage = imread("E:\\研究生\\学习材料\\学习书籍\\OpenCV图像处理编程实例-源码-20160801\\《OpenCV图像处理编程实例-源码-20160801\\images\\flower.jpg");
if (!srcImage.data)
return -1;
int noOfSegment = 0;
Mat segments=watershedSrgment(srcImage, noOfSegment);
segMerge(srcImage, segments, noOfSegment);
return 0;
}
上一篇: 数据结构干货笔记:平衡二叉树(AVL)的调整和构建C代码实现
下一篇: 全网最强-wym专属
推荐阅读