C#開(kāi)發(fā)的人臉左右相似度計(jì)算軟件源碼分析
本文實(shí)例講述了C#開(kāi)發(fā)的人臉左右相似度計(jì)算軟件。分享給大家供大家參考。具體分析如下:
模仿湖南衛(wèi)視快樂(lè)大本營(yíng)中所使用的一款人臉左右對(duì)稱(chēng)相似度計(jì)算軟件,自己寫(xiě)的一個(gè)小軟件,使用語(yǔ)言是C#,希望跟喜歡這個(gè)軟件的同志們共享!
1. FaceClass類(lèi)程序
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; namespace FaceSmile { class FaceClass { /// <summary> /// 左臉對(duì)稱(chēng)函數(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> /// 右臉對(duì)稱(chēng)函數(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> /// 定義膚色檢測(cè)函數(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類(lèi)程序
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 軟件操作 //左臉對(duì)稱(chēng) 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!"); } } //右臉對(duì)稱(chēng) 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!"); } } //打開(kāi)圖像 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(); } //圖像打開(kāi)函數(shù) private void OpenImage() { try { ofd.Filter = "All files (*.*)|*.*|bmp files (*.bmp)|*.bmp|jpeg files (*.jpg)|*.jpg|png files (*.png)|*.png"; ofd.Title = "打開(kāi)"; 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; } //膚色檢測(cè) 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 } }
希望本文所述對(duì)大家的C#程序設(shè)計(jì)有所幫助。
- C#編程實(shí)現(xiàn)四舍五入、向上及下取整的方法
- C#計(jì)算程序執(zhí)行過(guò)程花費(fèi)時(shí)間的方法
- C#計(jì)算字符串哈希值(MD5、SHA)的方法小結(jié)
- C#實(shí)現(xiàn)計(jì)算一個(gè)點(diǎn)圍繞另一個(gè)點(diǎn)旋轉(zhuǎn)指定弧度后坐標(biāo)值的方法
- C#計(jì)算字符串相似性的方法
- C#實(shí)現(xiàn)計(jì)算年齡的簡(jiǎn)單方法匯總
- C#圖像處理之圖像均值方差計(jì)算的方法
- C#計(jì)算文件MD5校驗(yàn)的方法
- C#編程實(shí)現(xiàn)取整和取余的方法
相關(guān)文章
C#使用Data?Annotations進(jìn)行手動(dòng)數(shù)據(jù)驗(yàn)證
這篇文章介紹了C#使用Data?Annotations進(jìn)行手動(dòng)數(shù)據(jù)驗(yàn)證的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06Extjs4如何處理后臺(tái)json數(shù)據(jù)中日期和時(shí)間
本文給大家分享Extjs4如何處理后臺(tái)json數(shù)據(jù)中日期和時(shí)間,通過(guò)代碼示例給大家剖析,感興趣的朋友快來(lái)圍觀2015-08-08用NPOI創(chuàng)建Excel、合并單元格、設(shè)置單元格樣式、邊框的方法
本篇文章小編為大家介紹,用NPOI創(chuàng)建Excel、合并單元格、設(shè)置單元格樣式、邊框的方法。需要的朋友參考下2013-04-04C#實(shí)現(xiàn)文件上傳及文件下載功能實(shí)例代碼
文件上傳文件下載需求在項(xiàng)目中經(jīng)常會(huì)遇到,今天小編給大家分享C#實(shí)現(xiàn)文件上傳及文件下載功能實(shí)例代碼,需要的朋友參考下吧2017-08-08VSCode調(diào)試C#程序及附缺失.dll文件的解決辦法
這篇文章主要介紹了VSCode調(diào)試C#程序及附缺失.dll文件的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09C#中使用Socket獲取網(wǎng)頁(yè)源代碼的代碼
C#使用Socket獲取網(wǎng)頁(yè)源代碼的代碼,需要的朋友可以參考下。2010-12-12