C#開發(fā)的人臉左右相似度計(jì)算軟件源碼分析
更新時(shí)間:2015年04月23日 09:29:51 作者:小蘿莉
這篇文章主要介紹了C#開發(fā)的人臉左右相似度計(jì)算軟件,較為詳細(xì)的分析了相似度計(jì)算的相關(guān)原理與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下
本文實(shí)例講述了C#開發(fā)的人臉左右相似度計(jì)算軟件。分享給大家供大家參考。具體分析如下:
模仿湖南衛(wèi)視快樂大本營中所使用的一款人臉左右對稱相似度計(jì)算軟件,自己寫的一個(gè)小軟件,使用語言是C#,希望跟喜歡這個(gè)軟件的同志們共享!
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>
/// 左臉對稱函數(shù)
/// </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>
/// 右臉對稱函數(shù)
/// </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>
/// 定義膚色檢測函數(shù)
/// </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>
/// 定義圖像灰度化函數(shù)
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
public static Bitmap ImageGray(Bitmap src)
{
int w = src.Width;
int h = src.Height;
//構(gòu)建與原圖像大小一樣的模版圖像
Bitmap dstBitmap = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//將原圖像存入內(nèi)存
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];
//調(diào)用圖像灰度化公式
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>
/// 左右臉相似度函數(shù)
/// </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>
/// 得到圖像信息函數(shù)
/// </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;
//定義人臉位置圖像調(diào)整變量
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();
}
//圖像打開函數(shù)
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);
}
}
//圖像保存函數(shù)
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#程序設(shè)計(jì)有所幫助。
您可能感興趣的文章:
相關(guān)文章
C# SQLite序列操作實(shí)現(xiàn)方法詳解
這篇文章主要介紹了C# SQLite序列操作實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了C#實(shí)現(xiàn)SQLite序列操作的具體步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
C#使用itextsharp打印pdf的實(shí)現(xiàn)代碼
提到打印,恐怕對于很多人都不會陌生,無論是開發(fā)者,還是非計(jì)算機(jī)專業(yè)的人員都會接觸到打印,?在.NET中實(shí)現(xiàn)PDF打印的組件比較多,例如PDFsharp、Report.NET、sharpPDF、itextSharp等等,今天主要簡單的介紹itextSharp組件,需要的朋友可以參考下2024-04-04
基于C#動(dòng)手實(shí)現(xiàn)網(wǎng)絡(luò)服務(wù)器Web Server
這篇文章主要為大家詳細(xì)介紹了基于C#動(dòng)手實(shí)現(xiàn)網(wǎng)絡(luò)服務(wù)器Web Server,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10

