圖像可以是看成是一個(gè)多維的數(shù)組选泻。讀取一張圖片,可以看成是讀入了一系列的像素內(nèi)容美莫。這些像素內(nèi)容页眯,按照不同的模式具有不同的格式。對于三通道的 RGB 位圖來說厢呵,每個(gè)像素是一個(gè) 8-bit 整數(shù)的三元組窝撵。圖像的像素操作是比較基礎(chǔ)的圖像算法,下面列舉三個(gè)常用的像素操作算法襟铭。
圖像加法
圖像的加法表示兩個(gè)輸入圖像在同一位置上的像素相加碌奉,得到一個(gè)輸出圖像的過程。
imageProcessor = Operator.add(imageProcessor1,imageProcessor2);
if (imageProcessor!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
Operator的add表示矩陣加法寒砖,有一個(gè)要求兩個(gè)圖像必須大小一致赐劣。
public static ImageProcessor add(ImageProcessor image1, ImageProcessor image2) {
if(!checkParams(image1, image2)) {
return null;
}
int channels = image1.getChannels();
int w = image1.getWidth();
int h = image1.getHeight();
ImageProcessor dst = (channels == 3) ? new ColorProcessor(w, h) : new ByteProcessor(w, h);
int size = w*h;
int a=0, b=0;
int c=0;
for(int i=0; i<size; i++) {
for(int n=0; n<channels; n++) {
a = image1.toByte(n)[i]&0xff;
b = image2.toByte(n)[i]&0xff;
c = Tools.clamp(a + b);
dst.toByte(n)[i] = (byte)c;
}
}
return dst;
}
在實(shí)際工作中,可以通過一張?jiān)瓐D和一個(gè)mask圖像來相加合成一些不規(guī)則的效果圖片哩都。
像素混合
在這里混合是線性混合魁兼,跟之前的圖像加法有一定的區(qū)別。
imageProcessor = Operator.addWeight(imageProcessor1,2.0f,imageProcessor2,1.0f,4);
if (imageProcessor!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
Operator的addWeight方法表示像素混合漠嵌。
public static ImageProcessor addWeight(ImageProcessor image1, float w1, ImageProcessor image2, float w2, int gamma) {
if(!checkParams(image1, image2)) {
return null;
}
int channels = image1.getChannels();
int w = image1.getWidth();
int h = image1.getHeight();
ImageProcessor dst = (channels == 3) ? new ColorProcessor(w, h) : new ByteProcessor(w, h);
int size = w*h;
int a=0, b=0;
int c=0;
for(int i=0; i<size; i++) {
for(int n=0; n<channels; n++) {
a = image1.toByte(n)[i]&0xff;
b = image2.toByte(n)[i]&0xff;
c = (int)(a*w1 + b*w2 + gamma);
dst.toByte(n)[i] = (byte)Tools.clamp(c);
}
}
return dst;
}
提取圖像中的ROI
ROI(region of interest)咐汞,表示圖像中感興趣的區(qū)域。對于一張圖像儒鹿,可能我們只對圖像中某部分感興趣化撕,或者要對目標(biāo)進(jìn)行跟蹤時(shí),需要選取目標(biāo)特征挺身,所以要提取圖像的感興趣區(qū)域侯谁。
Resources res = getResources();
final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.pixel_test_3);
image.setImageBitmap(bitmap);
CV4JImage cv4jImage = new CV4JImage(bitmap);
ImageProcessor imageProcessor = cv4jImage.getProcessor();
Rect rect = new Rect();
rect.x = 300;
rect.y = 200;
rect.width = 300;
rect.height = 450;
ImageProcessor resultImageProcessor = null;
try {
resultImageProcessor = Operator.subImage(imageProcessor,rect);
} catch (CV4JException e) {
}
if (resultImageProcessor!=null) {
CV4JImage resultCV4JImage = new CV4JImage(resultImageProcessor.getWidth(), resultImageProcessor.getHeight(), resultImageProcessor.getPixels());
result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
其中,rect.x和rect.y表示ROI的起始點(diǎn)章钾,rect.width和rect.height表示ROI的寬和高墙贱。Operator的subImage()表示從原圖中提取ROI,之所以在這里還用到了try catch贱傀,是為了防止出現(xiàn)ROI的寬度或者高度過大惨撇,從而導(dǎo)致數(shù)組越界。
subImage方法的代碼也很簡單
/**
* ROI sub image by rect.x, rect.y, rect.width, rect.height
* @param image
* @param rect
* @return
* @throws CV4JException
*/
public static ImageProcessor subImage(ImageProcessor image, Rect rect) throws CV4JException{
int channels = image.getChannels();
int w = rect.width;
int h = rect.height;
ImageProcessor dst = (channels == 3) ? new ColorProcessor(w, h) : new ByteProcessor(w, h);
int a=0;
int index = 0;
try {
for(int n=0; n<channels; n++) {
for(int row=rect.y; row < (rect.y+rect.height); row++) {
for(int col=rect.x; col < (rect.x+rect.width); col++) {
index = row*image.getWidth() + col;
a = image.toByte(n)[index]&0xff;
index = (row - rect.y)*w + (col - rect.x);
dst.toByte(n)[index] = (byte)a;
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new CV4JException("數(shù)組越界了");
}
return dst;
}
總結(jié)
cv4j 是gloomyfish和我一起開發(fā)的圖像處理庫府寒,純java實(shí)現(xiàn)魁衙,目前還處于早期的版本报腔。
像素操作是 cv4j 的基本功能之一,所有的像素操作算法都在Operator類中剖淀。除了本文介紹的三個(gè)算法之外纯蛾,還有substract表示矩陣減法、multiple表示矩陣逐元素乘法纵隔、division表示矩陣逐元素除法以及bitwise_and翻诉、bitwise_not、bitwise_or捌刮、bitwise_xor表示每個(gè)元素進(jìn)行位運(yùn)算分別是和碰煌、非、或绅作、異或芦圾。
如果您想看該系列先前的文章可以訪問下面的文集:
http://www.reibang.com/nb/10401400