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

 更新时间:2015年04月23日 09:29:51   作者:小萝莉  
这篇文章主要介绍了C#开发的人脸左右相似度计算软件,较为详细的分析了相似度计算的相关原理与具体实现技巧,需要的朋友可以参考下

本文实例讲述了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#程序设计有所帮助。

相关文章

  • Unity实现物体跟随鼠标移动

    Unity实现物体跟随鼠标移动

    这篇文章主要为大家详细介绍了Unity实现物体跟随鼠标移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C#中的委托使用

    C#中的委托使用

    委托是C#中新加入的一个类型,可以把它想作一个和Class类似的一种类型,和使用类相似,使用一个委托时,需要两个步骤,首先你要定义一个委托,就像是定义一个类一样;然后,你可以创建一个或多个该委托的实例。
    2016-07-07
  • 关于C#调用C++dll传指针释放内存问题

    关于C#调用C++dll传指针释放内存问题

    这篇文章主要介绍了关于C#调用C++dll传指针释放内存问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • C#无边框窗体实现以及拖动代码

    C#无边框窗体实现以及拖动代码

    我们给大家分享了关于C#无边框窗体实现以及拖动代码,大家在程序设计的时候如果用的到一起跟着小编学习下吧。
    2018-03-03
  • C# list<T>去重的实现

    C# list<T>去重的实现

    List集合在开发过程中很常见,经常我们要对该集合进行一系列操作,本文主要介绍了C# list<T>去重的实现,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • C#实现字符串倒序遍历的方法小结

    C#实现字符串倒序遍历的方法小结

    这篇文章主要为大家详细介绍了C#中实现字符串倒序遍历的常见方法,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考下
    2024-02-02
  • C# WPF编程之元素绑定详解

    C# WPF编程之元素绑定详解

    数据绑定是一种关系,该关系告诉WPF从源对象提取一下信息,并用这些信息设置目标对象的属性,下面我们就来了解一下WPF编程中元素绑定的相关知识吧
    2024-04-04
  • 用序列化实现List<T> 实例的深复制(推荐)

    用序列化实现List<T> 实例的深复制(推荐)

    下面小编就为大家带来一篇用序列化实现List<T> 实例的深复制(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • c# 文件操作(移动,复制,重命名)

    c# 文件操作(移动,复制,重命名)

    这篇文章主要介绍了c# 如何对文件操作(移动,复制,重命名),帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下
    2020-12-12
  • C#实现单线程异步互斥锁的示例代码

    C#实现单线程异步互斥锁的示例代码

    异步互斥锁的作用是用于确保存在异步操作的上下文同步互斥,这篇文章主要为大家详细介绍了C#如何实现单线程异步互斥锁,文中的示例代码讲解详细,需要的可以参考下
    2024-01-01

最新评论