对象检测是指检测出图像中的所有对象,并识别对象的类型。使用OpenCV中的深度学习预训练模型进行对象检测的基本步骤如下。
(1 )从配置文件和预训练模型文件中加载模型。
(2 )创建图像文件的块数据。
(3 )将图像文件的块数据设置为模型的输入。
(4)执行预测。
( 5)处理预测结果。
环境:群辉docker内安装好Anaconda和opencv4.5。运行容器,打开ip:8888,jupyter notebook运行程序。
其实只要正常的Python环境即可。
import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib
%matplotlib notebook
from PIL import ImageFont, ImageDraw, Image
#加载字体,以便显示汉字
fontpath = "STSONG.TTF"
font = ImageFont.truetype(fontpath,20) #载入字体,设置字号
font2 = {'family': 'STSONG', "size": 22}
matplotlib.rc('font', **font2) #设置plt字体
#准备对象名称类别,设置为中文
object_names = ('背景', '飞机', '自行车', '鸟', '船', '瓶子', '公共汽车', '小汽车','猫', '椅子', '牛', '餐桌', '狗', '马','摩托车','人','盆栽', '羊', '沙发', '火车', '监视器')
mode = cv2.dnn.readNetFromCaffe("MobileNetSSD_deploy.txt", "MobileNetSSD_Caffemodel.dat")
image = cv2.imread("obj.jpg") #打开用于对象检测的图像
#创建图像的块数据
blob = cv2.dnn.blobFromImage(image, 0.007843, (224,224),(120, 120, 127))
mode.setInput(blob) #将块数据设置为模型输入
result = mode.forward() #执行预测
ptime, x = mode.getPerfProfile() #获得完成预测时间
title='Prediction Time: %.2f ms' % (ptime * 1000.0 / cv2.getTickFrequency())
for i in range(result.shape[2]): #处理检测结果
confidence = result[0, 0, i, 2] #获得可信度
if confidence > 0.3: #输出可信度大于30%的检测结果
a,id,a,x1,y1,x2,y2=result[0, 0, i]
name_id = int(id) #获得类别名称id
blob_size=280
heightScale = image.shape[0] / blob_size#计算原图像和图像块的高度比例
widthScale = image.shape[1] / blob_size#计算原图像和图像块的宽度比例
#计算检测出的对象的左下角和右上角坐标
x1 = int(x1 * blob_size * widthScale)
y1 = int(y1 * blob_size * heightScale)
x2 = int(x2 * blob_size * widthScale)
y2 = int(y2 * blob_size * heightScale)
cv2.rectangle(image,(x1,y1),(x2,y2),(0,255,0),2)#绘制标识对象的绿色矩形
#在图像中输出对象名称和可信度
if name_id in range(len(object_names)):
text = object_names[name_id] + "\n{:.1%}".format(confidence)
img_pil = Image.fromarray(image)
draw = ImageDraw.Draw(img_pil)
draw.text((x1+5,y1), text, font = font,fill=(255,0,0)) #绘制文字
image = np.array(img_pil)
img = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
plt.title(title)
plt.imshow(img)
plt.axis('off')
plt.show()
import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib
%matplotlib notebook
from PIL import ImageFont, ImageDraw, Image
#加载字体,以便显示汉字
fontpath = "STSONG.TTF"
font = ImageFont.truetype(fontpath,20) #载入字体,设置字号
font2 = {'family': 'STSONG', "size": 22}
matplotlib.rc('font', **font2) #设置plt字体
#从文件中加载已知的对象名称
f=open("object_names.txt",encoding='utf-8')#文件保存了80个类别的对象名称,每行一个
object_names = [r.strip() for r in f.readlines()]
f.close()
#从文件中加载预训练的Darknet模型
mode = cv2.dnn.readNetFromDarknet("yolov3.cfg", "yolov3.weights")
image = cv2.imread("obj.jpg") #打开图像文件
imgH,imgW = image.shape[:2]
out_layers = mode.getLayerNames() #获得输出层
out_layers = [out_layers[i[0] - 1] for i in mode.getUnconnectedOutLayers()]
#创建图像blob数据
blob = cv2.dnn.blobFromImage(image,1/255.0,(416,416),swapRB=True,crop=False)
mode.setInput(blob) #将图像blob数据设置为模型输入
layer_results = mode.forward(out_layers)#执行预测,返回每层的预测结果
ptime, _ = mode.getPerfProfile()
tilte_text='Prediction Time:%.2f ms' % (ptime*1000/cv2.getTickFrequency())
result_boxes = []
result_scores = []
result_name_id = []
for layer in layer_results: #遍历所有输出层
for box in layer:#遍历层的所有输出预测结果,每个结果为一个边框
#预测结果结构:x, y, w, h, confidence,80个类别的概率
probs = box[5:]
class_id = np.argmax(probs) #找到概率最大的类别id
prob = probs[class_id] #找到最大的概率
if prob > 0.5: #筛选出概率大于50%的
#计算每个box在原图像中的的绝对坐标
box = box[0:4] * np.array([imgW, imgH, imgW, imgH])
(centerX, centerY, width, height) = box.astype("int")
x = int(centerX - (width / 2))
y = int(centerY - (height / 2))
result_boxes.append([x, y, int(width), int(height)])
result_scores.append(float(prob))
result_name_id.append(class_id)
#应用非最大值抑制消除重复边界框,获得要绘制的box
draw_boxes = cv2.dnn.NMSBoxes(result_boxes, result_scores, 0.6, 0.3)
if len(draw_boxes) > 0:
for i in draw_boxes.ravel():
#获得边框坐标
(x, y) = (result_boxes[i][0], result_boxes[i][1])
(w, h) = (result_boxes[i][2], result_boxes[i][3])
#绘制边框
cv2.rectangle(image,(x,y), (x+w,y+h),(0,255,0),1)
#输出类别名称和可信度
text=object_names[result_name_id[i]] +"\n{:.1%}".format(result_scores[i])
img_pil = Image.fromarray(image)
draw = ImageDraw.Draw(img_pil)
draw.text((x+5,y), text, font = font,fill=(0,0,255)) #绘制文字
image = np.array(img_pil)
img = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
plt.title(tilte_text)
plt.imshow(img)
plt.axis('off')
plt.show()
效果比第一个好一些。
相关文件在这里相关文件。