人工智能开发实战照片智能搜索功能实现

内容提要

  1. 项目分析
  2. 预备知识
  3. 项目实战

一、项目分析

1、提出问题

随着人民生活水平的提高和手机照相功能的日趋完美,我们不经意中拍摄了很多值得回忆的时刻,一场说走就走的旅行途中也记录下许多令人心动的瞬间,不知不觉之中,我们身边保存了大量的生活相片。

然而,每当你想重温你或者他的系列照片时,或者想分享一张你特别满意的靓照,从众多的照片中一遍遍翻找这些照片的确是一件费时费力的事情。

既然AI无时不在我们身边,能否借助AI的人脸识别技术来帮助我自动整理出我想要的照片,实现照片的智能搜索呢?答案无疑是肯定的。

下面,我们就利用人脸识别技术和OpenCV工具,对相册中的照片进行自动挑选以解决上述问题。

2、解决方法

帮助人们从相册中找出指定人物的系列照片,对于人工操作而言,并不是一件困难的事情,但整理的效率可能不尽人意,毕竟手动翻阅每张照片是个耗时费力的事。

让计算机替代人来完成这个事,难点在于如何从被检照片中识别与目标人脸高度相似的人脸,如果被检照片中有此人,说明该照片就是你想要的那一张,否则,该照片被忽视。

因此,一种可行的方案是:首先训练计算机认识不同式样的同一系列人脸,让它知道其实这些照片上的人物是同为一个人,从而得到目标人脸训练模型。

其次,遍历相册中的每张照片,检测出该照片上所有的人脸,提取人脸特征值,然后用目标人脸训练模型依次对人脸特征值进行预测比对,如果两者之间只要有一次高度匹配,就保留该照片,立即进入下一张照片的搜索,如果均不匹配,则忽视该照片,进行下一张搜索,直至搜索完所有的照片。

最后,得到的所有保留照片就是智能搜索的结果,至此,整个智能搜索照片过程结束。

问题的解决方案如下图所示。

二、预备知识

利用OpenCV来智能搜索相片,有两个重要的环节:

一是人脸区域的检测,这要用到前面提到的人脸检测器;

二是基于人脸区域数据的人脸识别,这要用到人脸识别模型。

下面分别来了解OpenCV中人类检测器和人脸识别模型的使用。

1、人脸检测器

我们可以从网络资源上下载别人训练好的人脸分类器,也可以自己训练。在此我们使用表中默认的级联分类器来检测照片中的人脸。

案例1:检测照片中的所有人脸,并用矩形框出人脸区域。

文件case1.ipynb代码如下:

1	import cv2
2	import numpy as np
3	faceCascade=cv2.CascadeClassifier('data/haarcascade_frontalface_default.xml')
4	img=cv2.imread('data/pic1.JPG')
5	gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
6	faces=faceCascade.detectMultiScale(gray,1.3,5)
7	for (x,y,w,h)in faces:
8	    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,0),1)
9	cv2.imshow('pic',img)
10	cv2.waitKey(0)
11	cv2.destroyAllWindows()

为方便调用默认的级联人脸分类模型,将文件haarcascade_frontalface_default.xml拷贝到源程序所在位置的data文件夹下,通过代码行3来构建人脸分类器faceCascade。

代码行4读取照片文件pic1.jpg,在代码行5将其转换成灰度图像。

代码行6对灰度图像gray按搜索窗口比例系数为1.3、相邻矩形最小个数为5的扫描方式检测人脸,并返回检测到的人脸矩形框向量数组。

代码行7-8遍历该向量数组,在图像img中人脸的相应位置绘制出一个个的矩形框。

代码行9显示绘制有人脸矩形框的照片。

代码行10一直等待用户的按键响应,按任意键继续,并通过代码行11关闭所有的窗口。

程序的运行效果如下:

由上可以看出,照片中的两个人脸被成功检测出来,人脸的位置及大小数据如下所示:

2、人脸识别算法

目前OpenCV支持:特征脸EigenFace、线性判别分析脸FisherFace与直方图脸LBPHFace三种人脸识别方法。

