圖像中二維碼的檢測(cè)和定位

二維碼

二維條碼/二維碼(2-dimensional bar code)是用某種特定的幾何圖形按一定規(guī)律在平面(二維方向上)分布的黑白相間的圖形記錄數(shù)據(jù)符號(hào)信息的孩饼;在代碼編制上巧妙地利用構(gòu)成計(jì)算機(jī)內(nèi)部邏輯基礎(chǔ)的“0”、“1”比特流的概念竹挡,使用若干個(gè)與二進(jìn)制相對(duì)應(yīng)的幾何形體來(lái)表示文字?jǐn)?shù)值信息镀娶,通過(guò)圖象輸入設(shè)備或光電掃描設(shè)備自動(dòng)識(shí)讀以實(shí)現(xiàn)信息自動(dòng)處理:它具有條碼技術(shù)的一些共性:每種碼制有其特定的字符集;每個(gè)字符占有一定的寬度揪罕;具有一定的校驗(yàn)功能等梯码。同時(shí)還具有對(duì)不同行的信息自動(dòng)識(shí)別功能、及處理圖形旋轉(zhuǎn)變化點(diǎn)好啰。

QR-Code-Overview.jpeg

定位圖案

  • Position Detection Pattern是定位圖案轩娶,用于標(biāo)記二維碼的矩形大小冒晰。這三個(gè)定位圖案有白邊叫Separators for Postion Detection Patterns庆捺。之所以三個(gè)而不是四個(gè)意思就是三個(gè)就可以標(biāo)識(shí)一個(gè)矩形了寄狼。
  • Timing Patterns也是用于定位的厚宰。原因是二維碼有40種尺寸,尺寸過(guò)大了后需要有根標(biāo)準(zhǔn)線涌庭,不然掃描的時(shí)候可能會(huì)掃歪了嚼隘。
  • Alignment Patterns 只有Version 2以上(包括Version2)的二維碼需要這個(gè)東東保屯,同樣是為了定位用的秉版。

通過(guò)查找定位圖案贤重,可以實(shí)現(xiàn)二維碼掃描的檢測(cè)和定位。

檢測(cè)和定位的步驟

先對(duì)圖片進(jìn)行灰度處理:

image = image.getImage().convert2Gray().getProcessor();
ByteProcessor src = ((ByteProcessor)image);

再對(duì)圖像做二值化處理:

Threshold t = new Threshold();
t.process(src, Threshold.THRESH_OTSU, Threshold.METHOD_THRESH_BINARY_INV, 20);

然后是對(duì)y清焕、x方向進(jìn)行形態(tài)學(xué)上的開(kāi)操作

        MorphOpen mOpen = new MorphOpen();
        byte[] data = new byte[width*height];
        System.arraycopy(src.getGray(), 0, data, 0, data.length);
        ByteProcessor copy = new ByteProcessor(data, width, height);
        mOpen.process(src, new Size(n1, n2)); // Y方向開(kāi)操作
        src.getImage().resetBitmap();

        mOpen.process(copy, new Size(n2, n1)); // X方向開(kāi)操作
        CV4JImage cv4JImage = new CV4JImage(width,height);
        ((ByteProcessor)cv4JImage.getProcessor()).putGray(copy.getGray());

所謂開(kāi)操作是指先腐蝕后膨脹的操作并蝗。在之前的文章二值圖像分析:案例實(shí)戰(zhàn)(文本分離+硬幣計(jì)數(shù))曾經(jīng)介紹過(guò)開(kāi)操作的用途。

import com.cv4j.core.datamodel.ByteProcessor;
import com.cv4j.core.datamodel.Size;

public class MorphOpen {

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

接下來(lái)是標(biāo)記聯(lián)通區(qū)域秸妥,找到二維碼的三個(gè)特征區(qū)域滚停,也就是定位圖案。

        // 聯(lián)通組件查找連接區(qū)域
        ConnectedAreaLabel ccal = new ConnectedAreaLabel();
        ccal.setFilterNoise(true);
        List<Rect> rectList = new ArrayList<>();
        int[] labelMask = new int[width*height];
        ccal.process(src, labelMask, rectList, true);
        float w = 0;
        float h = 0;
        float rate = 0;
        List<Rect> qrRects = new ArrayList<>();
        for(Rect roi : rectList) {

            if (roi == null) continue;

            if((roi.width > width/4 || roi .width < 10) || (roi.height < 10 || roi.height > height/4))
                continue;

            if((roi.x < 10 || roi.x > width -10)|| (roi.y < 10 || roi.y > height-10))
                continue;

            w = roi.width;
            h = roi.height;
            rate = (float)Math.abs(w / h  - 1.0);
            if(rate < 0.05 && isRect(roi, labelMask, width, height,true)) {
                qrRects.add(roi);
            }
        }

最后粥惧,通過(guò)定位圖案能夠找到二維碼所在的區(qū)域键畴,如果找不到會(huì)返回空的矩形。否則返回一個(gè)Rect影晓,它表示找到的二維碼所在圖像中的區(qū)域。

我們可以對(duì)該區(qū)域進(jìn)行標(biāo)識(shí)檩禾,下面是算法的具體使用挂签,找到圖像中的二維碼之后,用紅色的邊框框起來(lái)盼产。

        CV4JImage cv4JImage = new CV4JImage(bitmap);

        QRCodeScanner qrCodeScanner = new QRCodeScanner();
        Rect rect = qrCodeScanner.findQRCodeBounding(cv4JImage.getProcessor(),1,6);

