基于opencv+ImageAI+tensorflow的智能动漫人物识别系统——深度学习算法应用(含python、JS、模型源码)+数据集(三)

目录

  • 前言
  • 总体设计
    • 系统整体结构图
    • 系统流程图
  • 运行环境
    • 爬虫
    • 模型训练
    • 实际应用
  • 模块实现
    • 1. 数据准备
      • 1)爬虫下载原始图片
      • 2)手动筛选图片
    • 2. 数据处理
      • 1)切割得到人物脸部
      • 2)重新命名处理后的图片
      • 3)添加到数据集
    • 3. 模型训练及保存
      • 1)设置基本参数
      • 2)模型保存
      • 3)模块预测
  • 相关其它博客
  • 工程源代码下载
  • 其它资料下载


在这里插入图片描述

前言

本项目通过爬虫技术获取图片,利用OpenCV库对图像进行处理,识别并切割出人物脸部,形成了一个用于训练的数据集。通过ImageAI进行训练,最终实现了对动漫人物的识别模型。同时,本项目还开发了一个线上Web应用,使得用户可以方便地体验和使用该模型。

首先,项目使用爬虫技术从网络上获取图片。这些图片包含各种动漫人物,其中我们只对人物脸部进行训练,所以我们会对图像进行处理,并最终将这些图像将作为训练数据的来源。

其次,利用OpenCV库对这些图像进行处理,包括人脸检测、图像增强等步骤,以便准确识别并切割出人物脸部。这一步是为了构建一个清晰而准确的数据集,用于模型的训练。

接下来,通过ImageAI进行训练。ImageAI是一个简化图像识别任务的库,它可以方便地用于训练模型,这里用于训练动漫人物的识别模型。

最终,通过项目开发的线上Web应用,用户可以上传动漫图像,系统将使用训练好的模型识别图像中的动漫人物,并返回相应的结果。

总的来说,本项目结合了爬虫、图像处理、深度学习和Web开发技术,旨在提供一个便捷的动漫人物识别服务。这对于动漫爱好者、社交媒体平台等有着广泛的应用前景。

总体设计

本部分包括系统整体结构图和系统流程图。

系统整体结构图

系统整体结构如图所示。

在这里插入图片描述

系统流程图

系统流程如图所示。

在这里插入图片描述

运行环境

本部分包括爬虫、模型训练及实际应用运行环境。

爬虫

安装Python3.6以上及Selenium3.0.2版本。

详见博客。

模型训练

本部分包括安装依赖、安装ImageAI。

详见博客。

实际应用

实际应用包括前端开发环境和后端环境的搭建。

详见博客。

模块实现

本项目包括4个模块:数据准备、数据处理、模型训练及保存、模型测试,下面分别介绍各模块的功能及相关代码。

1. 数据准备

本项目的数据来自于百度图片,通过爬虫获取。

1)爬虫下载原始图片

详见博客。

2)手动筛选图片

部分人物的名称、现实事物或人物有重名现象,加上一些图片质量不佳,需要人为剔除,手动筛选。

详见博客。

2. 数据处理

将图片中的人脸裁剪进行模型训练,切割人脸部分由OpenCV通过训练好的动漫人物脸部识别模型lbpcascade_animeface截取人物脸部。GitHub下载地址为https://github.com/nagadomi/lbpcascade_animeface。

1)切割得到人物脸部

相关代码如下:

#基本参数设定
SRC = "Raw"    #待处理的文件路径
DST = "Data"   #处理后的文件路径
TRAIN_PER = 5  #训练的图片比例
TEST_PER = 1   #测试的图片比例
#处理原图片得到人物脸部图片并按比例分配训练和测试用于训练模型
for image_file in files:  #读取所有图片image_file = image_file.replace('\\', '/')  #解决Windows下的文件路径问题target_path = "/".join(image_file.strip("/").split('/')[1:-1])target_path = os.path.join(dst, target_path) + "/"if not os.path.exists(target_path):os.makedirs(target_path)
count = len(os.listdir(target_path)) + 1
image = cv2.imdecode(np.fromfile(image_file, dtype=np.uint8), -1)  
#解决中文路径读入图片问题gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  #OpenCV的设置gray = cv2.equalizeHist(gray)  #转化为灰度图片faces = cascade.detectMultiScale(gray,scaleFactor=1.05,  #指定每个图像缩放比例,缩小图像大小的参数minNeighbors=4,    #此参数将影响检测到的面孔,值越高,检测结果越少,质量越好minSize=(24, 24)   #最小对象大小或者小于此值的对象将被忽略for (x, y, w, h) in faces:crop_img = image[y:y + h, x:x + w]crop_img = cv2.resize(crop_img, (96, 96))  #重置为96*96filename = os.path.basename(image_file).split('.')[0]   cv2.imencode('.jpg',crop_img)[1].tofile(os.path.join(target_path, str(count) + ".jpg")) #保存切割的脸部

