常用的像素操作算法:圖像加法、像素混合稿械、提取圖像中的ROI

圖像可以是看成是一個(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());
        }
圖像加法.png

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());
        }
像素混合.png

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

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)咐汞,表示圖像中感興趣的區(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());
        }
提取圖像中的ROI.png

其中,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é)

cv4jgloomyfish和我一起開發(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市俄认,隨后出現(xiàn)的幾起案子个少,更是在濱河造成了極大的恐慌,老刑警劉巖梭依,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稍算,死亡現(xiàn)場離奇詭異典尾,居然都是意外死亡役拴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門钾埂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來河闰,“玉大人,你說我怎么就攤上這事褥紫〗裕” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵髓考,是天一觀的道長部念。 經(jīng)常有香客問我,道長氨菇,這世上最難降的妖魔是什么儡炼? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮查蓉,結(jié)果婚禮上乌询,老公的妹妹穿的比我還像新娘。我一直安慰自己豌研,他們只是感情好妹田,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布唬党。 她就那樣靜靜地躺著,像睡著了一般鬼佣。 火紅的嫁衣襯著肌膚如雪驶拱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天晶衷,我揣著相機(jī)與錄音屯烦,去河邊找鬼。 笑死房铭,一個(gè)胖子當(dāng)著我的面吹牛驻龟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缸匪,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼翁狐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凌蔬?” 一聲冷哼從身側(cè)響起露懒,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎砂心,沒想到半個(gè)月后懈词,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辩诞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年坎弯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片译暂。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抠忘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出外永,到底是詐尸還是另有隱情崎脉,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布伯顶,位于F島的核電站囚灼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏祭衩。R本人自食惡果不足惜灶体,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汪厨。 院中可真熱鬧赃春,春花似錦、人聲如沸劫乱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狭吼,卻和暖如春层坠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刁笙。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工破花, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疲吸。 一個(gè)月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓座每,卻偏偏與公主長得像,于是被迫代替她去往敵國和親摘悴。 傳聞我的和親對象是個(gè)殘疾皇子峭梳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354