OpenCV的扩展包opencv-contrib-python提供了相应的函数以方便构建上述三种人脸识别方法的模型,因此在使用人脸识别模型前,要执行以下命令安装OpenCV扩展包。

pip3 install opencv-contrib-python

扩展包提供的模型函数如下表所示:

由于LBPHFace算法不会受到光照、缩放、旋转和平移的影响,且执行性能高,通用性较好,是OpenCV中首选的人脸识别方案。

案例2:识别指定照片中的人是谁。

编写如下代码(case2.ipynb),以识别上图中的照片who.jpg人物是huangshuai还是limu

1	import cv2
2	import os
3	import numpy as np
4	images=[]
5	labels=[]
6	whoPath=''
7	name2num={'huangshuai':1,'limu':2}
8	num2name={1:'huangshuai',2:'limu'}
9	faceCascade=cv2.CascadeClassifier('data/haarcascade_frontalface_default.xml')
10	for root,dirs,filenames in os.walk('data\\case8-2\\'):
11	    for filename in filenames:
12	        if filename!='who.jpg':
13	            filePath=os.path.join(root,filename)
14	            img=cv2.imread(filePath,0)
15	            faces=faceCascade.detectMultiScale(img,1.3,3)
16	            name=filePath.split('\\')[-2]
17	            for (x,y,w,h) in faces:
18	                images.append(img[y:y+h,x:x+w])
19	                labels.append(name2num[name])
20	        else:
21	            whoPath=os.path.join(root,filename)
22	faceRecognizer=cv2.face.LBPHFaceRecognizer_create()
23	faceRecognizer.train(images,np.array(labels))
24	whoimg=cv2.imread(whoPath,0)
25	whoFace=faceCascade.detectMultiScale(whoimg,1.3,3)
26	for(x,y,w,h) in whoFace:
27	    pred_index,conf_score=faceRecognizer.predict(whoimg[y:y+h,x:x+w])
28	    print('待识别照片中的人是:',num2name[pred_index])
29	    print('置信度评分=',conf_score)

代码行4-5分别用列表images、labels保存用于训练人脸识别模型的人脸数据和标签数据。

在代码行7-8定义人物“huangshuai、limu”对应的标签号为“1、2”。

代码行9构建一个人脸分类器faceCascade。

代码行10-21对指定目录data\case8-2\下的文件夹及文件进行遍历,如果文件不是待识别照片who.jpg,则将它们作为训练集。

在代码行15检测出人脸,并在代码行18-19将人脸数据和标签值分别保存到列表images和labels中;若是待识别照片,则在代码行21保存其路径。

代码行22构建一个LBPHFace类型的人脸识别模型,并在代码行23利用人脸数据集images和标签集labels对该模型进行训练。

代码行26-29对照片who.jpg中的人脸进行识别。

在代码行27用训练好的模型对该照片的面部进行预测,返回人物标签值pred_index和置信度评分conf_score,并在代码行28-29分别打印出识别的人物姓名和置信度评分。

程序的运行效果如下所示:

需要指出的是,对人脸识别模型的训练,训练集越多,预测效果越好。

模型一旦训练好后,可以以XML文件的形式将其保存起来,以便下次直接读取调用,以避免每次预测前都要训练一次的麻烦。

三、项目实战

3.1 训练目标人脸识别模型

文件夹persons中有目标人物的几张照片,用照片中的人脸集去训练人脸识别模型,让模型“认识”该人脸,并保存该模型,以便后续利用该模型去“辨认”照片集中的面相。

新建文件task1.ipynb,根据任务目标,按照以下步骤和操作,完成任务一。

任务目标:

提取照片中的人脸数据构成训练集,使用训练集对LBPHFace人脸模型进行训练,将训练好的模型保存起来。

完成步骤:

(1)构建一个人脸检测器

(2)生成目标人脸数据的训练集

(3)训练人脸识别模型

1、构建一个人脸检测器

为方便代码重用,在文件task1.ipynb中定义函数get_face_cascade,以构建一个人脸检测器,代码如下。

