介紹幾種特殊的灰階算法濾鏡,将彩色圖像轉換為灰階圖像。其中涉及到的有基于門檻值的圖
像二值化,弗洛伊德.斯坦德伯格抖動算法,基于門檻值的部分灰階化
基礎知識- 怎麼把rgb轉換為單色的[0 ~256]之間的灰階,最常用的轉換公式如下:
gray = 0.299 * red + 0.587 * green + 0.114 * blue;
1. 基于像素平均值的圖像門檻值二值化算法:
處理流程:
a. 首先将彩色圖像轉換為灰階圖像
b. 計算灰階圖像的算術平均值– m
c. 以m為門檻值,完成對灰階圖二值化( 大于門檻值m,像素點指派為白色,否則指派為黑
色)
圖像效果:
關鍵代碼:
public bufferedimage filter(bufferedimage src, bufferedimage dest) {
int width = src.getwidth();
int height = src.getheight();
if ( dest == null )
dest = createcompatibledestimage( src, null );
src = super.filter(src, dest);
int[] inpixels = new int[width*height];
int[] outpixels = new int[width*height];
getrgb(src, 0, 0, width, height, inpixels );
// calculate means of pixel
int index = 0;
double redsum = 0, greensum = 0, bluesum = 0;
double total = height * width;
for(int row=0; row<height; row++) {
int ta = 0, tr = 0, tg = 0, tb = 0;
for(int col=0; col<width; col++) {
index = row * width + col;
ta = (inpixels[index] >> 24) & 0xff;
tr = (inpixels[index] >> 16) & 0xff;
tg = (inpixels[index] >> 8) & 0xff;
tb = inpixels[index] & 0xff;
redsum += tr;
greensum += tg;
bluesum +=tb;
}
}
int means = (int)(redsum / total);
system.out.println(" threshold average value = " + means);
// dithering
for(int row=0; row<height; row++) {
int ta = 0, tr = 0, tg = 0, tb = 0;
for(int col=0; col<width; col++) {
index = row * width + col;
ta = (inpixels[index] >> 24) & 0xff;
tr = (inpixels[index] >> 16) & 0xff;
tg = (inpixels[index] >> 8) & 0xff;
tb = inpixels[index] & 0xff;
if(tr >=means) {
tr = tg = tb = 255;
} else {
tr = tg = tb = 0;
}
outpixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
}
setrgb( dest, 0, 0, width, height, outpixels );
return dest;
}
2. 基于錯誤擴散的floyd-steinberg抖動算法
關于什麼是floyd-steinberg抖動,參見這裡
<a target="_blank" href="http://en.wikipedia.org/wiki/floyd%e2%80%93steinberg_dithering">http://en.wikipedia.org/wiki/floyd–steinberg_dithering</a>
@override
dest = createcompatibledestimage( src, null );
getrgb( src, 0, 0, width, height, inpixels );
int index = 0;
int r1 = (inpixels[index] >> 16) & 0xff;
int g1 = (inpixels[index] >> 8) & 0xff;
int b1 = inpixels[index] & 0xff;
int cindex = getclosecolor(r1, g1, b1);
outpixels[index] = (255 << 24) | (color_palette[cindex][0] << 16) | (color_palette[cindex][1] << 8) | color_palette[cindex][2];
int er = r1 - color_palette[cindex][0];
int eg = g1 - color_palette[cindex][1];
int eb = b1 - color_palette[cindex][2];
int k = 0;
if(row + 1 < height && col - 1 > 0) {
k = (row + 1) * width + col - 1;
r1 = (inpixels[k] >> 16) & 0xff;
g1 = (inpixels[k] >> 8) & 0xff;
b1 = inpixels[k] & 0xff;
r1 += (int)(er * kerneldata[0]);
g1 += (int)(eg * kerneldata[0]);
b1 += (int)(eb * kerneldata[0]);
inpixels[k] = (255 << 24) | (clamp(r1) << 16) | (clamp(g1) << 8) | clamp(b1);
if(col + 1 < width) {
k = row * width + col + 1;
r1 += (int)(er * kerneldata[3]);
g1 += (int)(eg * kerneldata[3]);
b1 += (int)(eb * kerneldata[3]);
if(row + 1 < height) {
k = (row + 1) * width + col;
r1 += (int)(er * kerneldata[1]);
g1 += (int)(eg * kerneldata[1]);
b1 += (int)(eb * kerneldata[1]);
if(row + 1 < height && col + 1 < width) {
k = (row + 1) * width + col + 1;
r1 += (int)(er * kerneldata[2]);
g1 += (int)(eg * kerneldata[2]);
b1 += (int)(eb * kerneldata[2]);
3. 選擇性灰階算法
計算選擇的顔色與像素灰階顔色之間的幾何距離值,跟門檻值比較決定是否像素點為灰階
值,可以得到一些讓你意想不到的圖像處理效果!
圖像效果 (main color = green, 門檻值 = 200)
原圖:
處理以後
關鍵代碼:
int gray = (int)(0.299 * (double)tr + 0.587 * (double)tg + 0.114 * (double)tb);
double distance = getdistance(tr, tg, tb);
if(distance < threshold) {
double k = distance / threshold;
int[] rgb = getadjustablergb(tr, tg, tb, gray, (float)k);
tr = rgb[0];
tg = rgb[1];
tb = rgb[2];
outpixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
outpixels[index] = (ta << 24) | (gray << 16) | (gray << 8) | gray;
建立新的目标image
public bufferedimage createcompatibledestimage(bufferedimage src, colormodel dstcm) {
if ( dstcm == null )
dstcm = src.getcolormodel();
return new bufferedimage(dstcm, dstcm.createcompatiblewritableraster(src.getwidth(), src.getheight()), dstcm.isalphapremultiplied(), null);