处理前和处理后的效果如图所示。

在这里插入图片描述

处理前图片

在这里插入图片描述

处理后图片

2)重新命名处理后的图片

对于处理后的图片,需要重新指定文件名称以便于统计和处理。相关代码如下:

def rename_files(dir, prefix='', joiner='_', startNum=0,changeType='', ignoreType='', typeOnly=''):'''重命名一个文件夹中的所有文件Args:dir(string):  重命名文件夹的路径prefix(string):  文件名前缀joiner(string):  连接文件名前缀和数字的连接符,默认为下划线startNum(int):  重命名文件的开始数字,默认为0changeType(string):  把文件重命名为指定类型,默认不指定类型typeOnly(string):  只处理指定类型的文件,使用空格分割,例如“.jpg .jpeg .png .bmp .webp”ignoreType(string):  忽略处理文件的类型,使用空格分割,例如,“.py .docx”'''for root, _, files in os.walk(dir):root = root.replace('\\', '/')if prefix == '':prefix = root.split('/')[-1]count = startNumfor file in files:true_type = os.path.splitext(file)[-1]  #文件真实类型type_list = typeOnly.split()ignore_list = ignoreType.split()if true_type in type_list or len(type_list) == 0:if true_type in ignore_list:continueif changeType == '':  #是否指定改变类型file_type = true_typeelse:file_type = changeTypenew_name = "{}{}{}{}".format(prefix, joiner, str(count), file_type)path = os.path.join(root, new_name)old_path = os.path.join(root, file)if old_path == path:continueif not os.path.exists(path):os.rename(old_path, path)count = count + 1
def main():parser = argparse.ArgumentParser(description="重命名指定文件夹下的所有文件")parser.add_argument("dir", type=str, help="重命名文件的路径")parser.add_argument("--prefix", "-p", type=str,default='', help="前缀,默认为文件名")parser.add_argument("--joiner", "-j", type=str, default="_", help="连接符")parser.add_argument("--startNum", "-s", type=int, default=0, help="开始数")parser.add_argument("--changeType", "-c", type=str,default='', help="重命名文件为指定类型")parser.add_argument("--ignoreType", "-i", type=str,default='', help="忽略处理的类型,使用空格分割")parser.add_argument("--typeOnly", "-t", type=str,default='', help="指定处理的类型,使用空格分割")args = parser.parse_args()rename_files(dir=args.dir, joiner="_temp_", ignoreType=args.ignoreType, typeOnly=args.typeOnly)rename_files(dir=args.dir, prefix=args.prefix, joiner=args.joiner, startNum=args.startNum,changeType=args.changeType, ignoreType=args.ignoreType, typeOnly=args.typeOnly)
print("Rename files finished")

3)添加到数据集

已经切割得到的脸部经过重新排序命名后,按照一定的比例添加到数据集。相关代码如下:

