河南大学指纹识别C#实现
这是我第一个比较自己写的比较成功的应用。创新实践选的是赵建辉老师的指纹识别。基于zk4500指纹识别仪的开发,教材给出了C++实现的实例,可能是VS版本的原因,我照着书上敲的代码一模一样都能报错,也是醉了。所以我改用比较熟悉的C#开发。只是成品功能均已经实现,只是界面还有一些细节仍有很大的改进空间。我想分享一下开发中遇到的问题,急于寻找源码的同学可以直接跳过,我会在文末附上百度网盘链接。
这是老师所给资源的目录:
其中,Sample文件夹下是实例程序,包括C
实时显示指纹图像
第一个问题:如何实现连接指纹仪使界面实时显示采集到的指纹图像主要是调用开发文档
4.1.9 sensorCapture
[函数]
int __stdcall sensorCapture(HANDLE handle, unsigned char
*imageBuffer, int imageBufferSize)
[功能]
从指纹采集器中采集图像
[参数说明]
handle
[in] sensorOpen 返回的句柄
imageBuffer
[in,out] 返 回 采 集 到 的 图 像 , 申 请 空 间 大 小 调 用
sensorGetParameter(106)
imageBufferSize
[in] imageBuffer 申请空间的大小
[返回值]
0 采集到图像的大小
0 没有采集到图像
-2 handle 或 imageBuffer 为空
-3 申请空间大小小于采集到图像空间大小
Sample C#示例下已经有相关实现。我是拷贝过来的。只是出现了问题,原因在于,所给示例是winForm,我用的是WPF。
winForm相关代码如下:
Thread captureThread = new Thread(new ThreadStart(DoCapture));
captureThread.IsBackground = true;
captureThread.Start();
g_bIsTimeToDie = false;
DoCapture:
private void DoCapture()
{
while (!g_bIsTimeToDie)
{
int ret = ZKFPCap.sensorCapture(g_Handle, g_FPBuffer, g_FPBufferSize);
if (ret > 0)
{
SendMessage(g_FormHandle, MESSAGE_FP_RECEIVED, IntPtr.Zero, IntPtr.Zero);
}
}
}
指纹图像显示
protected override void DefWndProc(ref Message m)
{
switch (m.Msg)
{
case MESSAGE_FP_RECEIVED:
{
try
{//可以借鉴
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(g_FPBuffer, g_nWidth, g_nHeight, ref ms);
Bitmap bmp = new Bitmap(ms);
this.picFP.Image = bmp;
//可以借鉴
txtStatus.Text = "IMAGE_READY";
int ret = 0;
int id = 0;
int score = 0;
int quality = 0;
if (g_IsRegister)
{
Array.Clear(g_RegTmp, 0, g_RegTmp.Length);
ret = ZKFinger10.BIOKEY_EXTRACT(g_biokeyHandle, g_FPBuffer, g_RegTmp, 0);
if (ret > 0)
{
Array.Copy(g_RegTmp, g_RegTmps[g_RegisterTimeCount++], ret);
// Get fingerprint quality
quality = ZKFinger10.BIOKEY_GETLASTQUALITY();
txtQuality.Text = quality.ToString();
txtPrompt.Text = string.Format("Still press finger {0} time", REGISTER_FINGER_COUNT - g_RegisterTimeCount);
if (g_RegisterTimeCount == REGISTER_FINGER_COUNT)
{
Array.Clear(g_RegTmp, 0, g_RegTmp.Length);
int size = 0;
/*unsafe
{
fixed (byte* Template1 = g_RegTmps[0])
{
fixed (byte* Template2 = g_RegTmps[1])
{
fixed (byte* Template3 = g_RegTmps[2])
{
byte*[] pTemplate = new byte*[3] { Template1, Template2, Template3 };
size = ZKFinger10.BIOKEY_GENTEMPLATE(g_biokeyHandle, pTemplate, 3, g_RegTmp);
}
}
}
}*/
size = ZKFinger10.BIOKEY_GENTEMPLATE_SP(g_biokeyHandle, g_RegTmps[0], g_RegTmps[1], g_RegTmps[2], 3, g_RegTmp);
if (size > 0)
{
ZKFinger10.BIOKEY_DB_ADD(g_biokeyHandle, ++g_RegisterCount, size, g_RegTmp);
txtPrompt.Text = string.Format("Register succeeded, fid={0}, totalCount={1}", g_RegisterCount, ZKFinger10.BIOKEY_DB_COUNT(g_biokeyHandle));
g_IsRegister = false;
}
else
{
txtPrompt.Text = "Register failed";
}
g_RegisterTimeCount = 0;
}
}
else
{
txtPrompt.Text = "Extract template failed";
}
}
else
{
Array.Clear(g_VerTmp, 0, g_VerTmp.Length);
if ((ret = ZKFinger10.BIOKEY_EXTRACT(g_biokeyHandle, g_FPBuffer, g_VerTmp, 0)) > 0)
{
// Get fingerprint quality
quality = ZKFinger10.BIOKEY_GETLASTQUALITY();
txtQuality.Text = quality.ToString();
ret = ZKFinger10.BIOKEY_IDENTIFYTEMP(g_biokeyHandle, g_VerTmp, ref id, ref score);
if (ret > 0)
{
txtPrompt.Text = string.Format("Identification success, id={0}, score={1}", id, score);
}
else
{
txtPrompt.Text = string.Format("Identification failed, score={0}", score);
}
}
else
{
txtPrompt.Text = "Extract template failed";
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
break;
default:
base.DefWndProc(ref m);
break;
}
}
Windows中的Message参见博文:https://www.cnblogs.com/ltt1987/archive/2006/06/01/414868.html
照搬进WPF是行不通的。因此我对DoCaputre做了相应的修改:
private void DoCapture()
{
while (!g_bIsTimeToDie)
{
int ret = ZKFPCap.sensorCapture(g_Handle, g_FPBuffer, g_FPBufferSize);
if (ret > 0)
{
//SendMessage(g_FormHandle, MESSAGE_FP_RECEIVED, IntPtr.Zero, IntPtr.Zero);
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(g_FPBuffer, g_nWidth, g_nHeight, ref ms);
Bitmap bt = new Bitmap(ms);
ShowImg(bt);
// pic1.Image = bmp;
}
}
}
ShowImage:
private void ShowImg(Bitmap bt)
{
//.Net框架下不允许一个线程中直接访问另一个线程的控件,因此下一行的写法是错误的,运行会出问题
//img1.Source = ImageTranslater.BitmapToBitmapImage(bt);
img1.Dispatcher.Invoke(() =>
{
img1.Source = ImageTranslater.BitmapToBitmapImage(bt);
});
}
ImageTranslater.BitmapToBitmapImage(Bitmap bt):实现Bitmap->BitmapImage;由于我用的是WPF的Image控件,因此需要这一步转换。
指纹信息入库
将采集到的指纹信息存入数据库中。
所建数据库如图

其中,Name->被采集人姓名
Age->被采集人年龄
Grade–>被采集人年级
PBuffer ->被采集人图像数据(字节数组)
相关代码:
case "指纹登记":
StateChange(false);
if (textBox_Grade.Text == null || textBox_Name.Text == null || textBox_Sno.Text == null || textBox_Grade.Text == "" || textBox_Name.Text == "" || textBox_Sno.Text == "")
{
MessageBox.Show("内容不能为空,请重新填写!");
}
else
{
FingerDatas fd = new FingerDatas();
fd.Name = textBox_Name.Text;
fd.Sno = textBox_Sno.Text;
fd.Grade = textBox_Grade.Text;
fd.PBuffer = g_FPBuffer;
using (FingerDataEntities context = new FingerDataEntities())
{
try
{
context.FingerDatas.Add(fd);
context.SaveChanges();
MessageBox.Show("保存成功");
}
catch (Exception ex)
{
MessageBox.Show("数据保存失败,发生错误:" + ex.Message);
}
}
}
textBox_Grade.Clear();
textBox_Name.Clear();
textBox_Sno.Clear();
img2.Source = null;
break;
指纹识别
主要是算法库的两个算法:
根据指纹图像生成模板的算法:
4.2.6 BIOKEY_EXTRACT
[函数]
int __stdcall BIOKEY_EXTRACT(HANDLE handle, BYTE*
PixelsBuffer, BYTE *Template, int PurposeMode)
[功能]
从指纹图像中提取指纹模板
[参数说明] handle
[in] BIOKEY_INIT 返回的句柄
PixelsBuffer
[in] 采集到的指纹图像
Template
[in,out] 返回提取的指纹模板
PurposeMode
[in] 保留,默认为 1 [返回值]
0 提取的指纹模板长度
0 失败
根据模板进行指纹的匹配:
4.2.17 BIOKEY_VERIFY
[函数]
int __stdcall BIOKEY_VERIFY(HANDLE handle, BYTE
*Template1, BYTE *Template2)
[功能]
两个模板进行 1:1 比对
[参数说明] handle
[in] BIOKEY_INIT 返回的句柄
Template1
[in] 待比对的指纹模板
Template2
[in] 待比对的指纹模板
[返回值]
0 1:1 比对的分数
0 比对失败
实现代码:
case "指纹识别":
StateChange(true);
byte[] newFinger = g_FPBuffer;
byte[] newFingerModel = new byte[2048];
string resultStr;
using (FingerDataEntities context = new FingerDataEntities())
{
try
{
var q1 = from t in context.FingerDatas
select new {t.Name,t.Sno,t.Grade,t.PBuffer} ;
if (q1.Equals(null))
{
MessageBox.Show("数据库不包含任何指纹信息,请录入指纹信息!" );
break;
}
else
{
int match = 0;
int result_extract = ZKFinger10.BIOKEY_EXTRACT(g_biokeyHandle, newFinger, newFingerModel, 0);
if (result_extract > 0)
{
foreach(var q in q1)
{
byte[] q_FingerModel = new byte[2048];
byte[] q_Finger = q.PBuffer;
ZKFinger10.BIOKEY_EXTRACT(g_biokeyHandle, q_Finger, q_FingerModel, 0);
match = ZKFinger10.BIOKEY_VERIFY(g_biokeyHandle, newFingerModel, q_FingerModel);
if (match > 0)
{
resultStr = string.Format("识别成功,匹配到的指纹信息为:\n 姓名:{0}\n 学号:{1} \n 年级:{2} \n 相似度:{3}%", q.Name, q.Sno, q.Grade, match);
MemoryStream ms = new MemoryStream();
BitmapFormat.GetBitmap(q_Finger, g_nWidth, g_nHeight, ref ms);
Bitmap bt = new Bitmap(ms);
BitmapImage bi = ImageTranslater.BitmapToBitmapImage(bt);
img2.Source = bi;
MessageBox.Show(resultStr);
break;
}
}
if (match == 0)
{
resultStr = "数据库中未找到与之相似的指纹信息,请录入信息后再次尝试";
MessageBox.Show(resultStr);
}
}
else
{
MessageBox.Show("出现意外");
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show("发生错误:" + ex.Message);
}
}
break;
尾声
本来打算用C#将书上的图像处理算法一一实现,无奈处理的结果太差劲,最后只能取巧,调用现成的算法库。虽然没能自己实现算法,在这个过程中,自己学到了许多东西,多少也算有所收获。最后,放上百度网盘链接,需要的同学可以自行下载。
2024-10-31
评论里放不出来链接,就在这里更新百度网盘链接:
链接:https://pan.baidu.com/s/1-q4PZlBOTiQvaybalywBuw 提取码:8888