C#开发的人脸左右相似度计算软件源码分析
作者:小萝莉 发布时间:2023-08-26 05:18:41
标签: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#程序设计有所帮助。


猜你喜欢
- 简介本文用示例介绍SpringBoot如何解决BigDecimal传到前端后精度丢失问题。问题描述实例Controllerpackage c
- 什么是栈和队列栈如果用数组模拟的话是类似于一个U形桶状堆栈空间,地下是封口的,只能从顶部一个地方进出,它的进出都是有顺序的,看下图:如果是进
- 效果图:后来又出了两篇,也可以看一下Android选择与上传图片之PictureSelector教程Android选择与上传图片之Matis
- 当目标数据库不能直连的,需要一个服务器作为中间跳板的时候,我们需要通过SSH通道连接数据库。ps:使用ssh连接,相当于本地开了个端口去连接
- using System;using System.Collections.Generic;using System.Linq;using
- 本文章牵涉到的技术点比较多:spring Data JPA、Redis、Spring MVC,Spirng Cache,所以在看这篇文章的时
- 最近零碎时间一直在研究OpenGL,所以没怎么进行分享,以后可能大部分时间会学习系统底层\NDK\VR\AR等领域,话不多少,今天来分享个小
- 1.with 函数首先先从with函数开始,with函数接受两个参数,第一个参数可以是一个任意类型的对象,第二个参数是一个Lambda表达式
- 使用@Indexed加快启动速度Spring读取@Component组件(派生性),有两种实现方式,一种是反射,一种是ASM。反射性能低主要
- 这篇文章主要介绍了Spring Boot项目维护全局json数据代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- JAVA 中Spring的@Async用法总结引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在处理与第三方
- 项目开发中对于一些数据的处理需要用到多线程,比如文件的批量上传,数据库的分批写入,大文件的分段下载等。 通常会使用spring自带的线程池处
- 何为原子性原子性:一条线程在执行一系列程序指令操作时,该线程不可中断。一旦出现中断,那么就可能会导致程序执行前后的结果不一致。与数据库中的原
- 使用第三方json转换工具,阿里巴巴json转换工具Fastjson1.2.7。https://www.jb51.net/softs/530
- 1.Mybatis的Dao层实现1.1 传统开发方式1.1.1编写UserDao接口public interface UserDao { &
- 众所周知Web服务器与客户端之间的通信是使用HTTP协议的。HTTP是一个客户端和服务器端请求和应答的标准(TCP)。因为HTTP协议是基于
- 知乎是一个真实的网络问答社区,社区氛围友好、理性、认真,连接各行各业的精英。他们分享着彼此的专业知识、经验和见解,为中文互联网源源不断地提供
- SpringBoot整合第三方技术一、整合Junit新建一个SpringBoot项目使用@SpringBootTest标签在test测试包内
- 本文实例为大家分享Android通过Movie展示Gif格式图片的相关代码,供大家参考,具体内容如下public class CommonG
- 本文实例为大家分享了C# picturebox实现画图功能的具体代码,供大家参考,具体内容如下在Form上添加 一个pictureBox,一