def divide_train_test(src, train_percentage=5, test_percentage=1):if not os.path.exists(src):print("folder %s is not exist" % src)returndirs = os.listdir(src)test_dir = os.path.join(src, "test")train_dir = os.path.join(src, "train")  #训练数据路径if not os.path.exists(test_dir):os.mkdir(test_dir)if not os.path.exists(train_dir):os.mkdir(train_dir)for dir_name in dirs:if dir_name != "test" and dir_name != "train":current_dir = os.path.join(src, dir_name)test_dir = os.path.join(src, "test", dir_name)  #测试集路径train_dir = os.path.join(src, "train", dir_name)  #训练集路径if not os.path.exists(test_dir):os.mkdir(test_dir)if not os.path.exists(train_dir):os.mkdir(train_dir)if os.path.isdir(current_dir):images = os.listdir(current_dir)image_num = len(images)for image in images:filename = os.path.basename(image).split('.')[0]if filename.isdigit():percentage = train_percentage + test_percentagetest_num = (image_num / percentage) * test_percentage + 1if int(filename) <= test_num:if not os.path.exists(os.path.join(test_dir, image)):shutil.move(os.path.join(current_dir, image), os.path.join(test_dir))else:os.remove(os.path.join(current_dir, image))else:if not os.path.exists(os.path.join(train_dir, image)):shutil.move(os.path.join(current_dir, image), os.path.join(train_dir))else:os.remove(os.path.join(current_dir, image))shutil.rmtree(current_dir)for dirs in os.listdir(src):for name in os.listdir(os.path.join(src, dirs)):if os.path.isdir(os.path.join(src, dirs, name)):rename_file(os.path.join(src, dirs, name))print("Set all cropped images to train and test")

3. 模型训练及保存

本部分包括设置基本参数、模型保存和模块预测。

1)设置基本参数

相关代码如下:

DATA_PATH = "Datas" #数据集路径
TRAIN_NUM = 30       #训练次数
BATCH = 5             #批次
model_trainer = ModelTraining()
model_trainer.setModelTypeAsResNet()        #训练算法
model_trainer.setDataDirectory(data_path)  #训练目录
model_trainer.trainModel(num_objects=num_obj,  
#该参数用于指定图像数据集中对象的数量
num_experiments=train_num,  #该参数用于指定图像训练的次数
enhance_data=True,  #该参数用于指定是否生成训练图像的副本以获得更好的性能
batch_size=batch,  #该参数用于指定批次数量,分批训练,直到所有批次训练集都完成为止
show_network_summary=True #该参数用于指定是否在控制台中显示训练的过程 

2)模型保存

模型每次训练完成都会输出一个.h5文件和对应的.json文件,如图1所示。model_class.json文件中包含人物名称,molde_ex-xxx_acc_xxxxxx.h5中ex后的数字表示训练次数,acc后的数字表示对应的精度。model_class.json文件中的人物名称如图2所示,采用Unicode编码。训练好的模型保存后可重复使用,也可移植到其他环境中使用。

在这里插入图片描述

图1 训练模型后输出结果

在这里插入图片描述

图2 model_class.json文件中的人物名称

3)模块预测

相关代码如下:

#设置基本参数
IMAGE_PATH = "uploader/"  #预测图片路径
MODEL_PATH = "data/models/model_ex-150_acc-0.883871.h5"  #模型路径
JSON_PATH = "data/json/model_class.json"  #json文件路径
RESULT_COUNT = 3  #显示预测结果的数量
prediction = CustomImagePrediction()  #初始化ResNet
prediction.setModelTypeAsResNet()  #设置ResNet模型
#预测函数
def predict(img_path, model_path=MODEL_PATH, json_path=JSON_PATH, result_count=RESULT_COUNT):if not os.path.exists(img_path):print("Can not found img %s" % img_path)returnwith open(json_path) as f:num_obj = len(json.load(f))print(num_obj)prediction.setModelPath(model_path)prediction.setJsonPath(json_path)prediction.loadModel(num_objects=num_obj)predictions, probabilities = prediction.predictImage(img_path, result_count=result_count)result = {}i = 1for eachPrediction, eachProbability in zip(predictions, probabilities):result[i]={eachPrediction: str(round(float(eachProbability), 2)) + '%' }i = i + 1print(result)return result

相关其它博客

基于opencv+ImageAI+tensorflow的智能动漫人物识别系统——深度学习算法应用(含python、JS、模型源码)+数据集(一)

基于opencv+ImageAI+tensorflow的智能动漫人物识别系统——深度学习算法应用(含python、JS、模型源码)+数据集(二)

基于opencv+ImageAI+tensorflow的智能动漫人物识别系统——深度学习算法应用(含python、JS、模型源码)+数据集(四)

