首页 > 其他分享 >.net 调用Open CV 寻找并读取单据条码

.net 调用Open CV 寻找并读取单据条码

时间:2023-09-07 16:02:23浏览次数:38  
标签:Open Image System Drawing new net grad CV Size

0、背景

公司物流和财务部门想要把纸质单据做电子归档,需要识别单据上的二维码,拍照后保存到归档系统。

1、软件模块

1、WPF客户端

对接高拍仪驱动,控制拍照

读取图片使用opencv 处理图片,寻找二维码块

使用二维码读取api 读取二维码内容

上传图片和二维码数据到服务器

2、webapi 后端

图片上传接口

数据查询保存接口

单据查询页面

2、open cv 代码C#-Emgu


        private void ShowBgrImage(System.Windows.Controls.Image oImage, Image<Bgr, byte> src)
        {
            this.Dispatcher.Invoke(() => {
                oImage.Source = BitmapSourceConvert.ToBitmapSource(src);
            });
        }


        private void ShowGrayImage(System.Windows.Controls.Image oImage, Image<Gray, byte> src)
        {
            this.Dispatcher.Invoke(() => {
                oImage.Source = BitmapSourceConvert.ToBitmapSource(src);
            });
        }

        public byte[] getImgByte(System.Drawing.Image image)
        {
            MemoryStream ms = new MemoryStream();
            try
            {
                image.Save(ms, ImageFormat.Bmp);
                byte[] bt = ms.GetBuffer();
                return bt;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                ms.Close();
            }
        }


        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            string sFile = AppDomain.CurrentDomain.BaseDirectory + "Test15.jpg";//"Test5.png";

            System.Drawing.Image img = System.Drawing.Image.FromFile(sFile);
            Bitmap barcodeBitmap = new Bitmap(img);
            
            Image<Bgr, byte> img_src = new Image<Bgr, byte>(barcodeBitmap);

            //1
            this.ShowBgrImage(this.Img1, img_src);

            //return;
            //灰度化2
            Image<Gray, byte> imput_gray = new Image<Gray, byte>(img_src.Size);
            CvInvoke.CvtColor(img_src, imput_gray, ColorConversion.Bgr2Gray);
            this.ShowGrayImage(this.Img2, imput_gray);


            //计算x,y方向梯度,相加 3
            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.Sobel(imput_gray, grad_x1, DepthType.Default, 0, 1, 3);
            CvInvoke.Sobel(imput_gray, grad_y1, DepthType.Default, 1, 0, 3);
            CvInvoke.Add(grad_x1, grad_y1, grad_all, null, DepthType.Default);
            this.ShowGrayImage(this.Img3, grad_all);
            
            // 高斯模糊 4
            grad_all = grad_all.SmoothGaussian(11);
            this.ShowGrayImage(this.Img4, grad_all);


            // 二值化 5
            CvInvoke.Threshold(grad_all, grad_all, 50, 255, ThresholdType.Binary);
            this.ShowGrayImage(this.Img5, grad_all);


            //消除裂缝 6
            Mat oMat1 = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle,
        new System.Drawing.Size(8, 8), new System.Drawing.Point(0, 0));
            CvInvoke.MorphologyEx(grad_all, grad_all, Emgu.CV.CvEnum.MorphOp.Close, oMat1,
              new System.Drawing.Point(0, 0), 1, BorderType.Default,
              new MCvScalar(255, 0, 0, 255));
            this.ShowGrayImage(this.Img6, grad_all);


            //膨胀与腐蚀(消除杂点)
            Mat oMat2 = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle,
       new System.Drawing.Size(20, 20), new System.Drawing.Point(0, 0));
            CvInvoke.Erode(grad_all, grad_all, oMat2, new System.Drawing.Point(0, 0), 4,
              BorderType.Default, new MCvScalar(255, 0, 0, 255));
            CvInvoke.Dilate(grad_all, grad_all, oMat2, new System.Drawing.Point(0, 0), 4,
              BorderType.Default, new MCvScalar(255, 0, 0, 255));
            this.ShowGrayImage(this.Img7, grad_all);


            //查找轮廓,绘制轮廓
            #region Find triangles and rectangles
            List<Triangle2DF> triangleList = new List<Triangle2DF>();
            List<RotatedRect> boxList = new List<RotatedRect>(); //a box is a rotated rectangle


            using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
            {
                CvInvoke.FindContours(grad_all, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
                int count = contours.Size;
                for (int i = 0; i < count; i++)
                {
                    using (VectorOfPoint contour = contours[i])
                    using (VectorOfPoint approxContour = new VectorOfPoint())
                    {
                        CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
                        if (CvInvoke.ContourArea(approxContour, false) > 500)
                        {
                            if (approxContour.Size == 3)
                            {
                                System.Drawing.Point[] pts = approxContour.ToArray();
                                triangleList.Add(new Triangle2DF(
                                 pts[0],
                                 pts[1],
                                 pts[2]
                                 ));
                            }
                            else if (approxContour.Size == 4)
                            {
                                #region determine if all the angles in the contour are within [80, 100] degree
                                bool isRectangle = true;
                                System.Drawing.Point[] pts = approxContour.ToArray();
                                LineSegment2D[] edges = Emgu.CV.PointCollection.PolyLine(pts, true);


                                for (int j = 0; j < edges.Length; j++)
                                {
                                    double angle = Math.Abs(
                                     edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
                                    if (angle < 80 || angle > 100)
                                    {
                                        isRectangle = false;
                                        break;
                                    }
                                }
                                #endregion

                                if (isRectangle)
                                {
                                    boxList.Add(CvInvoke.MinAreaRect(approxContour));
                                }
                            }
                        }
                    }
                }
            }
            
            this.Img8.Source = BitmapSourceConvert.ToBitmap(barcodeBitmap);
            //this.ShowGrayImage(this.Img8, grad_all);

            foreach (RotatedRect box in boxList)
            {
                if(box.Size.Width < 50 || box.Size.Height < 50)
                {//过滤小于50像素的块
                    continue;
                }
                if(box.Size.Width / box.Size.Height > 1.6 || box.Size.Height / box.Size.Width > 1.6)
                {//过滤长宽比例大于2的块
                    continue;
                }
                System.Drawing.Point[] pts = Array.ConvertAll(box.GetVertices(), System.Drawing.Point.Round);
                int x = 0, y = 0, length = 0, width = 0;
                List<int> xList = new List<int>();
                List<int> yList = new List<int>();
                for (int i = 0; i < pts.Length; i++)
                {
                    System.Drawing.Point point = pts[i];
                    System.Drawing.Point point1 = new System.Drawing.Point();
                    if (i == pts.Length - 1)
                        point1 = pts[0];
                    else
                        point1 = pts[i + 1];
                    
                    Line oLine = new Line();
                    oLine.Stroke = new SolidColorBrush(Colors.Red);
                    oLine.StrokeThickness = 2;
                    oLine.X1 = point.X;
                    oLine.Y1 = point.Y;
                    
                    oLine.X2 = point1.X;
                    oLine.Y2 = point1.Y;
                    this.CvMainZm.Children.Add(oLine);
                    xList.Add(point.X);
                    xList.Add(point1.X);
                    yList.Add(point.Y);
                    yList.Add(point1.Y);
                }
                
                x = xList.Min();
                y = yList.Min();
                length= xList.Max() - x;
                width = yList.Max() - y;
                TextBlock text = ReadQRCode(barcodeBitmap, x, y, length + 50, width + 50);
                if(text != null)
                {
                    //this.CvMainZm.Children.Add(text);
                    Console.WriteLine(text.Text);
                }
            }
            #endregion
        }

        TextBlock ReadQRCode(Bitmap srcImg, int x, int y, int length, int width)
        {
            if(length <= 1 || width <= 1)
            {
                return null;
            }

            Bitmap clipedImg = new Bitmap(length, width);

            System.Drawing.Rectangle srcRect = new System.Drawing.Rectangle(x, y, length, width);
            Graphics g = Graphics.FromImage(clipedImg);
            g.DrawImage(srcImg, 0, 0, srcRect, GraphicsUnit.Pixel);
            g.Dispose();
            ////分割结束

            ////读取分割后的二维码
            Image<Bgr, byte> img_src2 = new Image<Bgr, byte>(clipedImg);
            Image<Gray, byte> imput_gray2 = new Image<Gray, byte>(clipedImg.Size);
            CvInvoke.CvtColor(img_src2, imput_gray2, ColorConversion.Bgr2Gray);

            //截取的二维码需要高斯模糊处理一下值是奇数
            //如果是清晰的不要执行下面的2行
            imput_gray2 = Sharpen(imput_gray2, clipedImg.Width, clipedImg.Height, 3, 3, 1);
            imput_gray2 = imput_gray2.SmoothGaussian(5);

            this.ShowGrayImage(this.Img1, imput_gray2);
            Bitmap barcodeBitmap = new Bitmap(imput_gray2.ToBitmap());
            ZXing.BarcodeReader re = new ZXing.BarcodeReader();
            ZXing.Result result2 = re.Decode(barcodeBitmap);
            if(result2 != null)
            {
                MessageBox.Show(result2.Text);
            }
            //Zbar 读取二维码
            //Bitmap pImg = MakeGrayscale3((Bitmap)barcodeBitmap);
            using (ZBar.ImageScanner scanner = new ZBar.ImageScanner())
            {
                scanner.SetConfiguration(ZBar.SymbolType.None, ZBar.Config.Enable, 0);
                scanner.SetConfiguration(ZBar.SymbolType.CODE39, ZBar.Config.Enable, 1);
                scanner.SetConfiguration(ZBar.SymbolType.CODE128, ZBar.Config.Enable, 1);
                scanner.SetConfiguration(ZBar.SymbolType.QRCODE, ZBar.Config.Enable, 1);
                List<ZBar.Symbol> symbols = new List<ZBar.Symbol>();
                symbols = scanner.Scan((System.Drawing.Image)barcodeBitmap);

                if (symbols != null && symbols.Count > 0)
                {
                    string result = string.Empty;
                    symbols.ForEach(s => result += "条码内容:" + s.Data + " 条码质量:" + s.Quality + Environment.NewLine);
                    MessageBox.Show(result);
                }
            }

            string txtMsg = "";
            
            TextBlock tb = new TextBlock() { Text = txtMsg };
            tb.Foreground = System.Windows.Media.Brushes.Red;
            return tb;
        }

标签:Open,Image,System,Drawing,new,net,grad,CV,Size
From: https://blog.51cto.com/u_16249230/7398269

相关文章

  • HarmonyOS/OpenHarmony(Stage模型)应用开发组合手势(一)连续识别
    组合手势由多种单一手势组合而成,通过在GestureGroup中使用不同的GestureMode来声明该组合手势的类型,支持连续识别、并行识别和互斥识别三种类型。00001. GestureGroup(mode:GestureMode,...gesture:GestureType[])mode:必选参数,为GestureMode枚举类。用于声明该组合手势的类型。ge......
  • Kubernetes快速进阶与实战:构建可靠的容器化应用平台
    ......
  • net core读取配置节
    通过工具类 AppSettingsConfig services.AddSingleton(newAppSettingsConfig(configuration)); usingMicrosoft.Extensions.Configuration;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceXXXXX.Common{......
  • window.showModalDialog与window.open全屏显示
    搞了半天就是搞不出模式对话框的全屏显示,原来其与window.open的参数设置完全不同.functionwinModalFullScreen(strURL){varsheight=screen.height-70;varswidth=screen.width-10;varwinoption="dialogHeight:"+sheight+"px;dialogWidth:"+swidth+"px;status:ye......
  • IndexSearch中增量索引使用reopen
    publicIndexSearchernewIndexSearcher(){ try{ if(null==isearcher){ isearcher=newIndexSearcher(IndexReader.open("D:/Index")); }else{ IndexReaderindexReader=isearcher.getIndexReader();//获取当前的indexReader if(!in......
  • cv2.error: Unknown C++ exception from OpenCV code.报错解决
    问题原因:opencv版本太高,python版本太低解决办法:打开opencv下载网站找到自己的python版本对应的opencv的版本,然后通过下面代码安装pipinstallopencv-python==4.1.2.30-ihttps://pypi.tuna.tsinghua.edu.cn/simple ......
  • .NET Core 在其上下文中,该请求的地址无效。
    .NETCore在其上下文中,该请求的地址无效。看了端口,发现没被占用,后来发现是IP地址变了改成正确的IP就可以了。......
  • 浅述视频监控平台EasyCVR监控汇聚平台可视化安全管理在生产工作中的重要性
    EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,在视频监控播放上,视频云存储/安防监控汇聚平台可支持1、4、9、16个画面窗口播放,可同时播放多路视频流,也能支持视频定时轮播。视频监控汇聚平台EasyCVR支持多种播放协议,包括:HLS、HTTP-FLV、WebSocket-......
  • kubeadm部署kubernetes+harbor
    kubeadm部署kubernetes+harbor架构图 安装步骤1、在所有节点上安装Docker和kubeadm2、部署KubernetesMaster3、部署容器网络插件4、部署KubernetesNode,将节点加入Kubernetes集群中5、部署DashboardWeb页面,可视化查看Kubernetes资源6、部署Har......
  • OpenMLDB 基于 Kubernetes 的部署全攻略
    简介Kubernetes作为当前工业界流行的云原生容器编排和管理工具,在大量项目实践中被使用。目前,OpenMLDB的离线引擎和在线引擎,均已经完整支持了基于Kubernetes的部署,可以实现更为方便的管理功能。本文将分别介绍离线和在线引擎基于Kubernetes的部署攻略。注意,离线和在线引擎......