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

目录

前言

一、软件功能

1.添加/删除人脸库

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

3.检索照片

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

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

二、开发中碰到的坑

1.DllImport调用问题

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

总结


 

6fafc3d6e406496485285df0cace9c1f.jpg


335a3a78b68842029d8063aec029d935.jpg 

c4588481b4db42b791b48fb55270cbe0.jpg 

d2bead1041fa461cbed1104f46129774.jpg 

 

前言

家里存储的照片太多了,大概有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<ListViewItem> ItemsSource = new List<ListViewItem>();
private void button1_Click(object sender, EventArgs e)
        {
            List<string> face_name_list = new List<string>();
            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上发布的资源。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
一、主要内容:OpenCV能够实现强大丰富的图像处理,但是它缺少一个能够支持它运行的界面。Csharp经过多年的发展,得益于它的“所见及所得”能力,非常方便编写界面。这两者如果能够“双剑合璧”,将有效帮助实际工作产出。本课着重推荐GOCW采用“Csharp基于CLR直接调用Opencv编写的算法库”方法,能够将最新的OpenCV技术引入进来,同时保证生成程序的最小化。    为了进一步说明Csharp和OpenCV的结合使用,首先一个较为完整的基于winform实现答题卡识别的例子,相比较之前的实现,本次进一步贴近生产实际、内涵丰富,对算法也进行了进一步提炼。同时我们对WPF下对OpenCV函数的调用、OpenCV.js的调用进行相关教授。       二、课程结构1、 EmguCV、OpenCVSharp和GOCW之间进行比较(方便代码编写、能够融入最新的算法、速度有保障、方便调试找错、拒绝黑箱化);2、视频采集模块的构建,视频采集和图像处理之间的关系;3、视频采集专用的SDK和“陪练”系统的介绍;4、在视频增强类项目中和图像处理项目中,算法的选择;5、Csharp界面设计、图片的存储和其他构建设计;6、较为完整的答题卡识别例子,兼顾界面设计和算法分析;8、WPF基于GOCW也同样可以基于GOCW实现算法调用;webForm虽然也可以通过类似方法调用,但是OpenCV.JS的方法更现代高效。9、关于软件部署的相关要点和窍门。       三、知识要点:1、基本环境构建和程序框架;2、CLR基本原理和应用方法;3、接入、采集、模拟输入;4、图像处理,通过构建循环采集图片;5、增强和实时处理;6、基于投影等技术的答题卡识别算法;7、存储、转换;8、部署交付。        课程能够帮助你掌握Csharp调用Opencv的基本方法,获得相应框架代码和指导;从而进一步提升实现“基于图像处理”的解决方案能力。  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nxxjmpf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值