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…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...