一、meanshift 分割算法原理;
参考论文:Mean shift: A robust approach toward feature space analysis , PAMI, 2002
mean shift认为中心是概率密度( probalility density function )的 极大值点 ,沿着梯度方向,自适应调整步长(越靠近极值点步长越小),迭代搜索 。
其算法主要分为二步:
1. 模点搜索,即找每个数据点的类中心,以中心的颜色代替自己的颜色,从而平滑图像。但模点搜索得到的模点太多,并且很多模点挨得很近,若果将每个模点都作为一类的话,类别太多,容易产生过分割,即分割太细,所以要合并掉一些模点。
2.模点聚类。模点聚类后所得到的分割区域中,有些区域所包含的像素点太少,这些小区域也不是我们想要的,需要再次合并。OpenCV采用 flood fill 函数实现。
二、meanshift 分割算法在opencv上的实现;
CV_EXPORTS_W void pyrMeanShiftFiltering(InputArray src,//输入图像
OutputArray dst,//输出图像
double sp,//空间域半径
double sr, //颜色域半径
int maxLevel=1,分割金字塔的最大层数
TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) ) ;//迭代的终止条件
其中,double sp,//空间域半径,double sr,//颜色域半径,int maxLevel=1,分割金字塔的最大层数,这三个值越大,程序运行的速度越慢
源码范例
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat src, dst;
void meanshift_seg(int spatialRad, int colorRad, int maxPryLevel)
{
调用meanshift图像金字塔进行分割
pyrMeanShiftFiltering(src, dst, spatialRad, colorRad, maxPryLevel);
RNG rng = theRNG();
Mat mask(dst.rows + 2, dst.cols + 2, CV_8UC1, Scalar::all(0));
for (int i = 0; i < dst.rows; i++) //opencv图像等矩阵也是基于0索引
{
for (int j = 0; j < dst.cols; j++)
{
if (mask.at(i + 1, j + 1) == 0)
{
Scalar newcolor(rng(256), rng(256), rng(256));
floodFill(dst, mask, Point(j, i), newcolor, 0, Scalar::all(1), Scalar::all(1));
}
}
}
}
int main(int argc, uchar* argv[])
{
clock_t start, end;
start = clock();
src = imread("1.jpg");
meanshift_seg(10,10,1);
imshow("src", src);
imshow("dst", dst);
end = clock();
cout << "Run time: " << (double)(end - start) / CLOCKS_PER_SEC << "S" << endl;
waitKey();//无限等待用户交互响应
}
分割后的图像