工程源代码下载

详见本人博客资源下载页


其它资料下载

如果大家想继续了解人工智能相关学习路线和知识体系,欢迎大家翻阅我的另外一篇博客《重磅 | 完备的人工智能AI 学习——基础知识学习路线,所有资料免关注免套路直接网盘下载》
这篇博客参考了Github知名开源平台,AI技术平台以及相关领域专家:Datawhale,ApacheCN,AI有道和黄海广博士等约有近100G相关资料,希望能帮助到所有小伙伴们。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十大排序之归并排序(详解)

文章目录 &#x1f412;个人主页&#x1f3c5;算法思维框架&#x1f4d6;前言&#xff1a; &#x1f380;归并排序 时间复杂度O(n*logn)&#x1f387;1. 算法步骤思想&#x1f387;2、动画演示&#x1f387;3.代码实现 &#x1f412;个人主页 &#x1f3c5;算法思维框架 &#…

lvm 扩容根分区失败记录

lvm 扩容根分区失败记录 1、问题描述2、错误描述3、解决方法重启系统进入grub界面&#xff0c;选择kernel 2.x 启动系统。然后同样的resize2fs命令扩容成功。 1、问题描述 根分区不足。 系统有2个内核版本&#xff0c;一个是kernel 2.x&#xff0c;另一个是kernel 4.x。 这次l…

C语言剔除相关数(ZZULIOJ1204:剔除相关数)

题目描述 一个数与另一个数如果含有相同数字和个数的字符&#xff0c;则称两数相关。现有一堆乱七八糟的整数&#xff0c;里面可能充满了彼此相关的数&#xff0c;请你用一下手段&#xff0c;自动地将其剔除。 输入&#xff1a;多实例测试。每组数据包含一个n(n<1000)&#…

知行之桥EDI系统HTTP签名验证

本文简要概述如何在知行之桥EDI系统中使用 HTTP 签名身份验证&#xff0c;并将使用 CyberSource 作为该集成的示例。 API 概述 首字母缩略词 API 代表“应用程序编程接口”。这听起来可能很复杂&#xff0c;但真正归结为 API 是一种允许两个不同实体相互通信的软件。自开发以…

2023.11.25-电商项目建设业务学习1-指标,业务流程,核销

目录 1.指标分类(原子指标,派生指标,衍生指标) 2.一些业务名词 3.四大业务流程-销售需求 3.1-线上线下销售 3.2线上线下退款 4.四大业务流程-会员业务 5.四大业务流程-供应链业务 6.四大业务流程-商城业务 7.核销主题需求分析 1.指标分类(原子指标,派生指标,衍生指标) 原…

JVM类加载的过程和JVM垃圾回收机制

