濾鏡
濾鏡;主要是用來(lái)實(shí)現(xiàn)圖像的各種特殊效果叛赚。它在Photoshop中具有非常神奇的作用澡绩。濾鏡通常需要同通道、圖層等聯(lián)合使用俺附,才能取得最佳藝術(shù)效果肥卡。
在移動(dòng)端或者在web開(kāi)發(fā)時(shí)處理圖片都是一件麻煩的事兒。我調(diào)研過(guò)很多l(xiāng)ibrary事镣,特別是在移動(dòng)端處理圖片時(shí)動(dòng)不動(dòng)都需要使用 C++ 或者 OpenCV步鉴。這對(duì)于 Java 程序員來(lái)說(shuō),具有很高的門檻璃哟。甚至在調(diào)試時(shí)氛琢,遇到錯(cuò)誤都會(huì)無(wú)法下手進(jìn)行處理。其實(shí)随闪,隨著手機(jī)設(shè)備性能的不斷提高阳似,使用 Java 同樣能完成這些事情。
實(shí)現(xiàn)
這是原圖铐伴,可以選擇濾鏡來(lái)美化圖片撮奏。
這是幾種濾鏡的效果
首先,我們的庫(kù)叫 cv4j当宴,cv 是 Computer Vision 的意思畜吊,同時(shí)也用于致敬 OpenCV。
https://github.com/imageprocessor/cv4j
以SepiaTone濾鏡為例户矢,我們自己私下叫它懷舊風(fēng)格的濾鏡
import com.cv4j.core.datamodel.ImageData;
import com.cv4j.image.util.Tools;
public class SepiaToneFilter implements CommonFilter {
@Override
public ImageData filter(ImageData src) {
int width = src.getWidth();
int height = src.getHeight();
int offset = 0;
for(int row=0; row<height; row++) {
offset = row * width;
int tr = 0, tg = 0, tb = 0;
for (int col = 0; col < width; col++) {
tr = (src.getPixels()[offset] >> 16) & 0xff;
tg = (src.getPixels()[offset] >> 8) & 0xff;
tb = src.getPixels()[offset] & 0xff;
int fr = (int) colorBlend(noise(), (tr * 0.393) + (tg * 0.769) + (tb * 0.189), tr);
int fg = (int) colorBlend(noise(), (tr * 0.349) + (tg * 0.686) + (tb * 0.168), tg);
int fb = (int) colorBlend(noise(), (tr * 0.272) + (tg * 0.534) + (tb * 0.131), tb);
src.getPixels()[offset] = (255 << 24) | (Tools.clamp(fr) << 16) | (Tools.clamp(fg) << 8) | Tools.clamp(fb);
offset++;
}
}
return src;
}
private double noise() {
return Math.random()*0.5 + 0.5;
}
private double colorBlend(double scale, double dest, double src) {
return (scale * dest + (1.0 - scale) * src);
}
}
ImageData是我們自己定義的圖像數(shù)據(jù)結(jié)構(gòu)玲献。所有的濾鏡都是通過(guò)ImageData來(lái)傳遞。
import android.graphics.Bitmap;
public interface ImageData {
int CV4J_IMAGE_TYPE_RGB = 0;
int CV4J_IMAGE_TYPE_GRAY = 2;
int CV4J_IMAGE_TYPE_HSV = 4;
int CV4J_IMAGE_TYPE_BINARY = 8;
int[] getPixels();
int getWidth();
int getHeight();
int getType();
byte[] getChannel(int index);
void putPixels(int[] pixels);
int getPixel(int row, int col);
void setPixel(int row, int col, int rgb);
int[] getPixelByRowNumber(int rowIndex);
void convert2Gray();
Bitmap toBitmap();
}
ImageData是一個(gè)接口,目前它的實(shí)現(xiàn)類只有ColorImage捌年。
所以使用一個(gè)濾鏡瓢娜,通常只要這樣寫的就ok了。
ColorImage colorImage = new ColorImage(bitmap);
CommonFilter filter = new SepiaToneFilter();
colorImage = (ColorImage) filter.filter(colorImage);
imageView.setImageBitmap(colorImage.toBitmap());
性能是我們一直關(guān)心的話題延窜,我在模擬器上跑了demo app恋腕,通過(guò) AOP 的方法打印了 demo app 中一些濾鏡在使用時(shí)花費(fèi)的時(shí)間。
在demo app中逆瑞,濾鏡實(shí)例化是借助Class.forName()肯定比直接使用new 某個(gè)濾鏡類要慢一些荠藤。
總結(jié)
cv4j 是賈志剛和我一起開(kāi)發(fā)的圖像處理庫(kù),目前還處于很早期的版本获高。我們每天都會(huì)對(duì)這個(gè)庫(kù)做一些提交哈肖。整個(gè)庫(kù)在架構(gòu)上和圖像算法上都還有很大的提升空間。