C#开发的人脸左右相似度计算软件源码分析

 更新时间:2020年6月25日 11:30  点击:1258

本文实例讲述了C#开发的人脸左右相似度计算软件。分享给大家供大家参考。具体分析如下:

模仿湖南卫视快乐大本营中所使用的一款人脸左右对称相似度计算软件,自己写的一个小软件,使用语言是C#,希望跟喜欢这个软件的同志们共享!

1. FaceClass类程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace FaceSmile
{
 class FaceClass
 {
  /// <summary>
  /// 左脸对称函数
  /// </summary>
  /// <param name="a"></param>
  /// <returns></returns>
  public static Bitmap FaceFlipLeft(Bitmap a)
  {
   Rectangle rect = new Rectangle(0, 0, a.Width, a.Height);
   System.Drawing.Imaging.BitmapData srcData = a.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, a.PixelFormat);
   IntPtr ptr = srcData.Scan0;
   int bytes = 0;
   bytes = srcData.Stride * a.Height;
   byte[] grayValues = new byte[bytes];
   System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
   byte[] temp = new byte[bytes];
   temp = (byte[])grayValues.Clone();
   for (int j = 0; j < a.Height; j++)
   {
    for (int i = 0; i < (int)(a.Width/2); i++)
    {
     temp[(a.Width - 2 - i) * 3 + j * srcData.Stride] = temp[i * 3 + j * srcData.Stride];
     temp[(a.Width - 2 - i) * 3 + 1 + j * srcData.Stride] = temp[i * 3 + 1 + j * srcData.Stride];
     temp[(a.Width - 2 - i) * 3 + 2 + j * srcData.Stride] = temp[i * 3 + 2 + j * srcData.Stride];
    }
   }
   grayValues = (byte[])temp.Clone();
    System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
   a.UnlockBits(srcData);
   return a;
  }
  /// <summary>
  /// 右脸对称函数
  /// </summary>
  /// <param name="a"></param>
  /// <returns></returns>
  public static Bitmap FaceFlipRight(Bitmap a)
  {
   Rectangle rect = new Rectangle(0, 0, a.Width, a.Height);
   System.Drawing.Imaging.BitmapData srcData = a.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, a.PixelFormat);
   IntPtr ptr = srcData.Scan0;
   int bytes = 0;
   bytes = srcData.Stride * a.Height;
   byte[] grayValues = new byte[bytes];
   System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
   byte[] temp = new byte[bytes];
   temp = (byte[])grayValues.Clone();
   for (int j = 0; j < a.Height; j++)
   {
    for (int i = 0; i < (int)(a.Width / 2); i++)
    {
     temp[i * 3 + j * srcData.Stride] = temp[(a.Width - 2 - i) * 3 + j * srcData.Stride];
     temp[i * 3 + 1 + j * srcData.Stride] = temp[(a.Width - 2 - i) * 3 + 1 + j * srcData.Stride];
     temp[i * 3 + 2 + j * srcData.Stride] = temp[(a.Width - 2 - i) * 3 + 2 + j * srcData.Stride];
    }
   }
   grayValues = (byte[])temp.Clone();
   System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
   a.UnlockBits(srcData);
   return a;
  }
  /// <summary>
  /// 定义肤色检测函数
  /// </summary>
  /// <param name="a"></param>
  /// <returns></returns>
  public static Bitmap SkinDetect(Bitmap a)
  {
   Rectangle rect = new Rectangle(0, 0, a.Width, a.Height);
   System.Drawing.Imaging.BitmapData bmpData = a.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
   int stride = bmpData.Stride;
   unsafe
   {
    byte* pIn = (byte*)bmpData.Scan0.ToPointer();
    byte* P;
    int R, G, B;
    double r, g, Fupr, Flor, Wrg;
    for (int y = 0; y < a.Height; y++)
    {
     for (int x = 0; x < a.Width; x++)
     {
      P = pIn;
      B = P[0];
      G = P[1];
      R = P[2];
      if (R + G + B == 0)
      {
       r = 0;
       g = 0;
      }
      else
      {
       r = (R / (R + G + B));
       g = (G / (R + G + B));
      }
      Fupr = (1.0743 * r + 0.1452 - 1.3767 * r * r);
      Flor = (0.5601 * r + 0.1766 - 0.776 * r * r);
      Wrg = (r - 0.33) * (r - 0.33) + (g - 0.33) * (g - 0.33);
      if ((R - G >= 45) && ((R > G) && (G > B)) && (Fupr > g) && (Wrg >= 0.0004))
      {
       P[0] = (byte)B;
       P[1] = (byte)G;
       P[2] = (byte)R;
      }
      else
      {
       P[0] = 0;
       P[1] = 0;
       P[2] = 0;
      }
      pIn += 3;
     }
     pIn += stride - a.Width * 3;
    }
   }
   a.UnlockBits(bmpData);
   return a;
  }
  /// <summary>
  /// 定义图像灰度化函数
  /// </summary>
  /// <param name="src"></param>
  /// <returns></returns>
  public static Bitmap ImageGray(Bitmap src)
  {
   int w = src.Width;
   int h = src.Height;
   //构建与原图像大小一样的模版图像
   Bitmap dstBitmap = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
   //将原图像存入内存
   System.Drawing.Imaging.BitmapData srcData = src.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
   System.Drawing.Imaging.BitmapData dstData = dstBitmap.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
   unsafe
   {
    byte* pIn = (byte*)srcData.Scan0.ToPointer();
    byte* pOut = (byte*)dstData.Scan0.ToPointer();
    byte* p;
    int stride = srcData.Stride;
    int r, g, b;
    for (int y = 0; y < h; y++)
    {
     for (int x = 0; x < w; x++)
     {
      p = pIn;
      r = p[2];
      g = p[1];
      b = p[0];
      //调用图像灰度化公式
      pOut[0] = pOut[1] = pOut[2] = (byte)(b * 0.114 + g * 0.587 + r * 0.299);
      pIn += 3;
      pOut += 3;
     }
     pIn += srcData.Stride - w * 3;
     pOut += srcData.Stride - w * 3;
    }
    src.UnlockBits(srcData);
    dstBitmap.UnlockBits(dstData);
    return dstBitmap;
   }
  }
 }
}

