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();}
注:如果需要其它源码,请留言邮箱,我看到私发。
相关文章:
C# 实现电子签名
本项目基于Emgu.CV(C#下OpenCv的封装)开发的,编译器最新版Vs2022,编译环境x86 直接看效果图 1.主页面 2.我们先看手写的方式: 点击确认就到主界面,如下 : 点击自动适配-,再点击生成…...
小米6/6X/米8/米9手机刷入鸿蒙HarmonyOS.4.0系统-刷机包下载-遥遥领先
小米手机除了解锁root权限,刷GSI和第三方ROM也是米粉的一大爱好,这不,在华为发布了HarmonyOS.4.0系统后不久,我们小米用户也成功将自己的手机干山了HarmonyOS.4.0系统。虽然干上去HarmonyOS.4.0系统目前BUG非常多,根本…...
集合框架和泛型二
一、Set接口 1. Set接口概述 java.util.Set 不包含重复元素的集合、不能保证存储的顺序、只允许有一个 null。 public interface Set<E> extends Collection<E>抽象方法,都是继承自 java.util.Collection 接口。 Set 集合的实现类有很多,…...
thinkphp6 入门教程合集(更新中)
thinkphp6 入门(1)--安装、路由规则、多应用模式 thinkphp6 入门(1)--安装、路由规则、多应用模式_软件工程小施同学的博客-CSDN博客 thinkphp6 入门(2)--视图、渲染html页面、赋值 thinkphp6 入门&#…...
openGauss学习笔记-65 openGauss 数据库管理-创建和管理数据库
文章目录 openGauss学习笔记-65 openGauss 数据库管理-创建和管理数据库65.1 前提条件65.2 背景信息65.3 注意事项65.4 操作步骤65.4.1 创建数据库65.4.2 查看数据库65.4.3 修改数据库65.4.4 删除数据库 openGauss学习笔记-65 openGauss 数据库管理-创建和管理数据库 65.1 前提…...
mysql、MHA高可用配置即故障切换
MHA概述 一套优秀的MySQL高可用环境下故障切换和主从复制的软件 MHA的出现就是解决MySQL 单点的问题 MySQL故障过程中,MHA能做到0-30秒内自动完成故障切换 MHA能在故障切换的过程中最大程度上保证数据的一致性以达到真正意义上的高可用 MHA的组成(核…...
使用“vue init mpvue/mpvue-quickstart“初始化mpvue项目时出现的错误及解决办法
当使用"vue init mpvue/mpvue-quickstart"初始化 mpvue 项目时出现 "vue-cli Failed to download repo mpvue/mpvue-quickstart: connect ETIMEDOUT IP地址"原因是 github 的 IP 解析失败,连接超时 解决办法:更改最新的 github 的 …...
Linux-Shell整理集合
Shell变量 参考文章: Shell脚本中变量的使用 shell语法之 , ‘ ‘ , {},, ,‘‘,(),$(())四种语法含义 参考文章: shell语法之 , ‘ ‘ , {},, ,‘‘,(),$(())四种语法含义 grep常用用法 Shell awk命令详解 grep 跟awk连着用: 获取某程序的…...
windows环境下node安装教程(超详细)
安装node.js 1、下载node: 下载地址:下载 | Node.js 中文网 node.js的zip包安装时是直接解压缩后就可以了, node.js的msi包是傻瓜式一路next就可以了 选择一中方式就可以 2、解压后的目录,或者mis安装后的目录如下: 3、安装完后,可以在命令行中输入…...
《TCP/IP网络编程》阅读笔记--并发多进程服务端的使用
目录 1--并发服务器端 2--进程 2-1--进程的相关概念 2-2--fork()创建进程 2-3--僵尸进程 2-4--wait()和waitpid()销毁僵尸进程 3--信号处理 3-1--signal()函数 3-2--sigaction()函数 3--3--利用信号处理技术消灭僵尸进程 4--基于多任务的并发服务器 5--分割 TCP 的…...
【C++】day2学习成果:引用、结构体等等。。。
1.封装一个结构体,结构体中包含一个私有数组,用来存放学生的成绩,包含一个私有变量,用来记录学生个数, 提供一个公有成员函数,void setNum(int num)用于设置学生个数 提供一个公有成员函数:void…...
QT 第五天 TCP通信与数据库
一、数据库增删改查 QT core gui sqlgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your comp…...
Java程序中常用的设计模式有哪些和该种设计模式解决的痛点
设计模式是大量程序员智慧的结晶,是优秀的代码范式,是以前那些大佬程序员的编程经验总结,非常值得学习。 在软件开发中,有许多常用的设计模式,每种模式都解决了特定类型的问题。以下是一些常见的设计模式及其简要介绍&…...
Android12之解析/proc/pid进程参数(一百六十四)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…...
正儿八经的雅思口语盘丝洞大法学习总结(长期修改更新)针对23.9月考生
目录 开篇语 李仙童口语大法 具体体系内容 说道科技产品或者说非传统物品 part2回答八大准则 【part2回答八大准则】(一) 【part2回答八大准则】(二) 【part3回答七大准则】(一) Part 1 核心体系 …...
算法竞赛入门【码蹄集新手村600题】(MT1260-1280)C语言
算法竞赛入门【码蹄集新手村600题】(MT1260-1280)C语言 目录MT1260 袋鼠躲猫猫MT1261 留下来的才是幸运数MT1262 约数MT1263 最大的三位约数MT1264 完数MT1265 区间完数MT1266 完数与因子MT1267 亏数MT1268 因数的因数MT1269 区间素数MT1270 素数计算MT1271 三生质数…...
qt连接tcp通信和连接数据库
通过数据库实现学生管理系统 widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//判断数据库对象是否包含了自己使用的数据库 Studemt.dbif(!db.co…...
MySQL Oracle区别
由于SQL Server不常用,所以这里只针对MySQL数据库和Oracle数据库的区别 (1) 对事务的提交 MySQL默认是自动提交,而Oracle默认不自动提交,需要用户手动提交,需要在写commit;指令或者点击commit按钮 (2) 分页查询 MySQL是直接在SQL语…...
Figma实用插件速收藏!精选19个干货插件大公开!
Figma 如今有着大量的插件,在 UI/UX 设计领域,很多工作已经不用真的从零开始做了。用好 Figma 插件,往往能让设计工作事半功倍。不过其中的插件素质差别很大,需要仔细筛选。不过如果你选择了对的插件,合理的设置&#…...
【STM32】FSMC—扩展外部 SRAM 初步使用 1
基于野火指南者《零死角玩转 STM32F103—指南者》的学习 STM32F103系列 FSMC Flexible Static Memory Controller简介 1.详细功能参看《STM32F10x参考手册》,这边是概述 是一个外设,挂载在AHB总线下。 可以用于驱动包括 SRAM、NOR FLASH 以及 NAND FL…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
