• C# 实现电子签名


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

    直接看效果图

    1.主页面

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

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

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

    放大看

     

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

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

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

    双击右边第一张放大:

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

    4.算法介绍:

    4.1自动适配

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

    1. ///
    2. /// 自动适配
    3. ///
    4. ///
    5. ///
    6. private void button4_Click(object sender, EventArgs e)
    7. {
    8. if (pictureBox1.Image == null)
    9. {
    10. MessageBox.Show("请选择图像");
    11. return;
    12. }
    13. imgShow?.Dispose();
    14. gray?.Dispose();
    15. imgShow = new Imagebyte>(new Bitmap(pictureBox1.Image));
    16. gray = imgShow.Convertbyte>();
    17. double median = radioButton1.Checked ? CalculateMedian(gray) : CalculateAvg(gray);
    18. double sigma = (float)numericUpDown1.Value;
    19. double lower = Math.Max(0, (1.0 - sigma) * median);
    20. double upper = Math.Min(255, (1.0 + sigma) * median);
    21. trackBar1.Value = (int)lower;
    22. label1.Text = trackBar1.Value.ToString();
    23. trackBar2.Value = (int)upper;
    24. label3.Text = trackBar2.Value.ToString();
    25. }

     4.2Canny生成

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

    1. ///
    2. /// Canny生成
    3. ///
    4. ///
    5. ///
    6. private void button6_Click(object sender, EventArgs e)
    7. {
    8. if (gray == null || imgShow == null)
    9. {
    10. MessageBox.Show("请先选择自动适配");
    11. return;
    12. }
    13. // Canny算子边缘检测
    14. using Imagebyte> edges = gray.Canny(trackBar1.Value, trackBar2.Value);
    15. using VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
    16. using Mat hier = new Mat();
    17. CvInvoke.FindContours(edges, contours, hier, RetrType.List, ChainApproxMethod.ChainApproxSimple);
    18. // 掩码
    19. using Imagebyte> mask = new Imagebyte>(gray.Size);
    20. if (contours.Size > 10000)
    21. {
    22. MessageBox.Show("边缘太多,会非常耗时,请重先调节参数");
    23. return;
    24. }
    25. // 在imgShow图像上填充边缘边框
    26. for (int i = 0; i < contours.Size; i++)
    27. {
    28. var contour = contours[i];
    29. CvInvoke.DrawContours(imgShow, contours, i, new MCvScalar(0, 0, 255), 2);
    30. CvInvoke.DrawContours(mask, contours, i, new MCvScalar(255), thickness: -1);
    31. }
    32. this.pictureBox3.Image?.Dispose();
    33. this.pictureBox3.Image = imgShow.Bitmap;
    34. using Imagebyte> maskedImage = new Imagebyte>(gray.Size);
    35. CvInvoke.BitwiseAnd(gray, gray, maskedImage, mask);
    36. MCvScalar average = CvInvoke.Mean(maskedImage, mask);
    37. double blue = average.V0;
    38. double green = average.V1;
    39. double red = average.V2;
    40. trackBar3.Value = (int)Math.Round(red, 0);
    41. trackBar4.Value = (int)Math.Round(green, 0);
    42. trackBar5.Value = (int)Math.Round(blue, 0);
    43. label9.Text = trackBar3.Value.ToString();
    44. label10.Text = trackBar4.Value.ToString();
    45. label12.Text = trackBar5.Value.ToString();
    46. }

    4.3生成

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

    1. ///
    2. /// 生成
    3. ///
    4. ///
    5. ///
    6. private void button2_Click(object sender, EventArgs e)
    7. {
    8. if (pictureBox1.Image == null)
    9. {
    10. MessageBox.Show("请选择图片");
    11. return;
    12. }
    13. img?.Dispose();
    14. img = new Imagebyte>(new Bitmap(pictureBox1.Image));
    15. // 掩码
    16. using Imagebyte> mask2 = img.InRange(new Bgra(trackBar5.Value, trackBar4.Value, trackBar3.Value, 0), new Bgra(255, 255, 255, 255));
    17. // 将掩码中选取的颜色的alpha通道设置为0
    18. img.SetValue(new Bgra(0, 0, 0, 0), mask2);
    19. this.pictureBox2.Image?.Dispose();
    20. this.pictureBox2.Image = img.Bitmap;
    21. }

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

     

    1. private void button2_Click(object sender, EventArgs e)
    2. {
    3. if(this.pictureBox1.Image==null)
    4. {
    5. return;
    6. }
    7. float scaleX = (float)this.pictureBox1.Image.Width / pictureBox1.Width;
    8. float scaleY = (float)this.pictureBox1.Image.Height / pictureBox1.Height;
    9. Rectangle rect = new Rectangle(
    10. (int)(Rect.Left * scaleX),
    11. (int)(Rect.Top * scaleY),
    12. (int)(Rect.Width * scaleX),
    13. (int)(Rect.Height * scaleY));
    14. var rectangle = new OpenCvSharp.Rect(rect.X, rect.Y, rect.Width, rect.Height);
    15. rect.Intersect(new Rectangle(0, 0, this.pictureBox1.Image.Width, this.pictureBox1.Image.Height));
    16. using Mat nimage = new Bitmap(this.pictureBox1.Image).ToMat();
    17. using Mat image = new Mat(nimage, rectangle);
    18. using Mat convertedImage = new Mat();
    19. Cv2.CvtColor(image, convertedImage, ColorConversionCodes.BGRA2BGR); // 将图像转换为CV_8UC3类型
    20. using Mat mask = new Mat(convertedImage.Size(), MatType.CV_8UC1, Scalar.Black);
    21. using Mat bgdModel = new Mat();
    22. using Mat fgdModel = new Mat();
    23. var r = new OpenCvSharp.Rect(0, 0, rectangle.Width-10, rectangle.Height-10);
    24. Cv2.GrabCut(convertedImage, mask, r, bgdModel, fgdModel, 20, GrabCutModes.InitWithRect);
    25. Cv2.Threshold(mask, mask, 2, 255, ThresholdTypes.Binary);
    26. using Mat foreground = new Mat();
    27. Cv2.BitwiseAnd(convertedImage, convertedImage, foreground, mask);
    28. // 创建一个具有 alpha 通道的新图像
    29. using Mat result = new Mat();
    30. Cv2.CvtColor(image, result, ColorConversionCodes.BGRA2BGR);
    31. Cv2.Rectangle(result, rectangle, new Scalar(0, 0, 0), 1); // 绘制矩形边界
    32. Cv2.Multiply(result, new Scalar(1, 1, 1, 0), result); // 将背景部分置为透明
    33. // 将前景部分复制到结果图像中
    34. image.CopyTo(result, mask);
    35. pictureBox2.Image?.Dispose();
    36. pictureBox2.Image = result.ToBitmap();
    37. image.Dispose();
    38. }

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

  • 相关阅读:
    文件系统基础
    游戏设计模式专栏(八):Cocos中最常见的设计模式之一
    Docker-compose安装mysql
    Pytorch实现Bert模型
    聊一聊SqlSessionTemplate
    iOS 之homebrew ruby cocoapods 安装
    Gumbel-Softmax完全解析
    【java筑基】IO流进阶之文件随机访问、序列化与反序列化
    关于new Set( )还有哪些是你不知道的
    Spring Boot最核心的25个注解
  • 原文地址:https://blog.csdn.net/ftfmatlab/article/details/132702818