C# Onnx DBNet 检测条形码

效果

项目

代码

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Onnx_Demo
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";
        string startupPath;
        string model_path;

        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;

        Mat image;
        Mat result_image;

        SessionOptions options;
        InferenceSession onnx_session;
        Tensor<float> input_tensor;
        List<NamedOnnxValue> input_ontainer;
        IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
        DisposableNamedOnnxValue[] results_onnxvalue;

        StringBuilder sb = new StringBuilder();

        float binaryThreshold = 0.5f;
        float polygonThreshold = 0.7f;
        float unclipRatio = 1.5f;
        int maxCandidates = 1000;

        float[] mean = { 0.485f, 0.456f, 0.406f };
        float[] std = { 0.229f, 0.224f, 0.225f };

        int inpWidth = 736;
        int inpHeight = 736;

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;

            pictureBox1.Image = null;
            pictureBox2.Image = null;
            textBox1.Text = "";

            image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(image_path);
            image = new Mat(image_path);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            startupPath = Application.StartupPath + "\\model\\";

            model_path = startupPath + "model_0.88_depoly.onnx";

            // 创建输出会话
            options = new SessionOptions();
            options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;
            options.AppendExecutionProvider_CPU(0);// 设置为CPU上运行

            // 创建推理模型类,读取本地模型文件
            onnx_session = new InferenceSession(model_path, options);

            // 输入Tensor
            input_tensor = new DenseTensor<float>(new[] { 1, 3, inpHeight, inpWidth });

            // 创建输入容器
            input_ontainer = new List<NamedOnnxValue>();

        }

        float ContourScore(Mat binary, OpenCvSharp.Point[] contour)
        {
            Rect rect = Cv2.BoundingRect(contour);
            int xmin = Math.Max(rect.X, 0);
            int xmax = Math.Min(rect.X + rect.Width, binary.Cols - 1);
            int ymin = Math.Max(rect.Y, 0);
            int ymax = Math.Min(rect.Y + rect.Height, binary.Rows - 1);

            Mat binROI = new Mat(binary, new Rect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1));

            Mat mask = Mat.Zeros(new OpenCvSharp.Size(xmax - xmin + 1, ymax - ymin + 1), MatType.CV_8UC1);

            List<OpenCvSharp.Point> roiContour = new List<OpenCvSharp.Point>();

            foreach (var item in contour)
            {
                OpenCvSharp.Point pt = new OpenCvSharp.Point(item.X - xmin, item.Y - ymin);
                roiContour.Add(pt);
            }

            List<List<OpenCvSharp.Point>> roiContours = new List<List<OpenCvSharp.Point>>
            {
                roiContour
            };

            Cv2.FillPoly(mask, roiContours, new Scalar(1));

            float score = (float)Cv2.Mean(binROI)[0];

            return score;
        }

        void Unclip(List<Point2f> inPoly, List<Point2f> outPoly)
        {
            float area = (float)Cv2.ContourArea(inPoly);
            float length = (float)Cv2.ArcLength(inPoly, true);
            float distance = area * unclipRatio / length;

            int numPoints = inPoly.Count();
            List<List<Point2f>> newLines = new List<List<Point2f>>();
            for (int i = 0; i < numPoints; i++)
            {
                List<Point2f> newLine = new List<Point2f>();
                OpenCvSharp.Point pt1 = (OpenCvSharp.Point)inPoly[i];
                int index = (i - 1) % numPoints;
                if (index <= 0) index = 0;
                OpenCvSharp.Point pt2 = (OpenCvSharp.Point)inPoly[index];
                OpenCvSharp.Point vec = pt1 - pt2;

                Mat mat_vec = new Mat(1, 2, MatType.CV_8U, new int[] { vec.X, vec.Y });
                float unclipDis = (float)(distance / Cv2.Norm(mat_vec));

                Point2f rotateVec = new Point2f(vec.Y * unclipDis, -vec.X * unclipDis);
                newLine.Add(new Point2f(pt1.X + rotateVec.X, pt1.Y + rotateVec.Y));
                newLine.Add(new Point2f(pt2.X + rotateVec.X, pt2.Y + rotateVec.Y));
                newLines.Add(newLine);
            }

            int numLines = newLines.Count();
            for (int i = 0; i < numLines; i++)
            {
                Point2f a = newLines[i][0];
                Point2f b = newLines[i][1];
                Point2f c = newLines[(i + 1) % numLines][0];
                Point2f d = newLines[(i + 1) % numLines][1];
                Point2f pt;
                Point2f v1 = b - a;
                Point2f v2 = d - c;

                Mat mat_v1 = new Mat(1, 2, MatType.CV_32FC1, new float[] { v1.X, v1.Y });
                Mat mat_v2 = new Mat(1, 2, MatType.CV_32FC1, new float[] { v2.X, v2.Y });
                float cosAngle = (float)((v1.X * v2.X + v1.Y * v2.Y) / (Cv2.Norm(mat_v1) * Cv2.Norm(mat_v2)));

                if (Math.Abs(cosAngle) > 0.7)
                {
                    pt.X = (float)((b.X + c.X) * 0.5);
                    pt.Y = (float)((b.Y + c.Y) * 0.5);
                }
                else
                {
                    float denom = a.X * (float)(d.Y - c.Y) + b.X * (float)(c.Y - d.Y) +
                                  d.X * (float)(b.Y - a.Y) + c.X * (float)(a.Y - b.Y);
                    float num = a.X * (float)(d.Y - c.Y) + c.X * (float)(a.Y - d.Y) + d.X * (float)(c.Y - a.Y);
                    float s = num / denom;

                    pt.X = a.X + s * (b.X - a.X);
                    pt.Y = a.Y + s * (b.Y - a.Y);
                }
                outPoly.Add(pt);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }
            textBox1.Text = "检测中,请稍等……";
            pictureBox2.Image = null;
            Application.DoEvents();

            //图片
            image = new Mat(image_path);

            //将图片转为RGB通道
            Mat image_rgb = new Mat();
            Cv2.CvtColor(image, image_rgb, ColorConversionCodes.BGR2RGB);

            Mat resize_image = new Mat();
            Cv2.Resize(image_rgb, resize_image, new OpenCvSharp.Size(inpHeight, inpWidth));

            //输入Tensor
            for (int y = 0; y < resize_image.Height; y++)
            {
                for (int x = 0; x < resize_image.Width; x++)
                {
                    input_tensor[0, 0, y, x] = (resize_image.At<Vec3b>(y, x)[0] / 255f - mean[0]) / std[0];
                    input_tensor[0, 1, y, x] = (resize_image.At<Vec3b>(y, x)[1] / 255f - mean[1]) / std[1];
                    input_tensor[0, 2, y, x] = (resize_image.At<Vec3b>(y, x)[2] / 255f - mean[2]) / std[2];
                }
            }

            //将 input_tensor 放入一个输入参数的容器,并指定名称
            input_ontainer.Add(NamedOnnxValue.CreateFromTensor("input", input_tensor));

            dt1 = DateTime.Now;
            //运行 Inference 并获取结果
            result_infer = onnx_session.Run(input_ontainer);
            dt2 = DateTime.Now;

            //将输出结果转为DisposableNamedOnnxValue数组
            results_onnxvalue = result_infer.ToArray();

            var result_array = results_onnxvalue[0].AsTensor<float>().ToArray();

            Mat binary = new Mat(resize_image.Rows, resize_image.Cols, MatType.CV_32FC1, result_array);

            // threshold
            Mat threshold = new Mat();
            Cv2.Threshold(binary, threshold, binaryThreshold, 255, ThresholdTypes.Binary);

            Cv2.ImShow("threshold", threshold);

            int h = image.Rows;
            int w = image.Cols;
            float scaleHeight = (float)(h) / (float)(binary.Size(0));
            float scaleWidth = (float)(w) / (float)(binary.Size(1));

            threshold.ConvertTo(threshold, MatType.CV_8UC1);

            // Find contours
            OpenCvSharp.Point[][] contours;
            HierarchyIndex[] hierarchly;

            Cv2.FindContours(threshold, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);

            // Candidate number limitation
            int numCandidate = Math.Min(contours.Count(), maxCandidates > 0 ? maxCandidates : int.MaxValue);

            List<List<Point2f>> results = new List<List<Point2f>>();

            for (int i = 0; i < numCandidate; i++)
            {
                OpenCvSharp.Point[] contour = contours[i];

                // Calculate text contour score
                if (ContourScore(binary, contour) < polygonThreshold)
                    continue;

                // Rescale
                List<OpenCvSharp.Point> contourScaled = new List<OpenCvSharp.Point>();
                foreach (var item in contour)
                {
                    contourScaled.Add(new OpenCvSharp.Point((int)(item.X * scaleWidth), (int)(item.Y * scaleHeight)));
                }

                RotatedRect box = Cv2.MinAreaRect(contourScaled);

                // minArea() rect is not normalized, it may return rectangles with angle=-90 or height < width
                float angle_threshold = 60;  // do not expect vertical text, TODO detection algo property
                bool swap_size = false;
                if (box.Size.Width < box.Size.Height)  // horizontal-wide text area is expected
                {
                    swap_size = true;
                }
                else if (Math.Abs(box.Angle) >= angle_threshold)  // don't work with vertical rectangles
                {
                    swap_size = true;
                }

                if (swap_size)
                {
                    float temp = box.Size.Width;
                    box.Size.Width = box.Size.Height;
                    box.Size.Height = temp;

                    if (box.Angle < 0)
                        box.Angle += 90;
                    else if (box.Angle > 0)
                        box.Angle -= 90;
                }

                Point2f[] vertex = new Point2f[4];
                vertex = box.Points();  // order: bl, tl, tr, br

                List<Point2f> approx = new List<Point2f>();

                for (int j = vertex.Length - 1; j >= 0; j--)
                {
                    approx.Add(vertex[j]);
                }

                List<Point2f> polygon = new List<Point2f>();

                Unclip(approx, polygon);

                results.Add(approx);

            }

            result_image = image.Clone();

            for (int i = 0; i < results.Count; i++)
            {
                for (int j = 0; j < 4; j++)
                {

                    Cv2.Circle(result_image
                     , new OpenCvSharp.Point((int)results[i][j].X, (int)results[i][j].Y)
                     , 2
                     , new Scalar(0, 0, 255)
                     , -1);

                    if (j < 3)
                    {
                        Cv2.Line(result_image
                            , new OpenCvSharp.Point((int)results[i][j].X, (int)results[i][j].Y)
                            , new OpenCvSharp.Point((int)results[i][j + 1].X, (int)results[i][j + 1].Y)
                            , new Scalar(0, 255, 0), 2);
                    }
                    else
                    {
                        Cv2.Line(result_image
                            , new OpenCvSharp.Point((int)results[i][j].X, (int)results[i][j].Y)
                            , new OpenCvSharp.Point((int)results[i][0].X, (int)results[i][0].Y)
                            , new Scalar(0, 255, 0), 2);
                    }


                }
            }

            pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());

            sb.Clear();
            sb.AppendLine("推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms");
            sb.AppendLine("------------------------------");
            textBox1.Text = sb.ToString();

        }

        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox2.Image);
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox1.Image);
        }
    }
}

