OPENCV條碼檢測與識別

來源:互聯網
上載者:User

標籤:

  條碼是當前超市和部分工廠使用比較普遍的物品,產品標識技術,使用網路攝影機檢測一張圖片的條碼包含有兩個步驟,第一是定位條碼的位置,定位之後剪下出條碼,並且識別出條碼對應的字串,然後就可以調用網路,資料庫等手段快速進行後續處理.

      條碼識別要考慮到條碼的特點,本文針對的是條碼在圖片中的位置相對垂直,沒有各種傾斜的那種條碼,如所示

 

要定位首先要檢視這種條碼的特點,這種映像在X方向上的梯度肯定很明顯,同時,Y方向的梯度就沒這麼明顯,所以第一步,我們應該將映像的灰階映像分別計算梯度,用X方向梯度減去Y方向梯度,這樣可以保留X方向特徵並且去除Y方向的幹擾,處理之後映像如下所示

可以看到,二維碼對一維碼的定位形成了幹擾,但是二維碼的空間漏洞相對一維碼多很懂,於是我們考慮進行一次模糊並且二值化,看能不能有所效果,如下(記得調整相應的模糊化參數和閾值參數,得到相對最好的結果)

有一定的效果,但是此時又出現問題條碼出現了黑色的縫隙,不利於定位完整地區,這個時候要進行一些形態學操作,去除黑色縫隙,我們選擇閉運算,運算元根據縫隙的情況,寬度大於高度,矩形縫隙.處理以後的結果.

效果可以,又出現問題,二維碼的地區連著,還是面積很大,對後面我們算地區面積依然有影響,但是我們觀測二維碼的串連地區明顯要比一維碼的串連地區要細很多,也就是說,我們可以很快的腐蝕斷二維碼的串連,同時還保持一維碼的串連,然後在膨脹回來,二維碼的串連斷開就應該不會有這個大塊的地區連著了,注意,膨脹和腐蝕的次數應當是一致的,保證得到結果地區的準確.我選擇膨脹腐蝕四次,先膨脹斷開二維碼串連,最後的結果顯示如下

此時,二維碼的影響就基本沒有了,現在我們只需要先尋找輪廓,然後計算映像中每個輪廓的面積,選出面積最大的那個輪廓,計算這個輪廓的最小外包矩形,就能找到相應的映像地區了.這樣操作的結果和切分出來的條碼如下所示

到目前為止,我們已經完成了條碼的位置定位,並且剪下出了條碼的團,接下裡對這個圖案進行識別,識別之前,總結一下

  1. 形態學梯度運算,忽略Y方向梯度,著眼於X方向梯度
  2. 映像模糊化,為了便於後期的映像串連
  3. 映像求閾值,加速演算法處理,併合理使用模糊化的效果
  4. 形態學去除黑洞,閉運算
  5. 膨脹腐蝕,斷開二維碼串連
  6. 尋找輪廓,計算輪廓最大面積,擬合輪廓矩形,得到最終結果

接下來條碼識別,可以使用zbar識別庫,庫的簡介就不說了,可以自己去官網下載,安裝時候記得選上第三個選項,否則沒有標頭檔.

安裝完成後,到安裝目錄,將bin目錄加入環境變數,在VS中VC++目錄的include中加入標頭檔地址,lib地址,並加入lib名稱(連接器-輸入-附加依賴項),然後就可以使用了,具體使用查看下面的代碼,結果如下

代碼如下

