二值圖像分析:案例實(shí)戰(zhàn)(文本分離+硬幣計(jì)數(shù))

圖像的二值化

圖像二值化就是將圖像上的像素點(diǎn)的灰度值設(shè)置為0或255扼仲,也就是將整個(gè)圖像呈現(xiàn)出明顯的黑白效果顺献。
將256個(gè)亮度等級(jí)的灰度圖像通過適當(dāng)?shù)拈撝颠x取而獲得仍然可以反映圖像整體和局部特征的二值化圖像。在數(shù)字圖像處理中,二值圖像占有非常重要的地位,首先救巷,圖像的二值化有利于圖像的進(jìn)一步處理默责,使圖像變得簡(jiǎn)單贬循,而且數(shù)據(jù)量減小,能凸顯出感興趣的目標(biāo)的輪廓桃序。其次杖虾,要進(jìn)行二值圖像的處理與分析,首先要把灰度圖像二值化媒熊,得到二值化圖像奇适。

在實(shí)際應(yīng)用中,很多圖像的分析最終都轉(zhuǎn)換為二值圖像的分析泛释,比如:醫(yī)學(xué)圖像分析滤愕、前景檢測(cè)、字符識(shí)別怜校,形狀識(shí)別间影。二值化+數(shù)學(xué)形態(tài)學(xué)能解決很多計(jì)算機(jī)識(shí)別工程中目標(biāo)提取的問題。

開操作演示---文本分離與切割

開操作是先腐蝕后膨脹的過程茄茁。用來消除小物體魂贬、在纖細(xì)點(diǎn)處分離物體、平滑較大物體的邊界的同時(shí)并不明顯改變其面積裙顽。

跟開操作相對(duì)應(yīng)的是閉操作付燥。另外,腐蝕和膨脹在下文中有介紹愈犹。

cv4j 中键科,我們封裝好了這些形態(tài)學(xué)的常用操作,比如開閉操作漩怎、腐蝕和膨脹等等勋颖。

其中,開操作的代碼如下:

public class MorphOpen {
    /**
     * in order to remove litter noise block, erode + dilate operator
     *
     * @param binary
     * @param structureElement
     */
    public void process(ByteProcessor binary, Size structureElement) {
        Erode erode = new Erode();
        Dilate dilate = new Dilate();
        erode.process(binary, structureElement);
        dilate.process(binary, structureElement);
    }
}

先來看一個(gè)完整demo的效果圖


完整的demo效果.png

第三步如果看不太清楚勋锤,我們看一下放大的效果圖


放大第三步的操作.png

如上圖所示叁执,demo完成了文本的切割。我們來看看具體的代碼是怎么實(shí)現(xiàn)的谈宛。

準(zhǔn)備工作展示原圖

        Resources res = getResources();
        final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.test_binary1);
        image0.setImageBitmap(bitmap);

第一步二值化

        CV4JImage cv4JImage = new CV4JImage(bitmap);
        Threshold threshold = new Threshold();
        threshold.process((ByteProcessor)(cv4JImage.convert2Gray().getProcessor()),Threshold.THRESH_TRIANGLE,Threshold.METHOD_THRESH_BINARY_INV,255);
        image1.setImageBitmap(cv4JImage.getProcessor().getImage().toBitmap());

第二步開操作

MorphOpen morphOpen = new MorphOpen();
cv4JImage.resetBitmap();
morphOpen.process((ByteProcessor)cv4JImage.getProcessor(),new Size(5));

image2.setImageBitmap(cv4JImage.getProcessor().getImage().toBitmap());

第三步連通組件標(biāo)記

        ConnectedAreaLabel connectedAreaLabel = new ConnectedAreaLabel();
        byte[] mask = new byte[cv4JImage.getProcessor().getWidth() * cv4JImage.getProcessor().getHeight()];
        List<Rect> rectangles = new ArrayList<>();
        connectedAreaLabel.process((ByteProcessor)cv4JImage.getProcessor(),mask,rectangles,true);
        cv4JImage.resetBitmap();
        Bitmap newBitmap = cv4JImage.getProcessor().getImage().toBitmap();

        if (Preconditions.isNotBlank(rectangles)) {
            Tools.drawRects(newBitmap,rectangles);
        }

        image3.setImageBitmap(newBitmap);

其實(shí)次哈,做完第三步再結(jié)合ocr就可以識(shí)別出具體文字啦。如果再結(jié)合一下網(wǎng)絡(luò)爬蟲的話吆录,意義更大亿乳。

雖然, cv4j 目前還只是移動(dòng)端的庫,但是它畢竟是java開發(fā)的葛假,改成適合desktop的很容易。

腐蝕操作演示---硬幣計(jì)數(shù)

腐蝕操作是一種消除邊界點(diǎn)滋恬,使邊界向內(nèi)部收縮的過程聊训』致龋可以用來消除小且無意義的物體带斑。腐蝕操作掃描圖像的每一個(gè)像素勋磕,用結(jié)構(gòu)元素與其覆蓋的二值圖像做“與”操作:如果都為1,結(jié)果圖像的該像素為1敢靡,否則為0。

跟腐蝕操作相對(duì)的是膨脹操作啸胧。腐蝕用于分割獨(dú)立的圖像元素赶站,而膨脹用于連接相鄰的元素。

腐蝕的算法:


腐蝕操作.png