下载

可执行程序exe包下载

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/110711.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FPGA时序分析与约束(9)——主时钟约束

一、时序约束 时序引擎能够正确分析4种时序路径的前提是&#xff0c;用户已经进行了正确的时序约束。时序约束本质上就是告知时序引擎一些进行时序分析所必要的信息&#xff0c;这些信息只能由用户主动告知&#xff0c;时序引擎对有些信息可以自动推断&#xff0c;但是推断得到…

PHP的Excel导出与导入

下载地址&#xff08;注意php版本大于7.3可能会报错&#xff09; GitHub - PHPOffice/PHPExcel: ARCHIVED 解压 1、导出 Excel $data[[name>a,age>11],[name>b,age>22],[name>d,age>33], ]; $fileds["name">"名称","age"…

在Java和PostgreSQL枚举之间进行转换的通用方法

枚举类型&#xff08;enum&#xff09;是一种方便的数据类型&#xff0c;允许我们指定一个常量列表&#xff0c;对象字段或数据库列可以设置为该列表中的值。 枚举的美妙之处在于我们可以通过提供人类可读格式的枚举常量来确保数据完整性。因此&#xff0c;Java和PostgreSQL原…

详解—数据结构《树和二叉树》

目录 一.树概念及结构 1.1树的概念 1.2树的表示 二.二叉树的概念及结构 2.1概念 2.2二叉树的特点 2.3现实中的二叉树 2.4数据结构中的二叉树 2.5 特殊的二叉树 2.6二叉树的存储结构 2.6.1二叉树的性质 2.6.2 顺序结构 2.6.3链式存储 三. 二叉树的链式结构的遍历 …