1	import cv2
2	import os
3	import numpy as np
4	def get_face_cascade(model_file):
5	    faceCascade=cv2.CascadeClassifier(model_file)#利用cv2中已训练好的人脸检测文件model_file来构建一个人脸检测器faceCascade。
6		return faceCascade

2、生成目标人脸数据训练集

根据前面的解决方案,需要获取目标对象的人脸数据和标签值,作为人脸识别模型的训练集。

编写代码如下,得到训练集。

1	def get_faces_trains(file_path,model_file):
2	    images=[]
3	    labels=[]
4	    faceCascade=get_face_cascade(model_file)
5	    for file in os.listdir(file_path):
6	        filePath=os.path.join(file_path,file)
7	        img=cv2.imread(filePath,0)
8	        faces=faceCascade.detectMultiScale(img,1.3,3)
9	        x,y,w,h=faces[0]
10	        images.append(img[y:y+h,x:x+w])
11	        labels.append(1)
12		return images,labels
13	images,labels=get_faces_trains('data/persons/','data/haarcascade_frontalface_default.xml')

代码行2-3定义的变量分别保存人脸数据和人脸标签。

代码行5-11遍历文件目录file_path下所有的目标人物照片文件,在代码行7读入灰度图。

在代码行8利用人脸分类器对灰度图检测人脸,然后在代码行10-11分别保存人脸数据和标签值,因为已知训练照片属于同一个人,所以标签值相同。

代码行13利用定义好的函数get_faces_trains来获取data/persons目录下目标人脸的训练数据。

3、训练人脸识别模型

有了步骤2的训练数据,就可以对LBPHFace模型进行训练,代码如下:

1	faceRecognizer=cv2.face.LBPHFaceRecognizer_create()
2	faceRecognizer.train(images,np.array(labels))
3	faceRecognizer.save('data/models/my_LBPHfaceRec.xml')

因为标签集labels是列表类型,需要转换成向量类型,然后在代码行2对人脸识别模型进行训练,并在代码行3将训练好的模型保存起来,以备后续随时调用。

至此,我们就得到了一个可用于搜索照片的人脸识别模型。

3.2 找到与某个用户最相似的n个用户

任务一已经按照指定的人物照片训练好了人脸识别模型,那么下一步我们就可以利用该模型,去照片集中帮我们找到想要的照片。

根据任务目标,按照以下步骤和操作,完成任务二。

任务目标:

搜索照片集中与目标人脸高度相似的照片,并显示搜索结果。

完成步骤:

(1)加载训练好的模型

(2)搜索照片集中要找的照片

1、加载训练好的模型

初始化人脸识别方法,读取训练好的模型文件,将其作为预测照片的人脸识别器。代码如下:

1	faceRecognizer1=cv2.face.LBPHFaceRecognizer_create()
2	faceRecognizer1.read('data/models/my_LBPHfaceRec.xml')

2、搜索照片集中要找的照片

有了人脸识别器faceRecognizer1,就定义如下方法search_photos,用它去寻找与目标人脸相似的照片,代码如下:

1	def search_photos(file_path,model_file):
2	    faceCascade=get_face_cascade(model_file)
3	    i=0
4	    for file in os.listdir(file_path):
5	        filePath=os.path.join(file_path,file)
6	        pred_img=cv2.imread(filePath)
7	        gray=cv2.cvtColor(pred_img,cv2.COLOR_BGR2GRAY)
8	        faces=faceCascade.detectMultiScale(gray,1.3,3)
9	        x,y,w,h=faces[0]
10	        pred_index,conf_score=faceRecognizer1.predict(gray[y:y+h,x:x+w])
11	        if conf_score<50:
12	            i+=1
13	            cv2.putText(pred_img,str(i),(x+int(w/2),y+int(h/2)),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),3) 
14	            cv2.imshow('foundImage',pred_img)
15	            cv2.waitKey(0)
16	        	cv2.destroyAllWindows()
17	search_photos('data/photos/','data/haarcascade_frontalface_default.xml')

代码行4-16是遍历目录file_path下的照片集,代码行7将读取的彩色图转换成灰度图。

代码行10用人脸识别器faceRecognizer1去预测当前人脸数据应归属于那一类、置信度如何。

