1.人形识别结果
2.代码
python+OpenCV+yolov3训练库,代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import os
imgFiles=["pic03.jpg", "pic04.jpg"]
net=None
classes=None
colors=None
def recog_person(imgFile, ratio):
print(imgFile)
global net, classes, colors
if(net==None):
# 加载模型配置和权重
net = cv2.dnn.readNet("../common/yolov3.weights", "../common/yolov3.cfg")
# 加载对象类别
classes = []
with open("coco.names", "r") as f:
classes = [line.strip() for line in f.readlines()]
# 随机颜色
colors = np.random.uniform(0, 255, size=(len(classes), 3))
# 加载图像
image = cv2.imread(imgFile)
# 获取图像尺寸
height, width, _ = image.shape
new_height = 416
new_width = int(width * (new_height / height))
resized_image = cv2.resize(image, (new_width, new_height))
# 构建输入blob
blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416), swapRB=True, crop=False)
# 设置输入blob作为网络的输入
net.setInput(blob)
# 前向传递,获取输出层
layer_names = net.getLayerNames()
print("layer names counts=%d" %(len(layer_names)))
print(net.getUnconnectedOutLayers())
#print(length(layer_names))
#output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
outs = net.forward(output_layers)
# 初始化边界框、置信度和类别列表
boxes = []
confidences = []
class_ids = []
# 对每个输出层进行处理
for out in outs:
for detection in out:
# 获取类别置信度
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
# 过滤掉低置信度的预测
if confidence > ratio:
# 获取边界框坐标
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# 边界框的左上角坐标
x = int(center_x - w / 2)
y = int(center_y - h / 2)
# 更新边界框、置信度和类别列表
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
# 非最大值抑制
indices = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
print("indices", len(indices), indices)
print("-------------------------------")
print("class_ids", len(class_ids), class_ids)
print("classes", len(classes));
print("colors", len(colors));
print("boxes counts=", len(boxes), len(indices));
# 绘制边界框和类别标签
font = cv2.FONT_HERSHEY_SIMPLEX
for i in range(len(boxes)):
if i in indices:
x, y, w, h = boxes[i]
#label = classes[class_ids[i]]
#color = colors[class_ids[i]]
color = (128,0,128)
cv2.rectangle(image, (x, y), (x+w, y+h), color, 2)
#cv2.putText(image, label, (x, y-10), font, 0.5, color, 2)
# 显示结果图像
name, extension = os.path.splitext(imgFile)
output_filename = name + ".ai.jpg";
cv2.imwrite(output_filename, image)
for file in imgFiles:
recog_person(file,0.5)
3.注意事项
3.1 yoloV3的训练库使用的分辨率是一个正方形的分辨率,416*416或者压缩,或者是扫描。
3.2上面筛选目标对象的代码没有代入,所以误识别到了一些其他物体。
3.3 yoloV3的训练库名称是:yolov3.weight yolov3.cfg
3.4 置信概率50%。
4.我所知晓的图像识别原理
4.1数学机制
图像识别中运算量最大的部分是矩阵运算。它的原理是这样的:你看,刚刚的yoloV3的训练库,针对的是固定分辨率416*416的图片。它的训练库最终输出的总规模是200M字节。假定我们有一个非常简单的训练库,能够识别三角形。那这个东西,在最终进行图像识别时,是怎么运作的呢?我们知道图像在被拍摄为图片后,会有平移,缩放,投影,这三种运算。这些运算对应的都是一些矩阵运算。假定最终,我们经过某些变换后,能够让我们的识别库中的这组三角形顶点集合,与最终识别到的点阵中的某组点阵之间能够形成(ArrayOfModel) = K*(ArrayOfPt),也就是说,这个时候,它们只是大小的差异,那么我们就认为捕获到了一组三角形。
捕获的原则,肯定是先捕获更大的点阵组,然后逐渐尝试捕获更小的点阵组,类似这样。这个点阵的匹配过程是可以并行执行的。所以,显卡那种结构会更适合进行点阵运算。支持多路同时计算的量子计算也肯定更适合这种模式。
4.2提高效率的可能途径
模式库的分离,可能是最有效的提高效率的途径。如果你已经确定了要进行模式匹配的对象的几乎,匹配算法就不会在尝试在一个明显更大的模式库里去进行复杂匹配计算。
4.3手工进行图像识别的途径
基本的步骤:
- 如果对颜色不敏感,或者特别敏感,可以尝试将图片转换为黑白,或者特定的颜色通道,这样能够大范围地消减无关特征。
- 锐化,把轮廓特征提取出来。
- 首先对明显的几何特征进行识别,比如线段,或者线段相邻的几何构造,明显的圆环标志点。
- 手工构造模型的特征点阵。
- 对新的图片进行矩阵运算,尝试找到那些与既有特征点阵相匹配的点,或者线的集合。
4.4 机器学习
机器学习很像在进行某些变量的函数关系的推导过程中,使用逐点样条差值。你不再尝试推导出明确的点阵特征值。而是一切交给机器,喂入大量的图片,由它自己建立关联关系。
5.工程实现时的注意事项
5.1 关键问题
通过检查附录A,附录B,你会发现,工程实现时的关键在于代码优化。算法基本是明的。但是,在工程应用时必须考虑成本。此时,必须进行计算优化。针对学习阶段可以用堆CPU,堆显卡的方式实现。但是一但开始部署,必须要在一个性价比较高的嵌入式平台,能在所需的有限时间内跑通算法。
5.2 优化的途径
建议搜索是否有针对特定的识别算法经过预先优化的arm平台。我觉得这比自己做始终要更快——当然,局限是,它可能已经限制死了训练集的图片幅面和具体的识别算法。但是即使这样,它仍然是更好的途径。
在优化瓶颈无法克服时,降低像素是可以尝试的途径。
5.3 训练集私有图片的标注
你可以使用一个预先训练好的训练集先对你自己拍摄的图片进行识别,然后删减识别到的物体,或者追加。这样更快,不必徒手标注每一张图片。
5.4 截止2024.1的推荐ARM平台和新的加速技术
观察附录B,你会发现ARM平台在不降低其他参数的情况下,几乎无法使用。但是事实上并非如此。推荐一篇帖子:
YOLOv8 与 RKNN 的碰撞:全新 SOTA 视觉模型如何在边端大放异彩 - 知乎 (zhihu.com)
RKNN是一种基于既有训练结果的一种识别优化:
利用这种计算技术,在 RK3399平台下的实际运算结果:
YOLOv5s部署在瑞芯微电子RK3399Pro中使用NPU进行加速推理 - 知乎
NPU 的算力相当于1~8TPOS,这个算力已经和附录A,未使用任何加速技术在I5-9400 2.9GHz下的运算结果相当。而事实上的识别能力,训练集的图片尺寸不变,实际的识别速度可以达到100ms以内。在工业场景,已经是一个可以接受的识别方案。此时看这个测试人员的截屏:
它跑的是80个物体的完整训练集,对于有针对性的特定物体的识别,速度还可以进一步加快。
这个平台的开发板淘宝价在800+Yuan 这个级别。
5.4.1 其他的加速方案
全志V853 在 NPU 转换 YOLO V3 模型_全志npu适配-CSDN博客
注意yolov3的部分啊。320,应该指320*320, 416是416*416,对应的是待识别物体的幅面,tiny,spp似乎是为了适应嵌入式环境的一些简化版本,不仅仅缩减了幅面,而且对运算过程本身也做了裁剪。
附录A Yolo3的资源消耗
- CPU Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz
- 上面第三组 takes 415 ms
- 复杂场景最高 takes 1945 ms
附录B Intel和ARM平台部署的矩阵运算相关的对比数据:
出处:深度学习模型Intel与ARM部署性能分析,Intel和ARM CPU上CNN计算速度差距分析。
CPU 型号 | 支持加速指令 | 1 core 测试时间 | 2 core测试时间 | 4核测试时间 | 8核心测试时间 |
---|---|---|---|---|---|
i5-10400 CPU @2.90GHz 12核 睿频4.3GHz Ubuntu 18.04, x86-64,Linux 5.4.0,本地 mkl-threads 6 | OpenMP+MKL-DNN | 27.63s | 17.63s | 9.64s | 8.0s |
与上同3080ti服务器 | OpenMP 4.5, 没有MKL-DNN | 36.44s | 24.10s | 16.00s | 13.25s |
i7-9700k CPU @3.60Hz 8核 睿频4.9GHz torch 1.5 linux 5.4 x86-64, | OpenMP+MKL-DNN | 28.46s | 15.40s | 11.1s, | 6.75s |
Intel Xeon CPU E5-2680 v4 @2.40GHz 2 CPU 56核 睿频3.3 GHz centos linux 7,linux 3.10.0 | OpenMP+MKL-DNN | 32.23s | 18.20s | 10.72s | 6.94s |
Intel Xeon CPU E5-2690 v4@2.6GHz,32核,centos linux 7,linux3.10.0 mkl-max-threads=16 | OpenMP+MKL-DNN | 36.72s | 20.44s | 12.31s | 7.34s |
飞腾FT-2000+/64 CPU,64核,2.3GHz, 架构ARM 64 操作系统kylin 4.0,内核 linux 4.4 | OpenMP 4.5,无MKL-DNN | 501.35s 100%CPU | 303.8s 170%cpu | 210.7s 250%CPU | 112.0s 510% |
MacBook ARM CPU m1 3.2GHz, aarch64架构,ARMv8-A指令集架构,8核,mkl-max-threads=1 | 没有OpenMP,有MKL-DNN | 57.10s | 52.94s | 49.6s | 48.62s |