【广州华锐视点】节省成本,提升效果!教你快速搭建一个元宇宙3D虚拟展厅!

在当今这个数字化的时代&#xff0c;拥有一个专业的网站或者小程序已经成为了企业展示形象、推广产品的重要手段。然而&#xff0c;对于许多小企业来说&#xff0c;高昂的开发费用和复杂的技术门槛往往成为了他们实现这一目标的最大阻碍。那么&#xff0c;有没有一种方式&#…

使用 puppeteer 库采集豆瓣音频简单代码示例

今天要给大家分享的采集代码&#xff0c;主要是使用 puppeteer 库进行编写的&#xff0c;用于采集豆瓣网相关音频。这段代码也是非常的简单实用&#xff0c;一起来看看吧。 // 引入 puppeteer 库 const puppeteer require(puppeteer);// 定义获取代理服务器的函数 function …

如果一定要在C++和JAVA中选择,是C++还是java?

如果一定要在C和JAVA中选择&#xff0c;是C还是java&#xff1f; 计算机专业的同学对这个问题有疑惑的&#xff0c;- 定要看一下这个回答! 上来直接给出最中肯的建议: 如果你是刚刚步入大学的大一时间非常充裕的同学&#xff0c;猪学长强烈建议先学C/C.因为C 非常 最近很多…

