使用C#实现支持人脸识别的本地照片管理工具

目录

前言

一、软件功能

1.添加/删除人脸库

2.添加/删除照片库目录

3.检索照片

4.新增加了:视频中人脸识别

5.新增加了:照片、视频播放器

二、开发中碰到的坑

1.DllImport调用问题

2.照片显示数量大而加载慢

总结


 

使用C#实现支持人脸识别的本地照片管理工具_第1张图片


使用C#实现支持人脸识别的本地照片管理工具_第2张图片 

使用C#实现支持人脸识别的本地照片管理工具_第3张图片 

使用C#实现支持人脸识别的本地照片管理工具_第4张图片 

 

前言

家里存储的照片太多了,大概有4万多张,由于都是按照目录和时间管理的,现有目录又非常多(大概有近20多年的照片),所以基本很少翻看。希望能有一款支持人脸识别的照片管理工具,这样就看从大量照片中去查找照片,比如:可以查找照片中同时出现人物A、人物B、人物C的照片。自己去试用很多现成的软件,但都不符合我的需求,所以自己动手写了这个小工具。

 


 

一、软件功能

从C#写的支持人脸识别的本地照片管理工具,采用百度人脸识别离线SDK识别人脸,可管理十万级,具体功能:

1.添加/删除人脸库

自主选择包含人脸的照片进行标注,或者随机从照片库选择一张人脸照片标注。

2.添加/删除照片库目录

添加或删除管理的照片目录,会管理该目录下所有照片。

3.检索照片

支持人脸识别检索照片,最多可以同时选择三张不同的人脸进行交集检索。

4.新增加了:视频中人脸识别

增加了视频识别功能,支持支持照片(jpg,jpeg,png,bmp)和视频(avi,mp4,mpg,mpeg)的人脸识别、检索。

5.新增加了:照片、视频播放器

采用LVC库,增加了软件内对照片、视频的浏览,照片支持滚动放大、拖动;视频支持播放、进度条控制、音量控制等。

二、开发中碰到的坑

1.DllImport调用问题

采用DllImport的方式调用百度人脸识别离线SDK,发现如果跨线程调用该SDK中的函数,程序会莫名其妙的奔溃,调试后发现原因:尝试读取或写入 protected 内存。原因是DllImport调用的函数不能跨线程使用,所以我将所有涉及到百度人脸识别离线SDK的功能封装在一个线程(一个thread)中,这个线程始终循环等待命令,线程内的核心代码:

public class UpdatePhoto{
    public static bool running = false;
    public static ManualResetEvent signal= new ManualResetEvent(false);
    public static string function_name = "";
    public void run() {
            while (true)
            {
                signal.WaitOne();
                signal.Reset();
                running = true;
                //TODO
                 
                running =false;
            }
    }
}

需要调用该线程的时候,采用以下代码:

if (UpdatePhoto.running)
{
    MessageBox.Show("有其它操作正在进行,请等待完成,其它操作为:"+UpdatePhoto.cur_task_name);
}else
{
    UpdatePhoto.function_name = "update_undo_photo_face";
    UpdatePhoto.cur_task_name = "识别还未识别的照片人脸";
    UpdatePhoto.signal.Set();
}

2.照片显示数量大而加载慢

检索照片时,照片显示用ListView+ImageList,但是如果照片的数量很多,会造成ListView加载非常慢,并且由于需要读取照片缩略图,导致I/O非常大,由于IO瓶颈,照片缩略图显示非常慢。为此,首先我们采用事先计算好每张照片的缩略图(100*100),并把缩略图存储在sqlite数据库中,这样当需要展示缩略图的时候,就不需求要重复读取照片原文件再计算缩略图,这样就可以解决掉IO瓶颈的问题。其次,对于LiewView加载大力照片缓慢的问题,我们采用虚拟化的ListView。最后,加载缩略图时候我们单独开个线程来分批加载。代码如下:


private List ItemsSource = new List();
private void button1_Click(object sender, EventArgs e)
        {
            List face_name_list = new List();
            if (comboBox1.Text != "") {
                face_name_list.Add(comboBox1.Text);
            }
            if (comboBox2.Text != "" && comboBox2.Text != "--不选择--")
            {
                face_name_list.Add(comboBox2.Text);
            }
            if (comboBox3.Text != "" && comboBox3.Text != "--不选择--")
            {
                face_name_list.Add(comboBox3.Text);
            }
            if (face_name_list.Count==0)
            {
                MessageBox.Show("请至少选择一个人物名称。");
                return;
            }
            face_name_list.Sort();
            string key_word = "";
            foreach(string word in face_name_list) {
                key_word = key_word + "["+word+"]";
            }
            imageList1.Images.Clear();
            listView1.Items.Clear();
            listView1.LargeImageList = imageList1;
            listView1.View = View.LargeIcon;
            PhotoView.file_path_list.Clear();

            imageList1.Images.Clear();
            listView1.Items.Clear();
            listView1.LargeImageList = imageList1;
            listView1.View = View.LargeIcon;
            param.Clear();
            param.Add(new SQLiteParameter("@face_name", key_word));
            //MessageBox.Show("!");
            DataTable dt = slh.ExecuteQuery("select b.path,b.image,b.to_delete from photo_file b,photo_facename a where a.face_name = @face_name and a.file_id=b.id order by b.shooting_time desc", param.ToArray());
            //MessageBox.Show("2");
            PhotoView.file_path_list.Clear();
            ItemsSource.Clear();
            Bitmap common_bitmap = new Bitmap(100, 100);
            /* if (dt.Rows.Count >= 1000) {
                 MessageBox.Show("查询结果超过了1000张,本次随机显示1000张。单击查询,可再次随机显示其它照片");
             }*/
            if (dt.Rows.Count == 0)
            {
                MessageBox.Show("没有搜索到有关的照片!");
            }
            else {
                MessageBox.Show("共搜索有关照片"+dt.Rows.Count+"张!");
            }
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                if (dt.Rows[i][1] == null) continue;
                //if ((bool)dt.Rows[i][2]) { continue; }
                ListViewItem lvItem = new ListViewItem();
                lvItem.Tag = dt.Rows[i][0].ToString();
                lvItem.ImageIndex = ItemsSource.Count;
                lvItem.Text = (ItemsSource.Count + 1)+"";
                ItemsSource.Add(lvItem);
                //imageList1.Images.Add( common_bitmap);
                imageList1.Images.Add(System.Drawing.Image.FromStream(new MemoryStream((byte[])dt.Rows[i][1])));
                
                PhotoView.file_path_list.Add(dt.Rows[i][0].ToString());
            } 
            setStatusBar("状态:共检索到" + ItemsSource.Count + "张相关照片!");

            listView1.VirtualListSize = ItemsSource.Count;
        }
        void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
            if(ItemsSource==null || ItemsSource.Count == 0)
            {
                return;
            }
            e.Item = ItemsSource[e.ItemIndex];
        }

总结

如果需要下载本软件,请访问我在CSDN上发布的资源。

 

 

你可能感兴趣的:(软件开发,c#)