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

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


代码注释

作者:喵哥笔记

IDC笔记

学的不仅是技术,更是梦想!