經常使用的像素操做算法:圖像加法、像素混合、提取圖像中的ROI

圖像能夠是當作是一個多維的數組。讀取一張圖片,能夠當作是讀入了一系列的像素內容。這些像素內容,按照不一樣的模式具備不一樣的格式。對於三通道的 RGB 位圖來講,每一個像素是一個 8-bit 整數的三元組。圖像的像素操做是比較基礎的圖像算法,下面列舉三個經常使用的像素操做算法。java

圖像加法

圖像的加法表示兩個輸入圖像在同一位置上的像素相加,獲得一個輸出圖像的過程。git

imageProcessor = Operator.add(imageProcessor1,imageProcessor2);

        if (imageProcessor!=null) {
            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
            result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
        }複製代碼

圖像加法.png
圖像加法.png

Operator的add表示矩陣加法,有一個要求兩個圖像必須大小一致。github

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;
    }複製代碼

在實際工做中,能夠經過一張原圖和一個mask圖像來相加合成一些不規則的效果圖片。算法

像素混合

在這裏混合是線性混合,跟以前的圖像加法有必定的區別。數組

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());
        }複製代碼

像素混合.png
像素混合.png

Operator的addWeight方法表示像素混合。spa

addWeight.png
addWeight.png

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),表示圖像中感興趣的區域。對於一張圖像,可能咱們只對圖像中某部分感興趣,或者要對目標進行跟蹤時,須要選取目標特徵,因此要提取圖像的感興趣區域。.net

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());
        }複製代碼

提取圖像中的ROI.png
提取圖像中的ROI.png

其中,rect.x和rect.y表示ROI的起始點,rect.width和rect.height表示ROI的寬和高。Operator的subImage()表示從原圖中提取ROI,之因此在這裏還用到了try catch,是爲了防止出現ROI的寬度或者高度過大,從而致使數組越界。3d

subImage方法的代碼也很簡單rest

/** * 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("數組越界了");
        }

        return dst;
    }複製代碼

總結

cv4jgloomyfish和我一塊兒開發的圖像處理庫,純java實現,目前還處於早期的版本。code

像素操做是 cv4j 的基本功能之一,全部的像素操做算法都在Operator類中。除了本文介紹的三個算法以外,還有substract表示矩陣減法、multiple表示矩陣逐元素乘法、division表示矩陣逐元素除法以及bitwise_and、bitwise_not、bitwise_or、bitwise_xor表示每一個元素進行位運算分別是和、非、或、異或。

若是您想看該系列先前的文章能夠訪問下面的文集:
www.jianshu.com/nb/10401400

相關文章
相關標籤/搜索