一:Mean Shift算法介紹java
Mean Shift是一種聚類算法,在數據挖掘,圖像提取,視頻對象跟蹤中都有應用。本文算法
重要演示Mean Shift算法來實現圖像的低通邊緣保留濾波效果。其處理之後的圖像有點ide
相似油畫同樣。Mean Shift算法的輸入參數通常有三個:this
1. 矩陣半徑r,聲明大小google
2. 像素距離,常見爲歐幾里德距離或者曼哈頓距離url
3. 像素差值valuespa
算法大體的流程以下:.net
a. 輸入像素點P(x, y)orm
b. 計算該點的像素值pixelv視頻
c. 根據輸入的半徑r與差值value求出矩陣半徑內知足差值像素平均值做爲輸出像素點值
d. 計算shift與repetition,若是知足條件
e. 繼續c ~ d,直到條件不知足退出,獲得最終的輸出像素值
f. 對輸入圖像的每一個像素重複a ~ e,獲得圖像輸出像素數據
二:色彩空間轉換
本文Mean Shift濾波在YIQ顏色空間上完成,關於RGB與YIQ顏色空間轉換能夠參考
這裏:http://en.wikipedia.org/wiki/YIQ我google找來的轉換公式截屏:

三:程序效果

濾鏡源代碼:
- 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;
- colorDistance = 25;
- }
- 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);
-
-
- 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;
- pixelsf[i][1] = 0.5957f *r - 0.2744f*g - 0.3212f *b;
- pixelsf[i][2] = 0.2114f *r - 0.5226f*g + 0.3111f *b;
- }
-
- 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;
- YcOld = Yc;
- IcOld = Ic;
- QcOld = Qc;
-
- float mx = 0;
- float my = 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;
- 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";
- }
-
- }