opencv pyrMeanShiftFiltering
demo: http://download.csdn.net/detail/keen_zuxwang/9852585
MeanShfit
均值漂移算法是一种通用的聚类算法,它的基本原理:
对于给定的一定数量样本,任选其中一个样本,以该样本为中心点划定一个圆形区域,求取该圆形区域内样本的质心,即密度最大处的点,再以该点为中心继续执行上述迭代过程,直至最终收敛。可以利用均值偏移算法,可实现彩色图像分割。
(本质是经过迭代,将收敛点的像素值代替原来的像素值,从而去除了局部相似的纹理,同时保留了边缘等差异较大的特征)
pyrMeanShiftFiltering实现图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域,算法跟金字塔图像分割、grabcut图割、分水岭算法相比,耗时较长。
//! filters image using meanshift algorithm
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) );
src
输入图像,8位三通道的彩色图像,RGB,HSV、YUV等Opencv中的彩色图像格式均可
dst
输出图像,跟输入src有同样的大小和数据格式
sp
漂移物理空间半径大小;
sr
漂移色彩空间半径大小;
maxLevel
金字塔的最大层数;
termcrit
漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合
pyrMeanShiftFiltering函数的执行过程:
1、迭代空间构建:
以输入图像上src上任一点P0为圆心,建立物理空间上半径为sp,色彩空间上半径为sr的球形空间,物理空间上坐标2个—x、y,色彩空间上坐标3个—R、G、B(或HSV),构成一个5维的空间球体。
其物理空间的范围x和y是图像的长和宽,
色彩空间的范围R、G、B分别是0~255。
2、求取迭代空间的向量并移动迭代空间球体后重新计算向量,直至收敛:
在1中构建的球形空间中,求得所有点相对于中心点的色彩向量之和后,移动迭代空间的中心点到该向量的终点,并再次计算该球形空间中所有点的向量之和,如此迭代,直到在最后一个空间球体中所求得的向量和的终点就是该空间球体的中心点Pn,迭代结束。
3、更新输出图像dst上对应的初始原点P0的色彩值为本轮迭代的终点Pn的色彩值,如此完成一个点的色彩均值漂移。
4、对输入图像src上其他点,依次执行步骤1,、2、3,遍历完所有点位后,整个均值偏移色彩滤波完成
sp和sr的设置,二者设置的值越大,对图像色彩的平滑效果越明显,同时函数耗时也越多
漫水填充:
//! fills the semi-uniform image region and/or the mask starting from the specified seed point
CV_EXPORTS_W int floodFill( InputOutputArray image, InputOutputArray mask,
Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0,
Scalar loDiff=Scalar(), Scalar upDiff=Scalar(),
int flags=4 );
image
输入三通道8bit彩色图像CV_8UC3,同时作为输出。
mask
掩模图像,它的大小是输入图像的长宽左右各加1个像素,mask一方面作为输入的掩模图像,另一方面也会在填充的过程中不断被更新。
floodFill漫水填充的过程并不会填充mask上灰度值不为0的像素点,所以可以使用一个图像边缘检测的输出作为mask,这样填充就不会填充或越过边缘轮廓。mask在填充的过程中被更新:
每当一个原始图上一个点位(x,y)被填充之后,该点位置对应的mask上的点(x+1,y+1)的灰度值随机被设置为1(原本该点的灰度值为0),代表该点已经被填充处理过。
seedPoint
漫水填充的起始种子点。
newVal
被充填的色彩值。
rect
可选的参数,用于设置floodFill函数将要重绘区域的最小矩形区域;
loDiff
定义跟种子点相比色彩的下限值
upDiff
定义跟种子点相比色彩的上限值,介于种子点减去loDiff和种子点加上upDiff的值会被填充为跟种子点同样的颜色。
flags
漫水填充的模式,用于连通性、扩展方向等的定义
JNI :
JNIEXPORT jlong JNICALL Java_com_example_grabcut_MainActivity_doPyrMeanShiftFiltering(JNIEnv *env, jclass clz, jlong imageGray)
{
Mat img0 = Mat(*(Mat*)imageGray);
blur(img0, img0, Size(5,5)); //均值滤波
Mat img(img0.size(),CV_8UC3);
cvtColor(img0, img, CV_BGRA2BGR);
Mat res; //分割后图像
int spatialRad = 50; //空间窗口大小
int colorRad = 30; //色彩窗口大小
int maxPyrLevel = 1; //金字塔层数
pyrMeanShiftFiltering(img, res, spatialRad, colorRad, maxPyrLevel); //色彩聚类平滑滤波
Mat mask(res.rows+2, res.cols+2, CV_8UC1, Scalar::all(0) ); //掩模
for(int y = 0; y < res.rows; y++) {
for(int x = 0; x < res.cols; x++) {
if( mask.at<uchar>(y+1, x+1) == 0) { //非0处即为1,表示已经经过填充,不再处理
//Scalar newVal( rng(256), rng(256), rng(256) );
Scalar color(rand()&255, rand()&255, rand()&255);
floodFill(res, mask, Point(x,y), color, 0, Scalar::all(5), Scalar::all(5) ); //执行漫水填充
}
}
}
Mat *hist = new Mat(res);
return (jlong) hist;
}