目标检测(十)——利用网上训练好的R-CNN模型快速构建一个项目用于检测

以下内容不包含模型的构建与训练,只包含用模型进行相关图片(狗子)的检测。

利用网上训练好的R-CNN模型检测相关的图片

一、准备工作

新建项目文件夹DETECT(存放项目)下:

  1. 新建子文件夹dataset(存放下载的数据集)
  2. 新建子文件夹output(存放生成的输出文件)
  3. 待检测的图片

dataset下:

  1. 新建子文件夹images(存放下载的源图片)
  2. annotations(存放下载的标注文档)
  3. dog(存放下载的正样本)
  4. background(存放下载的负样本)

output下:

  1. model.h5(下载的训练好的模型)
  2. lb.pickle(生成的标签文件)

二、代码实现

##############################导入包#############################################
import os 
import cv2
from tensorflow.keras.models import Model, model_from_json, load_model
from tensorflow.keras.preprocessing.image import img_to_array, load_img, array_to_img
from tensorflow.keras.utils import to_categorical
import pickle
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelBinarizer
from sklearn.utils import shuffle

##########################设置文件存放路径############################################
BASE_PATH = "dataset" #设置数据集的路径
ORIG_IMAGES = os.path.sep.join([BASE_PATH, "images"]) #设置源图片的路径
ORIG_ANNOTS = os.path.sep.join([BASE_PATH, "annotations"]) #设置标注文档的路径
DOG_PATHS = os.path.sep.join([BASE_PATH, "dog"])#设置正样本路径
BACKGROUND_PATHS = os.path.sep.join([BASE_PATH, "background"])#设置负样本路径

BASE_OUTPUT = "output" #设置输出文件的路径,如果没有则创建
if not os.path.exists(BASE_OUTPUT):
    os.mkdir(BASE_OUTPUT)
    
LB_PATH = os.path.sep.join([BASE_OUTPUT, "lb.pickle"]) #LB_PATH 是保存标签文件的路径

############################定义检测时需要用到的函数###################################
def ssearch(image, mode="fast"):
    ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
    ss.setBaseImage(image)
    if mode == "fast":
        ss.switchToSelectiveSearchFast()
    else:
        ss.switchToSelectiveSearchQuality()
    rects = ss.process()
    return rects

def NMS(boxes, threshold):
    if len(boxes) == 0:
        return []
    boxes = np.array(boxes).astype("float")
    x1 = boxes[:, 0]
    y1 = boxes[:, 1]
    x2 = boxes[:, 2]
    y2 = boxes[:, 3]
    w1 = x2 - x1
    h1 = y2 - y1
    area = (w1 + 1) * (h1 + 1)
    temp = []
    idxs = np.argsort(y2)
    while len(idxs) > 0:
        last = len(idxs) - 1
        i = idxs[last]
        temp.append(i)
        x1_m = np.maximum(x1[i], x1[idxs[:last]])
        y1_m = np.maximum(y1[i], y1[idxs[:last]])
        x2_m = np.minimum(x2[i], x2[idxs[:last]])
        y2_m = np.minimum(y2[i], y2[idxs[:last]])
        w = np.maximum(0, x2_m - x1_m + 1)
        h = np.maximum(0, y2_m - y1_m + 1)
        over = (w * h) / area[idxs[:last]]
        idxs = np.delete(idxs, np.concatenate(([last],np.where(over > threshold)[0])))
    return boxes[temp].astype("int")
    
#############################进行分类训练################################################
#获取每张正样本图片路径
dogs = os.listdir(DOG_PATHS)
dogs = [os.path.sep.join([DOG_PATHS, path]) for path in dogs]

#获取每张负样本路径
backgrounds = os.listdir(BACKGROUND_PATHS)
backgrounds = [os.path.sep.join([BACKGROUND_PATHS, path]) for path in backgrounds]

imagepaths = [] # 创建列表用于存放所有正负样本的路径
bboxes = [] # 存放矩形坐标框
labels = [] # 存放所有图片对应的标签