2. SameRatioClass类程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace FaceSmile
{
 class SameRatioClass
 {
  /// <summary>
  /// 左右脸相似度函数
  /// </summary>
  /// <param name="src"></param>
  /// <param name="dst"></param>
  /// <returns></returns>
  public static double SameRatio(Bitmap src, Bitmap dst)
  {
   byte[] srcData = GetBytes(src);
   byte[] dstData = GetBytes(dst);
   double ratio = 0;
   int sum = 0;
   int std=0;
   for (int i = 0; i < srcData.Length; i++)
   {
    sum += Math.Abs(srcData[i] - dstData[i]);
    std += srcData[i];
   }
   ratio = 100-(double)(100*sum / std);
   return ratio;
  }
  /// <summary>
  /// 得到图像信息函数
  /// </summary>
  /// <param name="src"></param>
  /// <returns></returns>
  private static byte[] GetBytes(Bitmap src)
  {
   int w = src.Width;
   int h = src.Height;
   byte[] dataImage = new byte[w * h];
   System.Drawing.Imaging.BitmapData srcData = src.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);   
   unsafe
   {
    byte* pIn = (byte*)srcData.Scan0.ToPointer();    
    byte* p;
    int stride = srcData.Stride;
    int r, g, b;
    for (int y = 0; y < h; y++)
    {
     for (int x = 0; x < w; x++)
     {
      p = pIn;
      r = p[2];
      g = p[1];
      b = p[0];
      dataImage[x + y * x] = (byte)((r + g + b) / 3);
      pIn += 3;      
     }
     pIn += srcData.Stride - w * 3;     
    }
    src.UnlockBits(srcData);
    return dataImage;
   }
  }
 }
}