        Bitmap bm = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        Canvas canvas = new Canvas(bm);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth((float) 10.0);
        paint.setStyle(Paint.Style.STROKE);

        android.graphics.Rect androidRect = new android.graphics.Rect(rect.x-20,rect.y-20,rect.br().x+20,rect.br().y+20);
        canvas.drawRect(androidRect,paint);
        image.setImageBitmap(bm);
定位圖片中的二維碼區(qū)域.png
定位有創(chuàng)意的二維碼.png
截圖微信的二維碼.png

對(duì)于iPhone截屏之后的圖片饵婆,該圖片尺寸是1242?×?2208。在沒(méi)有對(duì)圖片做任何縮放處理的情況下戏售,使用該算法進(jìn)行定位二維碼的區(qū)域也是ok的侨核。


大圖中的二維碼.png

當(dāng)然草穆,對(duì)于大圖如果適當(dāng)?shù)亟挡蓸犹幚砘蛘呖s放的話,算法速度會(huì)更快搓译。

寫(xiě)在最后

彩色二維碼和小程序的圓形二維碼目前能夠檢測(cè)嗎悲柱?
暫時(shí)不能。因?yàn)閳D像在二值化之后些己,彩色的部分像素點(diǎn)會(huì)變成白色的像素點(diǎn)豌鸡,導(dǎo)致二維碼輪廓不完整,最終導(dǎo)致無(wú)法實(shí)現(xiàn)二值分析段标。我們會(huì)在完成模版匹配的功能之后涯冠,繼續(xù)優(yōu)化算法完善該功能,加上檢測(cè)彩色和圓形二維碼的能力逼庞。

算法的源碼位于cv4jQRCodeScanner中蛇更,該算法不能識(shí)別二維碼的字符串,只能找到二維碼的區(qū)域赛糟,如果需要識(shí)別二維碼還是需要使用Google Zxing派任。

總結(jié)

cv4jgloomyfish和我一起開(kāi)發(fā)的圖像處理庫(kù),純java實(shí)現(xiàn)虑灰,目前還處于早期的版本吨瞎。

文章中的算法是對(duì)二值圖像分析的綜合運(yùn)用,使用它再結(jié)合Google的ZXing能夠提高二維碼的識(shí)別率穆咐。當(dāng)然颤诀,由于它是pure java實(shí)現(xiàn)的,稍作改動(dòng)能夠用它來(lái)判斷出某張圖片中是否包含有二維碼对湃。

如果您想看該系列先前的文章可以訪問(wèn)下面的文集:
http://www.reibang.com/nb/10401400

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末崖叫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拍柒,更是在濱河造成了極大的恐慌心傀,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拆讯,死亡現(xiàn)場(chǎng)離奇詭異脂男,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)种呐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)宰翅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人爽室,你說(shuō)我怎么就攤上這事汁讼。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵嘿架,是天一觀的道長(zhǎng)瓶珊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)耸彪,這世上最難降的妖魔是什么伞芹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮搜囱,結(jié)果婚禮上丑瞧,老公的妹妹穿的比我還像新娘。我一直安慰自己蜀肘,他們只是感情好绊汹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著扮宠,像睡著了一般西乖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坛增,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天获雕,我揣著相機(jī)與錄音,去河邊找鬼收捣。 笑死届案,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罢艾。 我是一名探鬼主播楣颠,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼咐蚯!你這毒婦竟也來(lái)了童漩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤春锋,失蹤者是張志新(化名)和其女友劉穎矫膨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體期奔,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侧馅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呐萌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馁痴。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖搁胆,靈堂內(nèi)的尸體忽然破棺而出弥搞,到底是詐尸還是另有隱情,我是刑警寧澤渠旁,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布攀例,位于F島的核電站,受9級(jí)特大地震影響顾腊,放射性物質(zhì)發(fā)生泄漏粤铭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一杂靶、第九天 我趴在偏房一處隱蔽的房頂上張望梆惯。 院中可真熱鬧,春花似錦吗垮、人聲如沸垛吗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)怯屉。三九已至,卻和暖如春饵沧,著一層夾襖步出監(jiān)牢的瞬間锨络,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工狼牺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留羡儿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓是钥,卻偏偏與公主長(zhǎng)得像掠归,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咏瑟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

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

  • 不同圖像灰度不同拂到,邊界處一般會(huì)有明顯的邊緣,利用此特征可以分割圖像码泞。需要說(shuō)明的是:邊緣和物體間的邊界并不等同兄旬,邊緣...
    大川無(wú)敵閱讀 13,868評(píng)論 0 29
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,298評(píng)論 25 707
  • 7.已知矩形長(zhǎng)a,寬b,輸出其面積和周長(zhǎng),面積和周長(zhǎng)以一個(gè)空格隔開(kāi)解法一:直接法 解法二:格式化字符串
    everfight閱讀 333評(píng)論 0 0
  • 我想余寥,我的大學(xué)里最難過(guò)的一段時(shí)光莫過(guò)于大三下學(xué)期领铐。我不知道如果大三下的你是不是也跟我一樣有同樣的感受∷蜗希看似很多的選...
    愛(ài)迷路的火龍果閱讀 407評(píng)論 4 0
  • 1绪撵、二進(jìn)制轉(zhuǎn)十六進(jìn)制 四位二進(jìn)制表示一位十六進(jìn)制,先把四位二進(jìn)制轉(zhuǎn)成十進(jìn)制祝蝠,再轉(zhuǎn)成十六進(jìn)制eg:10110110=...
    陳志龍閱讀 431評(píng)論 0 0