其中纺念,g(x,y)為腐蝕后的灰度圖像贝椿,f(x,y)為原灰度圖像烙博,B為結(jié)構(gòu)元素焙格。腐蝕運(yùn)算是由結(jié)構(gòu)元素確定的鄰域塊中選取圖像值與結(jié)構(gòu)元素值的差的最小值。

可以簡(jiǎn)化為:


簡(jiǎn)化的腐蝕操作.png

來看一個(gè)例子肝陪,原圖中有很多硬幣蹲堂,通過一步步的分析計(jì)算出硬幣的個(gè)數(shù)播聪。


硬幣計(jì)數(shù)1.png
硬幣計(jì)數(shù)2.png

準(zhǔn)備工作展示原圖

        Resources res = getResources();
        final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.test_coins);
        image0.setImageBitmap(bitmap);

第一步二值化

        CV4JImage cv4JImage = new CV4JImage(bitmap);
        Threshold threshold = new Threshold();
        threshold.process((ByteProcessor)(cv4JImage.convert2Gray().getProcessor()),Threshold.THRESH_OTSU,Threshold.METHOD_THRESH_BINARY_INV,255);
        image1.setImageBitmap(cv4JImage.getProcessor().getImage().toBitmap());

第二步腐蝕操作

        Erode erode = new Erode();
        cv4JImage.resetBitmap();
        erode.process((ByteProcessor)cv4JImage.getProcessor(),new Size(3),10);
        image2.setImageBitmap(cv4JImage.getProcessor().getImage().toBitmap());

第三步連通組件標(biāo)記

        ConnectedAreaLabel connectedAreaLabel = new ConnectedAreaLabel();
        byte[] mask = new byte[cv4JImage.getProcessor().getWidth() * cv4JImage.getProcessor().getHeight()];

        int num = connectedAreaLabel.process((ByteProcessor)cv4JImage.getProcessor(),mask,null,false); // 獲取連通組件的個(gè)數(shù)

        SparseIntArray colors = new SparseIntArray();
        Random random = new Random();

        int height = cv4JImage.getProcessor().getHeight();
        int width = cv4JImage.getProcessor().getWidth();
        int size = height * width;
        for (int i = 0;i<size;i++) {
            int c = mask[i] & 0xff;
            colors.put(c,Color.argb(255, random.nextInt(255),random.nextInt(255),random.nextInt(255)));
        }

        cv4JImage.resetBitmap();
        Bitmap newBitmap = cv4JImage.getProcessor().getImage().toBitmap();

        for(int row=0; row<height; row++) {
            for (int col = 0; col < width; col++) {

                int c = mask[row*width+col] & 0xff;
                if (c>0) {
                    newBitmap.setPixel(col,row,colors.get(c));
                }
            }
        }

        image3.setImageBitmap(newBitmap);

        if (num>0)
            numTextView.setText(String.format("總計(jì)識(shí)別出%d個(gè)硬幣",num));

最終獲取了連通組件的個(gè)數(shù)也就是硬幣的個(gè)數(shù)稼虎,并且在已經(jīng)識(shí)別的硬幣上隨機(jī)著色。

總結(jié)

cv4jgloomyfish和我一起開發(fā)的圖像處理庫计济,純java實(shí)現(xiàn)茸苇,目前還處于早期的版本。這周沦寂,我們開始做二值圖像的分析(腐蝕传藏、膨脹腻暮、開閉操作、輪廓提取等等)毯侦,這個(gè)模塊并沒有完成全部功能哭靖,預(yù)計(jì)下周能完工试幽。

先前的文章:
Java實(shí)現(xiàn)高斯模糊和圖像的空間卷積
Java實(shí)現(xiàn)圖片濾鏡的高級(jí)玩法
Java實(shí)現(xiàn)圖片的濾鏡效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市卦碾,隨后出現(xiàn)的幾起案子铺坞,更是在濱河造成了極大的恐慌,老刑警劉巖洲胖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件济榨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绿映,警方通過查閱死者的電腦和手機(jī)擒滑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門腐晾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丐一,你說我怎么就攤上這事藻糖。” “怎么了库车?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵颖御,是天一觀的道長。 經(jīng)常有香客問我凝颇,道長,這世上最難降的妖魔是什么疹鳄? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任拧略,我火速辦了婚禮,結(jié)果婚禮上瘪弓,老公的妹妹穿的比我還像新娘垫蛆。我一直安慰自己,他們只是感情好腺怯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布袱饭。 她就那樣靜靜地躺著,像睡著了一般呛占。 火紅的嫁衣襯著肌膚如雪虑乖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天晾虑,我揣著相機(jī)與錄音疹味,去河邊找鬼。 笑死帜篇,一個(gè)胖子當(dāng)著我的面吹牛糙捺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笙隙,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼洪灯,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了竟痰?” 一聲冷哼從身側(cè)響起签钩,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凯亮,沒想到半個(gè)月后边臼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡假消,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年柠并,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡臼予,死狀恐怖鸣戴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粘拾,我是刑警寧澤窄锅,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏潮梯。R本人自食惡果不足惜咱筛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸锋爪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽其骄。三九已至,卻和暖如春扯旷,著一層夾襖步出監(jiān)牢的瞬間拯爽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國打工薄霜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留某抓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓惰瓜,卻偏偏與公主長得像否副,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子崎坊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容