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