文章目录 一、JVM类加载的过程1.1类加载的基本流程1.1.1加载1.1.2验证1.1.3准备1.1.4解析1.1.5初始化 1.2双亲委派模型 二、JVM垃圾回收机制2.1找到垃圾2.1.1引用计数(比如Python&#xff0c;PHP中用到)2.1.2可达性分析(比如Java中用到) 2.2释放垃圾2.2.1标记清除2.2.2复制算法…

Nginx配置文件中的关键字是什么?详细解释来了

点击上方蓝字关注我 Nginx 是一款高性能的 Web 服务器软件&#xff0c;同时也是一款反向代理服务器软件。Nginx 的配置文件通常是 /etc/nginx/nginx.conf&#xff0c;以下是一个典型的配置文件&#xff0c;并对其中的关键字进行详细解释。 1. 配置文件 perlCopy codeuser ngin…

计算机编程零基础编程学什么语言,中文编程工具构件简介软件下载

计算机编程零基础编程学什么语言&#xff0c;中文编程工具构件简介软件下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;象如…

Redis集群(新)

1.什么是集群 Redis集群实现了对Redis的水平扩容&#xff0c;可实现并发写操作&#xff0c;启动n个redis节点&#xff0c;将数据分别存储在不同的节点中&#xff0c;每块节点负责不同区域的插槽&#xff0c;所以Redis集群通过分区来提供一定程度的可用性。 Redis集群现采用的是…

EFAK-v3.0.1版部署与使用

一、前言 EFAK&#xff08;(Eagle For Apache Kafka&#xff0c;以前称为Kafka Eagle&#xff09;用于在使用 Topic 的情况下监控 Kafka 集群。包含Offset 的产生、Lag的变化、Partition的分布、Owner、Topic的创建以及修改的时间等信息。 二、环境&安装包 官方下载连接E…

Spring Boot 整合MyBatis-Plus 详解

MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 全新的 MyBatis-Plus 3.0 版本基于 JDK8&#xff0c;提供了 lambda 形…

积分球吸收光谱测量的领域有哪些?

积分球吸收光谱测量是一种常用的吸收光谱测量方法&#xff0c;它通过将样品放置在积分球的入口处&#xff0c;球内的光线经过多次反射后形成均匀的照度分布&#xff0c;然后使用光度计或光谱仪对光线进行测量&#xff0c;可以获得样品的相关参数。 在积分球吸收光谱测量中&…

十大排序之选择排序(详解)

文章目录 &#x1f412;个人主页&#x1f3c5;算法思维框架&#x1f4d6;前言&#xff1a; &#x1f380;选择排序 时间复杂度O(n^2)&#x1f387;1. 算法步骤思想&#x1f387;2.动画实现&#x1f387; 3.代码实现 &#x1f412;个人主页 &#x1f3c5;算法思维框架 &#x1f…

Java数组的复制、截取(内含例题:力扣-189.轮转数组)

目录 数组的复制、截取&#xff1a; 1、使用Arrays中的copyOf方法完成数组的拷贝 2、使用Arrays中的copyofRange方法完成数组的拷贝 题目链接&#xff1a; 数组的复制、截取&#xff1a; 1、使用Arrays中的copyOf方法完成数组的拷贝 public class Csdn {public static vo…

Edit And Resend测试接口工具(浏览器上的Postman)

优点 可以不用设置Cookie或者Token&#xff0c;只设置参数进行重发接口测试API 使用Microsoft Rdge浏览器 F12——然后点击网络——在页面点击发起请求——然后选择要重发的请求右键选择Edit And Resend——在网络控制台设置自己要设置的参数去测试自己写的功能

GEE:通过将 Landsat 5、7、8、9 的 C02 数据集合并起来,构建 NDVI 长时间序列

作者:CSDN @ _养乐多_ 本文记录了在 Google Earth Engine(GEE)平台上,将 Landsat-5、Landsat-7、Landsat-8 和 Landsat-9 的数据合成为一个影像集合,并生成 NDVI(归一化植被指数)的时间序列的代码。 代码封装成了函数,方便调用,结果如下图所示, 在实际应用中,可能…

基于光纤环形激光器的optisystem仿真及其传感应用

近年来&#xff0c;光纤传感器在航空航天领域&#xff0c;工业制造&#xff0c;医疗等领域引起了越来越多的关注&#xff0c;因为他们体积小&#xff0c;结构简单&#xff0c;灵敏度高&#xff0c;抗电磁干扰强&#xff0c;防腐性能好的特点。各种各样的传感器结构被设计出来&a…

哨兵1号回波数据(L0级)包格式解析与成像参数提取

坑爹的格式,具体有多坑往下看就知道了。matlab代码在文末。 先上首字母缩写: 再来回波数据包的格式图 1. 数据包格式 众所周知,解包的第一步是找帧头和帧长,找到第4~5字节,帧长码为“0x3761”,转十进制为14777,然而实际第一帧整帧的长度是14184。。。你要是加6我还能…

如何打造垂直LLM的护城河

B2B人工智能初创企业的一个伟大策略是打造“垂直人工智能”产品&#xff1a;成为特定行业的人工智能助手&#xff0c;比如律师、金融服务、医生。 听起来很简单&#xff1a;你可以利用LLM的超能力&#xff0c;并将其应用于宠物行业的特定数据和用例。 这就是我们在Explain所做的…

Leetcode—94.二叉树的中序遍历【简单】

2023每日刷题&#xff08;四十&#xff09; Leetcode—94.二叉树的中序遍历 C语言实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ /*** Note: The returned array mus…