<a target="_blank" href="http://blog.csdn.net/jia20003/article/details/8214567"></a>
一:mean shift算法介紹
mean shift是一種聚類算法,在資料挖掘,圖像提取,視訊對象跟蹤中都有應用。本文
重要示範mean shift算法來實作圖像的低通邊緣保留濾波效果。其處理以後的圖像有點
類似油畫一樣。mean shift算法的輸入參數一般有三個:
1. 矩陣半徑r,聲明大小
2. 像素距離,常見為歐幾裡德距離或者曼哈頓距離
3. 像素內插補點value
算法大緻的流程如下:
a. 輸入像素點p(x, y)
b. 計算該點的像素值pixelv
c. 根據輸入的半徑r與內插補點value求出矩陣半徑内滿足內插補點像素平均值作為輸出像素點值
d. 計算shift與repetition,如果滿足條件
e. 繼續c ~ d,直到條件不滿足退出,得到最終的輸出像素值
f. 對輸入圖像的每個像素重複a ~ e,得到圖像輸出像素資料
二:色彩空間轉換
本文mean shift濾波在yiq顔色空間上完成,關于rgb與yiq顔色空間轉換可以參考

三:程式效果
濾鏡源代碼:
package com.gloomyfish.filter.study;
import java.awt.image.bufferedimage;
public class meanshiftfilter extends abstractbufferedimageop {
private int radius;
private float colordistance;
public meanshiftfilter() {
radius = 3; // default shift radius
colordistance = 25; // default color distance
}
public int getradius() {
return radius;
public void setradius(int radius) {
this.radius = radius;
public float getcolordistance() {
return colordistance;
public void setcolordistance(float colordistance) {
this.colordistance = colordistance;
@override
public bufferedimage filter(bufferedimage src, bufferedimage dest) {
int width = src.getwidth();
int height = src.getheight();
if ( dest == null )
dest = createcompatibledestimage( src, null );
int[] inpixels = new int[width*height];
int[] outpixels = new int[width*height];
getrgb( src, 0, 0, width, height, inpixels);
// convert rgb color space to yiq color space
float[][] pixelsf = new float[width*height][3];
for(int i=0; i<inpixels.length; i++) {
int argb = inpixels[i];
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb) & 0xff;
pixelsf[i][0] = 0.299f *r + 0.587f *g + 0.114f *b; // y
pixelsf[i][1] = 0.5957f *r - 0.2744f*g - 0.3212f *b; // i
pixelsf[i][2] = 0.2114f *r - 0.5226f*g + 0.3111f *b; // q
}
int index = 0;
float shift = 0;
float repetition = 0;
float radius2 = radius * radius;
float dis2 = colordistance * colordistance;
for(int row=0; row<height; row++) {
int ta = 255, tr = 0, tg = 0, tb = 0;
for(int col=0; col<width; col++) {
int xc = col;
int yc = row;
int xcold, ycold;
float ycold, icold, qcold;
index = row*width + col;
float[] yiq = pixelsf[index];
float yc = yiq[0];
float ic = yiq[1];
float qc = yiq[2];
repetition = 0;
do {
xcold = xc;
ycold = yc;
icold = ic;
qcold = qc;
float mx = 0;
float my = 0;
float mi = 0;
float mq = 0;
int num=0;
for (int ry=-radius; ry <= radius; ry++) {
int y2 = yc + ry;
if (y2 >= 0 && y2 < height) {
for (int rx=-radius; rx <= radius; rx++) {
int x2 = xc + rx;
if (x2 >= 0 && x2 < width) {
if (ry*ry + rx*rx <= radius2) {
yiq = pixelsf[y2*width + x2];
float y2 = yiq[0];
float i2 = yiq[1];
float q2 = yiq[2];
float dy = yc - y2;
float di = ic - i2;
float dq = qc - q2;
if (dy*dy+di*di+dq*dq <= dis2) {
mx += x2;
my += y2;
mi += i2;
mq += q2;
num++;
}
}
}
}
}
}
float num_ = 1f/num;
yc = my*num_;
ic = mi*num_;
qc = mq*num_;
xc = (int) (mx*num_+0.5);
yc = (int) (my*num_+0.5);
int dx = xc-xcold;
int dy = yc-ycold;
float dy = yc-ycold;
float di = ic-icold;
float dq = qc-qcold;
shift = dx*dx+dy*dy+dy*dy+di*di+dq*dq;
repetition++;
}
while (shift > 3 && repetition < 100);
tr = (int)(yc + 0.9563f*ic + 0.6210f*qc);
tg = (int)(yc - 0.2721f*ic - 0.6473f*qc);
tb = (int)(yc - 1.1070f*ic + 1.7046f*qc);
outpixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
}
setrgb( dest, 0, 0, width, height, outpixels );
return dest;
public string tostring() {
system.out.println("mean shift filter...");
return "meanshiftfilter";
}