C# 实现电子签名

本项目基于Emgu.CV(C#下OpenCv的封装)开发的,编译器最新版Vs2022,编译环境x86

直接看效果图

1.主页面

2.我们先看手写的方式:

点击确认就到主界面,如下 :

点击自动适配-,再点击生成:

放大看

 

点击保存即可,生成透明电子签名图片。

3.在单色背景下手写名字,导入图片生成

先点击 选择图像 按钮,然后选择图像,点击自动适配,点击Canny算法生成,最后点击生成,如下:

双击右边第一张放大:

选择需要的区域点击保存即可。

4.算法介绍:

4.1自动适配

自动适配指根据灰度值像素选取Canny算子的上下阈值,主要目的是能快速自动适配Canny上下阈值,这里主要介绍以中位数或者平均值,然后以Sigma为临界值选取一个区间,如下:

        /// <summary>/// 自动适配/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button4_Click(object sender, EventArgs e){if (pictureBox1.Image == null){MessageBox.Show("请选择图像");return;}imgShow?.Dispose();gray?.Dispose();imgShow = new Image<Bgra, byte>(new Bitmap(pictureBox1.Image));gray = imgShow.Convert<Gray, byte>();double median = radioButton1.Checked ? CalculateMedian(gray) : CalculateAvg(gray);double sigma = (float)numericUpDown1.Value;double lower = Math.Max(0, (1.0 - sigma) * median);double upper = Math.Min(255, (1.0 + sigma) * median);trackBar1.Value = (int)lower;label1.Text = trackBar1.Value.ToString();trackBar2.Value = (int)upper;label3.Text = trackBar2.Value.ToString();}

 4.2Canny生成

Canny算子边缘检测具体不多介绍,这里目的是为了找到字体边缘,然后在图像上填充,方便我们能确定这个边缘是否能够准确找到,如果大都填充到字体上,说明边缘检测不错,找到这些边缘,然后计算它们的平均R、G、B:

        /// <summary>/// Canny生成/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button6_Click(object sender, EventArgs e){if (gray == null || imgShow == null){MessageBox.Show("请先选择自动适配");return;}// Canny算子边缘检测using Image<Gray, byte> edges = gray.Canny(trackBar1.Value, trackBar2.Value);using VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();using Mat hier = new Mat();CvInvoke.FindContours(edges, contours, hier, RetrType.List, ChainApproxMethod.ChainApproxSimple);// 掩码using Image<Gray, byte> mask = new Image<Gray, byte>(gray.Size);if (contours.Size > 10000){MessageBox.Show("边缘太多,会非常耗时,请重先调节参数");return;}// 在imgShow图像上填充边缘边框for (int i = 0; i < contours.Size; i++){var contour = contours[i];CvInvoke.DrawContours(imgShow, contours, i, new MCvScalar(0, 0, 255), 2);CvInvoke.DrawContours(mask, contours, i, new MCvScalar(255), thickness: -1);}this.pictureBox3.Image?.Dispose();this.pictureBox3.Image = imgShow.Bitmap;using Image<Gray, byte> maskedImage = new Image<Gray, byte>(gray.Size);CvInvoke.BitwiseAnd(gray, gray, maskedImage, mask);MCvScalar average = CvInvoke.Mean(maskedImage, mask);double blue = average.V0;double green = average.V1;double red = average.V2;trackBar3.Value = (int)Math.Round(red, 0);trackBar4.Value = (int)Math.Round(green, 0);trackBar5.Value = (int)Math.Round(blue, 0);label9.Text = trackBar3.Value.ToString();label10.Text = trackBar4.Value.ToString();label12.Text = trackBar5.Value.ToString();}

4.3生成

在生成中,我们会根据R、G、B计算出掩码,然后将掩码中选取的颜色的alpha通道设置为0,即为透明。

        /// <summary>/// 生成/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button2_Click(object sender, EventArgs e){if (pictureBox1.Image == null){MessageBox.Show("请选择图片");return;}img?.Dispose();img = new Image<Bgra, byte>(new Bitmap(pictureBox1.Image));// 掩码using Image<Gray, byte> mask2 = img.InRange(new Bgra(trackBar5.Value, trackBar4.Value, trackBar3.Value, 0), new Bgra(255, 255, 255, 255));// 将掩码中选取的颜色的alpha通道设置为0img.SetValue(new Bgra(0, 0, 0, 0), mask2);this.pictureBox2.Image?.Dispose();this.pictureBox2.Image = img.Bitmap;}

5.也可以直接调用GrabCut方法,多迭代几次就可以,不过效率低

 

 private void button2_Click(object sender, EventArgs e){if(this.pictureBox1.Image==null){return;}float scaleX = (float)this.pictureBox1.Image.Width / pictureBox1.Width;float scaleY = (float)this.pictureBox1.Image.Height / pictureBox1.Height;Rectangle rect = new Rectangle((int)(Rect.Left * scaleX),(int)(Rect.Top * scaleY),(int)(Rect.Width * scaleX),(int)(Rect.Height * scaleY));var rectangle = new OpenCvSharp.Rect(rect.X, rect.Y, rect.Width, rect.Height);rect.Intersect(new Rectangle(0, 0, this.pictureBox1.Image.Width, this.pictureBox1.Image.Height));using Mat nimage = new Bitmap(this.pictureBox1.Image).ToMat();using Mat image = new Mat(nimage, rectangle);using Mat convertedImage = new Mat();Cv2.CvtColor(image, convertedImage, ColorConversionCodes.BGRA2BGR); // 将图像转换为CV_8UC3类型using Mat mask = new Mat(convertedImage.Size(), MatType.CV_8UC1, Scalar.Black);using Mat bgdModel = new Mat();using Mat fgdModel = new Mat();var r = new OpenCvSharp.Rect(0, 0, rectangle.Width-10, rectangle.Height-10);Cv2.GrabCut(convertedImage, mask, r, bgdModel, fgdModel, 20, GrabCutModes.InitWithRect);Cv2.Threshold(mask, mask, 2, 255, ThresholdTypes.Binary);using Mat foreground = new Mat();Cv2.BitwiseAnd(convertedImage, convertedImage, foreground, mask);// 创建一个具有 alpha 通道的新图像using Mat result = new Mat();Cv2.CvtColor(image, result, ColorConversionCodes.BGRA2BGR);Cv2.Rectangle(result, rectangle, new Scalar(0, 0, 0), 1); // 绘制矩形边界Cv2.Multiply(result, new Scalar(1, 1, 1, 0), result); // 将背景部分置为透明// 将前景部分复制到结果图像中image.CopyTo(result, mask);pictureBox2.Image?.Dispose();pictureBox2.Image = result.ToBitmap();image.Dispose();}

注:如果需要其它源码,请留言邮箱,我看到私发。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

django configparser.NoSectionError: No section: ‘Samples

django configparser.NoSectionError: No section: Samples 背景&#xff1a;Windows下的Django项目&#xff0c;重新部署至Linux ubuntu20中。 samples_white_list eval(config.get(‘Samples’, ‘samples_white_list’)) File “/home/hhl/anaconda3/envs/django/lib/pytho…

13-JVM调优实战-3

上一篇&#xff1a;12-JVM调优实战-2 今天来介绍一款阿里巴巴的调优工具。 Arthas详解 Arthas 是 Alibaba 在 2018 年 9 月开源的 Java 诊断工具。支持 JDK6&#xff0c; 采用命令行交互模式&#xff0c;可以方便的定位和诊断线上程序运行问题。Arthas 官方文档十分详细&am…

C++学习之list的实现

在了解学习list实现之前我们首先了解一下关于迭代器的分类&#xff1a; 按功能分类&#xff1a; 正向迭代器 反向迭代器 const正向迭代器 const反向迭代器 按性质分类&#xff1a; 单向迭代器 只能 例如单链表 双向迭代器 可&#xff0c;也可-- 例如双…

解决Microsoft Edge无法正常运行的有效方案分享!

Microsoft Edge打不开或不能加载网页是用户在Windows 10、Android、Mac和iOS设备上的网络浏览器上遇到的许多错误之一。其他Microsoft Edge问题可能包括浏览器窗口和选项卡冻结、网站崩溃、互联网连接错误消息以及丢失Microsoft Edge书签、收藏夹、密码和收藏。 Microsoft Edg…

UMA 2 - Unity Multipurpose Avatar☀️四.UMA人物部位的默认颜色和自定义(共享)颜色

文章目录 🟥 人物颜色介绍1️⃣ 使用默认颜色2️⃣ 使用自定义颜色🟧 UMA自定义颜色的作用🟨 自定义颜色还可作为共享颜色🟥 人物颜色介绍 UMA不同部位的颜色分为默认的内置颜色和我们新定义的颜色. 1️⃣ 使用默认颜色 比如不勾选UseSharedColor时,使用的眼睛的默认…

【2023年11月第四版教材】第12章《质量管理》(第二部分)

第12章《质量管理》&#xff08;第二部分&#xff09; 4 规划质量管理4.1 数据收集★★★4.2 数据分析★★★4.3 数据表现★★★4.4 质量管理计划★★★4.5 质量测量指标★★★ &#xff08;22下35&#xff09; 4 规划质量管理 组过程输入工具和技术输出计划1.规划质量管理1.项…

antv-G6知识图谱安装--使用(实例)--连接线修改成动态,并添加跟随线移动的光圈,设置分支跟踪定位功能

这系列文章主要是完成一个图谱的自定义修改&#xff08;最近太忙了长篇分段更新自己使用流程&#xff09; 1. 连接线修改成动态&#xff0c;并添加跟随线移动的光圈 2. 自定义卡片样式和文字内容 3. 自定义伸缩节点的样式&#xff0c;并添加动画样式 3. 自定义弹窗样式 4. 自定…

普通用户使用spark的client无法更新Ranger策略

普通用户使用spark的client无法更新Ranger策略 报错图片&#xff1a; WARN org.apache.ranger.admin.client.RangerAdminRESTClient: Error getting Roles. secureModetrue, usercaojianxiangUCDIPA.VIATRIS.CC (auth:KERBEROS)&#xff0c;responsef"httpStatusCode&quo…

多线程-锁的种类

1 作用 Java中的锁主要用于保障多并发线程情况下数据的一致性。在多线程编程中为了保障数据的一致性&#xff0c;我们通常需要在使用对象或者方法之前加锁&#xff0c;这时如果有其他线程也需要使用该对象或者该方法,则首先要获得锁,如果某个线程发现锁正在被其他线程使用,就会…

Java基于SpringBoot+Vue的 4S店车辆管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 功能总览4 系统设计4.1 系统设计主要功能4.2 数据库设计4.2.1 数据库设计规范4.2…

产品波士顿矩阵

随着公司产品的增多&#xff0c;每个产品的生命周期节点各不相同&#xff0c;很多时候我们往往在产品结构、资源分配方面会产生各种问题&#xff0c;导致需要发展的产品得不到资源&#xff0c;消耗资源的产品却有无法增长&#xff0c;所谓不聚焦导致的问题其实是资源和发展错配…

【RocketMQ】设计理念与核心概念扫盲

【RocketMQ】设计理念与核心概念扫盲 文章目录 【RocketMQ】设计理念与核心概念扫盲一、RocketMQ的设计理念和目标1.1、设计理念1.2、设计目标 二、RocketMQ的核心概念扫盲篇2.1、部署架构2.1.1、Nameserver2.1.2、Broker2.1.3、Client 2.2、消息订阅模型2.2.1、消费模式2.2.2、…