Android NDK开发详解之Application.mk探秘

Android NDK开发详解之Application.mk探秘 概览变量APP_ASFLAGSAPP_ASMFLAGSAPP_BUILD_SCRIPTAPP_CFLAGSAPP_CLANG_TIDYAPP_CLANG_TIDY_FLAGSAPP_CONLYFLAGSAPP_CPPFLAGSAPP_CXXFLAGSAPP_DEBUGAPP_LDFLAGSAPP_MANIFESTAPP_MODULESAPP_OPTIMAPP_PLATFORMAPP_PROJECT_PATHAPP_STL…

518抽奖软件,高质量缩放算法,照片显示更清晰

518抽奖软件简介 518抽奖软件&#xff0c;518我要发&#xff0c;超好用的年会抽奖软件&#xff0c;简约设计风格。 包含文字号码抽奖、照片抽奖两种模式&#xff0c;支持姓名抽奖、号码抽奖、数字抽奖、照片抽奖。([http://www.518cj.net/]http://www.518cj.net/) 高质量缩放…

最新JustMedia V2.7.3主题破解版去授权WordPress主题模板

JustMedia主题是一款针对有图片或者视频发布需求的网站量身定制开发的wordpress主题&#xff0c;适合各类图片展示类网站使用。 同时JustMedia主题首次加入了我们WPCOM团队独立自主开发的前端用户中心模块&#xff0c;相比用户中心插件可提供更好的体验效果。 新版用户中心为…