3. 主窗体程序

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace FaceSmile
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
   groupBox1.Visible = true;
   groupBox2.Visible = false;
  }
  #region 全局变量定义
  //定义原始图像变量
  private Bitmap src ;
  //定义图像相似度变量
  private double ratio = 0;
  //定义图像路径变量
  private string curFileName;
  //定义人脸位置图像调整变量
  private int numAdjust = 0;
  #endregion
  #region 软件操作
  //左脸对称
  private void button1_Click(object sender, EventArgs e)
  {
   if (src != null)
   {
    Bitmap temp = (Bitmap)src.Clone();
    Bitmap a = FaceClass.FaceFlipLeft(temp);
    pictureBox1.Image = (Image)a;
    ratio = SameRatioClass.SameRatio(a, src);
    label1.Text = ratio.ToString();
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  //右脸对称
  private void button2_Click(object sender, EventArgs e)
  {
   if (src != null)
   {
    Bitmap temp = (Bitmap)src.Clone();
    Bitmap a = FaceClass.FaceFlipRight(temp);
    pictureBox1.Image = (Image)a;
    ratio = SameRatioClass.SameRatio(a, src);
    label1.Text = ratio.ToString();
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  //打开图像
  private void button3_Click(object sender, EventArgs e)
  {
   OpenImage();
   if (src != null)
   {
    pictureBox1.Image = (Image)src;
    pictureBox1.Width = src.Width;
    pictureBox1.Height = src.Height;
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  //保存图像
  private void button4_Click(object sender, EventArgs e)
  {
   SaveImage();
  }
  //图像打开函数
  private void OpenImage()
  {
   try
   {
    ofd.Filter = "All files (*.*)|*.*|bmp files (*.bmp)|*.bmp|jpeg files (*.jpg)|*.jpg|png files (*.png)|*.png";
    ofd.Title = "打开";
    ofd.ShowHelp = true;
    if (ofd.ShowDialog() == DialogResult.OK)
    {
     curFileName = ofd.FileName;
     src = new Bitmap(curFileName);
    }
   }
   catch (Exception ex)
   {
    MessageBox.Show(ex.Message);
   }
  }
  //图像保存函数
  private void SaveImage()
  {
   try
   {
    sfd.Filter = "保存(*.bmp)|*.bmp";
    sfd.Title = "保存";
    sfd.ShowHelp = true;
    if (sfd.ShowDialog() == DialogResult.OK)
    {
     Bitmap temp = (Bitmap)pictureBox1.Image;
     temp.Save(sfd.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
    }
   }
   catch (Exception ex)
   {
    MessageBox.Show(ex.Message);
   }
  }
  //其他操作
  private void button5_Click(object sender, EventArgs e)
  {
   groupBox2.Location = new Point(groupBox1.Location.X, groupBox1.Location.Y);
   groupBox2.Visible = true;
   groupBox1.Visible = false;
  }
  //肤色检测
  private void button6_Click(object sender, EventArgs e)
  {
   if (pictureBox1.Image != null)
   {
    pictureBox1.Image = (Image)FaceClass.SkinDetect((Bitmap)pictureBox1.Image);
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  //返回操作
  private void button7_Click(object sender, EventArgs e)
  {
   groupBox1.Visible = true;
   groupBox2.Visible = false;
  }
  //灰度化
  private void button8_Click(object sender, EventArgs e)
  {
   if (pictureBox1.Image != null)
   {
    pictureBox1.Image = (Image)FaceClass.ImageGray((Bitmap)pictureBox1.Image);
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  //博客连接
  private void label2_Click(object sender, EventArgs e)
  {
   System.Diagnostics.Process.Start("IEXPLORE.EXE", "http://dongtingyueh.blog.163.com/");
  }
  //修正人脸位置
  private void button9_Click(object sender, EventArgs e)
  {
   if (numAdjust != 0)
   {
    int a = numAdjust;
    int b = src.Width - a;
    int result = a < b ? a : b;
    if (result == b)
    {
     src = src.Clone(new Rectangle(src.Width - 2 * result, 0, 2 * result, src.Height), src.PixelFormat);
    }
    else
    {
     src = src.Clone(new Rectangle(0, 0, 2 * result, src.Height), src.PixelFormat);
    }
    pictureBox1.Image = (Image)src;
    pictureBox1.Width = src.Width;
    pictureBox1.Height = src.Height;
   }
   trackBar1.Value = 0;
   label4.Text = "0";
  }
  #endregion
  #region 人脸位置修正
  private void trackBar1_Scroll(object sender, EventArgs e)
  {
   if (src != null)
   {
    trackBar1.Maximum = src.Width;
    trackBar1.Minimum = 0;
    numAdjust = trackBar1.Value;
    label4.Text = numAdjust.ToString();
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  private void trackBar1_ValueChanged(object sender, EventArgs e)
  {
   pictureBox1.Invalidate();
  }
  private void trackBar1_MouseUp(object sender, MouseEventArgs e)
  {
   if (src != null)
   {
    Graphics g = pictureBox1.CreateGraphics();
    g.DrawLine(new Pen(Color.Red, 2), new Point((int)(numAdjust), 0), new Point((int)(numAdjust), src.Height));
    g.Dispose();
   }
   else
   {
    MessageBox.Show("Please open one image!");
   }
  }
  #endregion
 }
}

希望本文所述对大家的C#程序设计有所帮助。

[!--infotagslink--]

相关文章

  • C#实现简单的登录界面

    我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
  • 浅谈C# 字段和属性

    这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
  • C#中截取字符串的的基本方法详解

    这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
  • C#实现简单的Http请求实例

    这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • C#中new的几种用法详解

    本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
  • 使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)

    这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
  • C#从数据库读取图片并保存的两种方法

    这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • C#绘制曲线图的方法

    这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
  • c#中(&&,||)与(&,|)的区别详解

    这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • 经典实例讲解C#递归算法

    这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
  • C#学习笔记- 随机函数Random()的用法详解

    下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#中list用法实例

    这篇文章主要介绍了C#中list用法,结合实例形式分析了C#中list排序、运算、转换等常见操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25