其中代码行11-16是判断如果置信度分数<50,则说明当前照片与目标人脸高度相似,通过代码行13在人脸中间部位写上序号i,然后通过代码行14显示该图像。

代码行17是调用定义的函数search_photos,完成照片的搜索任务。

上述代码的运行效果如下图所示:

可以看出,找出的6张照片上的人物与原目标人脸是一个人,说明本次智能搜索是有效的。

当然,在实际应用过程中,不排除漏搜和多搜的情况,这是就要考虑通过调参、甚至更改人脸检测器和识别模型来改善搜索效果。

更多精彩内容请持续关注本站!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1547442.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【CSS in Depth 2 精译_040】6.3 CSS 定位技术之:相对定位(下)—— 用纯 CSS 绘制一个三角形

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09;第二章 相对单位&#xff08;已完结&#xff09;第三章 文档流与盒模型&#xff08;已完结&#xff09;第四章 Flexbox 布局&#xff08;已…

RabbitMQ应用

RabbitMQ 共提供了7种⼯作模式, 进⾏消息传递 一、七种模式的概述 1、Simple(简单模式) P&#xff1a;生产者&#xff0c;就是发送消息的程序 C&#xff1a;消费者&#xff0c;就是接收消息的程序 Queue&#xff1a;消息队列&#xff0c;类似⼀个邮箱, 可以缓存消息; ⽣产者…

【微服务即时通讯系统】——brpc远程过程调用、百度开源的RPC框架、brpc的介绍、brpc的安装、brpc使用和功能测试

文章目录 brpc1. brpc的介绍1.1 rpc的介绍1.2 rpc的原理1.3 grpc和brpc 2. brpc的安装3. brpc使用3.1 brpc接口介绍 4. brpc使用测试4.1 brpc同步和异步调用 brpc 1. brpc的介绍 1.1 rpc的介绍 RPC&#xff08;Remote Procedure Call&#xff09;远程过程调用&#xff0c;是一…

使用Postman搞定各种接口token实战

现在许多项目都使用jwt来实现用户登录和数据权限&#xff0c;校验过用户的用户名和密码后&#xff0c;会向用户响应一段经过加密的token&#xff0c;在这段token中可能储存了数据权限等&#xff0c;在后期的访问中&#xff0c;需要携带这段token&#xff0c;后台解析这段token才…

Java Stream流编程入门