for dog in dogs:
    imagepaths.append(dog) #将正样本中的每张图片添加到 imagepaths
    labels.append("dog") #将每张图片对应的标签 "dog" 添加到 labels
    bboxes.append((0.0, 0.0, 0.0, 0.0)) #添加对应的矩形框坐标 bboxes

for background in backgrounds:
    imagepaths.append(background) #将每张负样本的路径添加到 imagepaths
    labels.append("background") #添加对应的标签 "background" 到 labels
    bboxes.append((0.0, 0.0, 0.0, 0.0))#添加对应的矩形框坐标

labels, imagepaths, bboxes = shuffle(labels, imagepaths, bboxes, random_state=42)#打乱labels、imagepaths、bboxes

lb = LabelBinarizer() #对数据集的标签进行编码
labels = lb.fit_transform(labels) #将训练集和测试集的标签二值化
if len(lb.classes_) == 2:
    labels = to_categorical(labels)

#使用导入的 pickle 模块将标签对象 lb 转换为二进制对象并保存成lb.pickle文件
with open(LB_PATH, "wb") as f:
    f.write(pickle.dumps(lb))

#############################载入模型################################################
model = load_model(os.path.sep.join([BASE_OUTPUT, "dog_model.h5"])) #载入模型
lb = pickle.loads(open(LB_PATH, "rb").read()) #读取标签对象lb.pickle
image = load_img("dogs6.jpeg") #导入待检测图片
image = img_to_array(image) #将图片转换为数组
height, width = image.shape[:2] #获取图片的宽 width 和高 height
rects = ssearch(image) #使用选择性搜索获取候选区域
pboxes = [] #列表 pboxes 将会存储模型输出的检测框


for (x, y, w, h) in rects[:500]: #遍历 rects 中的前 500 个候选区域
    
    if w < 50 or h < 50 or w == 0 or h == 0 or 2 * w < h or w > 0.7 * width or h > 0.7 * height:
        continue #剔除宽和高不满足设定条件的候选区域

    roi = image[y:y + h, x:x + w]#从原候选区域中裁剪出roi区域
    roi = cv2.resize(roi, (224, 224), interpolation=cv2.INTER_LINEAR)#对roi区域进行尺寸缩放
    roi = roi / 255.0#对roi区域进行归一化处理
    roi = np.expand_dims(roi, axis=0)#扩展roi区域维度
   
    (boxPreds, labelPreds) = model.predict(roi) #用模型对roi区域进行检测, 输出检测框的坐标 boxPreds 和目标的类别 labelPreds。
    
    i = np.argmax(labelPreds, axis=1)
    label = lb.classes_[i][0]
    if label == "background":  #如果标签的预测结果是backgournd则跳出当前循环
        continue
    if labelPreds[0][i] < 0.6:  #如果标签的预测值小于 0.6 则跳出当前循环
        continue
        
	(startX, startY, endX, endY) = boxPreds[0] #获取检测框的左上角和右下角顶点坐标
    #计算检测框在候选区域中的绝对坐标
    startX = int(startX * w)
    startY = int(startY * h)
    endX = int(endX * w)
    endY = int(endY * h)
    #计算检测框的宽 r_w 和高 r_h
    r_w = endX - startX
    r_h = endY - startY
    #计算检测框在原图中的坐标
    s_x = x + startX
    s_y = y + startY
    e_x = s_x + r_w
    e_y = s_y + r_h
    #将转换后的坐标添加到 pboxes 中
    pboxes.append((s_x, s_y, e_x, e_y))

picks = NMS(pboxes, threshold=0.3) #使用非极大值抑制抑制剔除 pboxes 中的冗余检测框

image = np.array(array_to_img(image)) #将数组转换为图像
for (nms_x, nms_y, end_x, end_y) in picks: #在原图中画出检测框
    cv2.rectangle(image, (nms_x, nms_y), (end_x, end_y), (0, 255, 0), 2)

#显示检测结果
plt.figure(figsize=(10, 10))
plt.imshow(image)

#保存图片至项目文件夹下
image = image[:, :, ::-1]
results = imagepath.split(".")[0] + "_predict" + ".jpg"
cv2.imwrite(results, image)

三、检测结果

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值