大数据平台发展及Hudi简要复习

第一代数据仓库——Vertica 最初&#xff0c;Uber使用MySQL作为他们的主要数据存储。然而&#xff0c;随着业务的扩展和数据量的增长&#xff0c;他们开始需要一个更强大的解决方案来进行大规模的数据分析和处理。 因此&#xff0c;Uber选择了Vertica作为他们的第一代数据仓库…

莫名其妙el-table不显示问题

完全复制element-ui中table代码&#xff0c;发现表格仍然不显示&#xff0c;看别人都说让降低版本&#xff0c;可我不想降低啊&#xff0c;不然其他组件有可能用不了&#xff0c;后来发现可以通过配置vite.config.js alias: {: path.resolve(__dirname, src),vue: vue/dist/vue…

关于息肉检测和识别项目的总结

前言 整体的思路&#xff1a;首先息肉数据集分为三类&#xff1a; 1.正常细胞 2. 增生性息肉 3. 肿瘤要想完成这个任务&#xff0c;首先重中之重是分割任务&#xff0c;分割结果的好坏&#xff0c; 当分割结果达到一定的准确度后&#xff0c;开始对分割后的结果进行下游分类…

Node.js的基本概念node -v 和npm -v 这两个命令的作用

Node.js 是一个开源且跨平台的 JavaScript 运行时环境&#xff0c;它可以让你在服务器端运行 JavaScript 代码。Node.js 使用了 Chrome 的 V8 JavaScript 引擎来执行代码&#xff0c;非常高效。 在 Node.js 出现之前&#xff0c;JavaScript 通常只在浏览器中运行&#xff0c;用…

谈思生物医疗直播 | 霍德生物研发中心负责人王安欣博士“iPSC衍生神经细胞产品全悬浮自动化工艺及特殊质控方法开发”

iPSC通过人体来源的终端体细胞重编程而来&#xff0c;其衍生细胞产品的生产与质控面临着诸多挑战&#xff0c;但也解决了许多自体细胞治疗的不稳定性和高成本等产业化难点。例如自体细胞不仅供体之间的差异对产品质量可能造成影响&#xff0c;即使同一个供体&#xff0c;体细胞…

SSM培训报名管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 培训报名管理系统是一套完善的信息系统&#xff0c;结合SSM框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主 要采用B/S模式开…

http1,https,http2,http3总结

1.HTTP 当我们浏览网页时&#xff0c;地址栏中使用最多的多是https://开头的url&#xff0c;它与我们所学的http协议有什么区别&#xff1f; http协议又叫超文本传输协议&#xff0c;它是应用层中使用最多的协议&#xff0c; http与我们常说的socket有什么区别吗&#xff1f; …

TSINGSEE青犀省级高速公路视频上云联网方案:全面实现联网化、共享化、智能化

一、需求背景 随着高速铁路的建设及铁路管理的精细化&#xff0c;原有的模拟安防视频监控系统已经不能满足视频监控需求&#xff0c;越来越多站点在建设时已开始规划高清安防视频监控系统。高速公路视频监控资源非常丰富&#xff0c;需要对其进行综合管理与利用。通过构建监控…

Java版 招投标系统简介 招投标系统源码 java招投标系统 招投标系统功能设计

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

【计算机网络】分层模型和应用协议

网络分层模型和应用协议 1. 分层模型 1.1 五层网络模型 网络要解决的问题是&#xff1a;两个程序之间如何交换数据。 四层&#xff1f;五层&#xff1f;七层&#xff1f; 2. 应用层协议 2.1 URL URL&#xff08;uniform resource locator&#xff0c;统一资源定位符&#…
最新文章