流式编程 stream流式编程分为 首先转化为stream中间函数的链接最后的终结函数 怎么转化为stream 单列集合 List<String> list new ArrayList<String>(); Collections.addAll(list,"1","2","3","4","5","…

【MySQL】MVCC及其实现原理

目录 1. 概念介绍 什么是MVCC 什么是当前读和快照读 MVCC的好处 2. MVCC实现原理 隐藏字段 Read View undo-log 数据可见性算法 3. RC和RR隔离级别下MVCC的差异 4. MVCC&#xff0b;Next-key-Lock 防止幻读 1. 概念介绍 什么是MVCC Multi-Version Concurrency Cont…

FGPA实验——触摸按键

本文系列都基于正点原子新起点开发板 FPGA系列 1&#xff0c;verlog基本语法&#xff08;随时更新&#xff09; 2&#xff0c;流水灯&#xff08;待定&#xff09; 3&#xff0c;FGPA实验——触摸按键 一、触摸操作原理实现 分类&#xff1a;电阻式&#xff08;不耐用&…

LeetCode - 850 矩形面积 II

题目来源 850. 矩形面积 II - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个轴对齐的二维数组 rectangles 。 对于 rectangle[i] [x1, y1, x2, y2]&#xff0c;其中&#xff08;x1&#xff0c;y1&#xff09;是矩形 i 左下角的坐标&#xff0c; (xi1, yi1) 是该…

通信工程学习:什么是VIM虚拟化基础设施管理器

VIM:虚拟化基础设施管理器 VIM(Virtualized Infrastructure Manager)虚拟化基础设施管理器,是一种负责管理和控制虚拟化环境中所有虚拟资源的工具和系统。以下是关于VIM虚拟化基础设施管理器的详细解释: 一、定义与功能 VIM是网络功能虚拟化(NFV)架构中…

李宏毅机器学习2023-HW10-Adversarial Attack

文章目录 TaskBaselineFGSM (Fast Gradient Sign Method (FGSM)I-FGSM(Iterative Fast Gradient Sign Method)MI-FGSM(Momentum Iterative Fast Gradient Sign Method)M-DI2-FGSM(Diverse Input Momentum Iterative Fast Gradient Sign Method) Reportfgsm attackJepg Compress…

探索5 大 Node.js 功能

目录 单线程 Node.js 工作线程【Worker Threads】 Node.js 进程 进程缺点 工作线程 注意 集群进程模块【Cluster Process Module】 内部发生了什么&#xff1f; 为什么要使用集群 注意&#xff1a; 应用场景&#xff1a; 内置 HTTP/2 支持 这个 HTTP/2 是什么&…

Windows安装Vim,并在PowerShell中直接使用vim

大家好啊&#xff0c;我是豆小匠。 这期介绍下怎么在windows的PowerShell上使用vim&#xff0c;方便在命令行里修改配置文件等。 先上效果图&#xff1a; 1、下载Vim GitHub传送门&#xff1a;https://github.com/vim/vim-win32-installer/releases 选择win-64的版本下载即可&…

VS Code使用Git Bash终端

Git Bash可以运行linux命令&#xff0c;在VS Code的终端界面&#xff0c;找到号旁边的箭头&#xff0c;就能直接切换了 当然&#xff0c;前提是安装了Git Bash&#xff0c;并且在资源管理器里&#xff0c;能鼠标右键出"Git Bash Here"

node.js从入门到快速开发一个简易的web服务器

浏览器中JavaScript学习路径: JavaScript基础语法浏览器内置API(DOMBOM)第三方库(jQuery,art-template等) Node.js的学习路径 JavaScript基础语法Node.js内置API模块(fs、path、http等)第三方API模块(express、mysql等) Node.js安装 通过Node.js 来运行Javascript 代码&am…

[已解决]npm install报错

问题分析&#xff1a; 想执行文件夹下的npm install&#xff0c;通过以及cmd进入&#xff0c;都会报错权限不够 如下报错&#xff08;哪一张不清楚&#xff0c;只知道是权限不够导致的&#xff09; 问题解决&#xff1a; 搜索Windows powershell 然后用管理员权限启动&#x…

【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器

文章目录 C list 容器详解&#xff1a;从入门到精通前言第一章&#xff1a;C list 容器简介1.1 C STL 容器概述1.2 list 的特点 第二章&#xff1a;list 的构造方法2.1 常见构造函数2.1.1 示例&#xff1a;不同构造方法2.1.2 相关文档 第三章&#xff1a;list 迭代器的使用3.1 …

基于skopt的贝叶斯优化基础实例学习实践

贝叶斯方法是非常基础且重要的方法&#xff0c;在前文中断断续续也有所介绍&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a; 《数学之美番外篇&#xff1a;平凡而又神奇的贝叶斯方法》 《贝叶斯深度学习——基于PyMC3的变分推理》 《模型优化调参利器贝叶斯优化bay…

使用API有效率地管理Dynadot域名,设置域名服务器(NS)

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…

Type-C接口相关知识:【总结大全】

Type-c现在非常通用了&#xff0c;所以了解Type-c也变得十分有必要了&#xff0c;还是秉承了解就要了解清楚的原则&#xff0c;我们深入的看看Type-c接口。 Type-c主要是取代上一代Micro usb接口&#xff0c;那么Type-c有什么优点呢&#xff1f; 正反可插&#xff0c;使用时不…

电脑usb接口封禁如何实现?5种禁用USB接口的方法分享!(第一种你GET了吗?)

“防患于未然&#xff0c;安全始于细节。”在信息技术飞速发展的今天&#xff0c;企业的信息安全问题日益凸显。 USB接口作为数据传输的重要通道&#xff0c;在带来便利的同时&#xff0c;也成为了数据泄露和安全风险的高发地。 因此&#xff0c;对电脑USB接口进行封闭管理&a…