c# EmguCv定位二維碼

c# EmguCv定位二維碼

http://blog.csdn.net/gaobobo138968/article/details/47663607

Emgu 和opencv一樣,用opencv寫的程序當然也可以“翻譯”爲Emgu版,這裏展示一個demo,使用Emgu定位圖片中的二維碼。

1.載入圖像

System.Drawing.Image img = System.Drawing.Image.FromFile("E:\\code.jpg");
Bitmap barcodeBitmap = new Bitmap(img);
Image<Bgr, byte> img_src = new Image<Bgr, byte>(barcodeBitmap );

2.轉爲灰度圖

Image<Gray, byte> imput_gray = new Image<Gray, byte>(img_src.Size);
CvInvoke.cvCvtColor(img_src, imput_gray, COLOR_CONVERSION.BGR2GRAY);

3.計算x,y方向梯度,相加

        Image<Gray, byte> grad_x1 = new Image<Gray, byte>(img_src.Size); 
        Image<Gray, byte> grad_y1 = new Image<Gray, byte>(img_src.Size);
        Image<Gray, byte> grad_all = new Image<Gray, byte>(img_src.Size);
        CvInvoke.cvSobel(imput_gray, grad_x1, 0, 1,3);
        CvInvoke.cvSobel(imput_gray, grad_y1, 1, 0, 3);
        CvInvoke.cvAdd(grad_x1, grad_y1, grad_all, IntPtr.Zero);

梯度圖:
這裏寫圖片描述

4.平均模糊

//平均模糊(9*9內核大小)
CvInvoke.cvSmooth(grad_all, grad_all, SMOOTH_TYPE.CV_BLUR, 9, 9,0,0);
CvInvoke.cvShowImage("平均模糊", grad_all);

平均模糊結果:
這裏寫圖片描述

5.二值化

CvInvoke.cvThreshold(grad_all, grad_all, 100, 255, THRESH.CV_THRESH_BINARY);
CvInvoke.cvShowImage("二值化", grad_all);

二值化圖片:
這裏寫圖片描述

6.消除裂縫

StructuringElementEx element = new StructuringElementEx( 21, 21,0, 0, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT );
CvInvoke.cvMorphologyEx( grad_all, grad_all, IntPtr.Zero, element, CV_MORPH_OP.CV_MOP_CLOSE, 1 );
CvInvoke.cvShowImage("消除裂縫", grad_all);

圖片結果:
這裏寫圖片描述

7.膨脹與腐蝕(消除雜點)

StructuringElementEx element1 = new StructuringElementEx(5, 5, 0, 0, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT);
CvInvoke.cvErode(grad_all, grad_all, element1, 4);
CvInvoke.cvDilate(grad_all, grad_all, element1, 4);
CvInvoke.cvShowImage("膨脹與腐蝕", grad_all); 

結果:
這裏寫圖片描述

8.查找輪廓,繪製輪廓

        IntPtr mem_storage = CvInvoke.cvCreateMemStorage(0);
        MCvSeq first_contour = new MCvSeq();
        IntPtr Dyncontour = new IntPtr();//存放檢測到的圖像塊的首地址
        CvInvoke.cvFindContours(grad_all, mem_storage, ref Dyncontour, 
            StructSize.MCvContour, 
            Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_EXTERNAL, 
            Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE, 
            new Point(0, 0));
        IntPtr temp = first_contour.ptr;
        Seq<Point> DyncontourTemp1 = new Seq<Point>(Dyncontour, null);//方便對IntPtr類型進行操作
        Seq<Point> DyncontourTemp = DyncontourTemp1;
        for (; DyncontourTemp1 != null && DyncontourTemp1.Ptr.ToInt32() != 0; DyncontourTemp1 = DyncontourTemp1.HNext)
        {
            Rectangle rect = CvInvoke.cvBoundingRect(DyncontourTemp1, true);
            if (rect.Width > 20 && rect.Height > 20)
            {
                rect.Width += 50;
                rect.Height += 50;
                Point p1 = new Point(rect.X, rect.Y);
                Point p2 = new Point(rect.X + rect.Width, rect.Y + rect.Height);
                CvInvoke.cvRectangle(img_src, p1, p2, new MCvScalar(0, 0, 255), 2, Emgu.CV.CvEnum.LINE_TYPE.EIGHT_CONNECTED, 0);
            }
        }

最後的結果:
這裏寫圖片描述

9.最後

從上圖可以看出找到了其中兩個二維碼,但是多了一個輪廓,不過定位二維碼的主要功能就是用於識別,識別不出來的定位塊自然也就沒有用了。如果定位一維碼(水平或垂直方向),即兩個方向梯度相減,效果也不錯。當然,這種定位方法會出現這樣一些不必要的小框,是不是可以通過大小再過濾一次呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章