#include <opencv2/opencv.hpp>#include <iostream>#include <zbar.h>using namespace cv;using namespace std;using namespace zbar;int main(int argc,char* argv[]){    char fileNameString[100];    char windowNameString[50];    char resultFileNameSring[100];    Mat srcImage,grayImage,blurImage,thresholdImage,gradientXImage,gradientYImage,gradientImage,morphImage;    for (int fileCount = 1;fileCount < 8;fileCount++)    {        sprintf(fileNameString,"F:\\opencv\\條碼檢測與識別\\barcode_0%d.jpg",fileCount);        sprintf(windowNameString,"result 0%d",fileCount);        sprintf(resultFileNameSring,"F:\\opencv\\條碼檢測與識別\\barcodeResult_0%d.jpg",fileCount);        //讀取映像        srcImage = imread(fileNameString);        if(srcImage.empty())        {            cout<<"image file read error"<<endl;            return -1;        }        //映像轉換為灰階映像        if(srcImage.channels() == 3)        {            cvtColor(srcImage,grayImage,CV_RGB2GRAY);        }        else        {            grayImage = srcImage.clone();        }        //建立映像的梯度幅值        Scharr(grayImage,gradientXImage,CV_32F,1,0);        Scharr(grayImage,gradientYImage,CV_32F,0,1);        //因為我們需要的條碼在需要X方向水平,所以更多的關注X方向的梯度幅值,而省略掉Y方向的梯度幅值        subtract(gradientXImage,gradientYImage,gradientImage);        //歸一化為八位元影像像        convertScaleAbs(gradientImage,gradientImage);        //看看得到的梯度映像是什麼樣子        //imshow(windowNameString,gradientImage);        //對圖片進行相應的模糊化,使一些噪點消除        blur(gradientImage,blurImage,Size(9,9));        //模糊化以後進行閾值化,得到到對應的黑白二值化映像,二值化的閾值可以根據實際情況調整        threshold(blurImage,thresholdImage,210,255,THRESH_BINARY);        //看看二值化映像        //imshow(windowNameString,thresholdImage);        //二值化以後的映像,條碼之間的黑白沒有串連起來,就要進行形態學運算,消除縫隙,相當於小型的黑洞,選擇閉運算        //因為是長條之間的縫隙,所以需要選擇寬度大於長度        Mat kernel = getStructuringElement(MORPH_RECT,Size(21,7));        morphologyEx(thresholdImage,morphImage,MORPH_CLOSE,kernel);        //看看形態學操作以後的映像        //imshow(windowNameString,morphImage);        //現在要讓條碼地區串連在一起,所以選擇膨脹腐蝕,而且為了保持圖形大小基本不變,應該使用相同次數的膨脹腐蝕        //先腐蝕,讓其他地區的亮的地方變少最好是消除,然後膨脹回來,消除幹擾,迭代次數根據實際情況選擇        erode(morphImage, morphImage, getStructuringElement(MORPH_RECT, Size(3,3)),Point(-1,-1),4);        dilate(morphImage, morphImage, getStructuringElement(MORPH_RECT, Size(3,3)),Point(-1,-1),4);        //看看形態學操作以後的映像        //imshow(windowNameString,morphImage);        vector<vector<Point2i>>contours;        vector<float>contourArea;        //接下來對目標輪廓進行尋找,目標是為了計算映像面積        findContours(morphImage,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);        //計算輪廓的面積並且存放        for(int i = 0; i < contours.size();i++)        {            contourArea.push_back(cv::contourArea(contours[i]));        }        //找出面積最大的輪廓        double maxValue;Point maxLoc;        minMaxLoc(contourArea, NULL,&maxValue,NULL,&maxLoc);        //計算面積最大的輪廓的最小的外包矩形        RotatedRect minRect = minAreaRect(contours[maxLoc.x]);        //為了防止找錯,要檢查這個矩形的偏斜角度不能超標        //如果超標,那就是沒找到        if(minRect.angle<2.0)        {            //找到了矩形的角度,但是這是一個旋轉矩形,所以還要重新獲得一個外包最小矩形            Rect myRect = boundingRect(contours[maxLoc.x]);            //把這個矩形在源映像中畫出來            //rectangle(srcImage,myRect,Scalar(0,255,255),3,LINE_AA);            //看看顯示效果,找的對不對            //imshow(windowNameString,srcImage);            //將掃描的映像裁剪下來,並儲存為相應的結果,保留一些X方向的邊界,所以對rect進行一定的擴張             myRect.x= myRect.x - (myRect.width/20);             myRect.width = myRect.width*1.1;            Mat resultImage = Mat(srcImage,myRect);            if(!imwrite(resultFileNameSring,resultImage))            {                cout<<"file save error!"<<endl;                return -2;            }        }    }    //檢測到了之後進行條碼識別    FileStorage file("F:\\opencv\\條碼檢測與識別\\result.xml",FileStorage::WRITE);    for (int fileCount = 1;fileCount < 8;fileCount++)    {        sprintf(resultFileNameSring,"F:\\opencv\\條碼檢測與識別\\barcodeResult_0%d.jpg",fileCount);        sprintf(windowNameString,"result 0%d",fileCount);        Mat result = imread(resultFileNameSring);        if(!result.empty())        {            //現在開始識別            cvtColor(result,grayImage,CV_RGB2GRAY);            int width = grayImage.cols;   // extract dimensions            int height = grayImage.rows;            Image image(width,height,"Y800",grayImage.data,width*height);            ImageScanner scanner;            scanner.set_config(ZBAR_NONE,ZBAR_CFG_ENABLE,1);            int n = scanner.scan(image);            for (Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end();++symbol)            {                cout <<"pic name:\t"<<resultFileNameSring<<endl<<"code type:\t"<<symbol->get_type_name()<<endl<<                    "decode string:\t"<<symbol->get_data()<<endl;                image.set_data(NULL,0);                //xml檔案寫入            }        }    }    waitKey(0);    return 1;}

資源如下

http://download.csdn.net/detail/dengrengong/9461797

 

OPENCV條碼檢測與識別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.