笔记补充:yolo识别、框选图片物体的python代码实现

本文介绍如何使用Python实现YOLOv3进行图片目标检测,并展示如何利用OpenCV绘制检测结果边界框。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前记:

(不知道怎么第一篇发出去的博客似乎一直搜不到,在此补充一封)

作用说明:学习笔记,主要用于自我记录。

(PS:本人菜鸟,文章仅供参考;如有错误,欢迎各位大神批评指正!)

最近刚刚接触yolo,由于yolo官网和网上各种资料几乎都是基于C语言的,本人觉得python比较简洁,故用python实现了C可实现的部分功能,包括(1)图片检测及画框、(2)本地视频检测、(3)webcam检测、(4)yolo结合ROS检测摄像头(webcam)视频。

该文此下只介绍(1)yolo在python下图片检测及画框。其余部分后续介绍。

【本系列文章代码全基于原作者代码,文中代码由于TAB缩进量可能会出现缩进问题】


1、使用环境和平台:

ubuntu 14.04+ python2.7+opencv2.4+yolo

关于yolo/darknet的安装:

git clone https://github.com/pjreddie/darknet
cd darknet
make

有GPU的可自行安装CUDA(识别速度会快很多),修改相关参数。

yolo/darknet官网链接:

https://pjreddie.com/darknet/yolo/

2、检测图片的python代码

以下代码只是对源程序(darknet/python/darknet.py)的简单修改。

#!coding=utf-8
#modified by Leo at 2018.04.25
#function: 1,NOT overwrite the origin picture  
#          2,print info BEFORE showing the display_window

from ctypes import *
import math
#import module named cv2 to draw
import cv2

def sample(probs):
    s = sum(probs)
    probs = [a/s for a in probs]
    r = random.uniform(0, 1)
    for i in range(len(probs)):
        r = r - probs[i]
        if r <= 0:
            return i
    return len(probs)-1

def c_array(ctype, values):
    arr = (ctype*len(values))()
    arr[:] = values
    return arr

class BOX(Structure):
    _fields_ = [("x", c_float),
                ("y", c_float),
                ("w", c_float),
                ("h", c_float)]

class DETECTION(Structure):
    _fields_ = [("bbox", BOX),
                ("classes", c_int),
                ("prob", POINTER(c_float)),
                ("mask", POINTER(c_float)),
                ("objectness", c_float),
                ("sort_class", c_int)]


class IMAGE(Structure):
    _fields_ = [("w", c_int),
                ("h", c_int),
                ("c", c_int),
                ("data", POINTER(c_float))]

class METADATA(Structure):
    _fields_ = [("classes", c_int),
                ("names", POINTER(c_char_p))]


lib = CDLL("/home/username/darknet/libdarknet.so", RTLD_GLOBAL)
lib.network_width.argtypes = [c_void_p]
lib.network_width.restype = c_int
lib.network_height.argtypes = [c_void_p]
lib.network_height.restype = c_int

predict = lib.network_predict
predict.argtypes = [c_void_p, POINTER(c_float)]
predict.restype = POINTER(c_float)

set_gpu = lib.cuda_set_device
set_gpu.argtypes = [c_int]

make_image = lib.make_image
make_image.argtypes = [c_int, c_int, c_int]
make_image.restype = IMAGE

get_network_boxes = lib.get_network_boxes
get_network_boxes.argtypes = [c_void_p, c_int, c_int, c_float, c_float, POINTER(c_int), c_int, POINTER(c_int)]
get_network_boxes.restype = POINTER(DETECTION)

make_network_boxes = lib.make_network_boxes
make_network_boxes.argtypes = [c_void_p]
make_network_boxes.restype = POINTER(DETECTION)

free_detections = lib.free_detections
free_detections.argtypes = [POINTER(DETECTION), c_int]

free_ptrs = lib.free_ptrs
free_ptrs.argtypes = [POINTER(c_void_p), c_int]

network_predict = lib.network_predict
network_predict.argtypes = [c_void_p, POINTER(c_float)]

reset_rnn = lib.reset_rnn
reset_rnn.argtypes = [c_void_p]

load_net = lib.load_network
load_net.argtypes = [c_char_p, c_char_p, c_int]
load_net.restype = c_void_p

do_nms_obj = lib.do_nms_obj
do_nms_obj.argtypes = [POINTER(DETECTION), c_int, c_int, c_float]

do_nms_sort = lib.do_nms_sort
do_nms_sort.argtypes = [POINTER(DETECTION), c_int, c_int, c_float]

free_image = lib.free_image
free_image.argtypes = [IMAGE]

letterbox_image = lib.letterbox_image
letterbox_image.argtypes = [IMAGE, c_int, c_int]
letterbox_image.restype = IMAGE

load_meta = lib.get_metadata
lib.get_metadata.argtypes = [c_char_p]
lib.get_metadata.restype = METADATA

load_image = lib.load_image_color
load_image.argtypes = [c_char_p, c_int, c_int]
load_image.restype = IMAGE

rgbgr_image = lib.rgbgr_image
rgbgr_image.argtypes = [IMAGE]

predict_image = lib.network_predict_image
predict_image.argtypes = [c_void_p, IMAGE]
predict_image.restype = POINTER(c_float)

def classify(net, meta, im):
    out = predict_image(net, im)
    res = []
    for i in range(meta.classes):
        res.append((meta.names[i], out[i]))
    res = sorted(res, key=lambda x: -x[1])
    return res

def detect(net, meta, image, thresh=.5, hier_thresh=.5, nms=.45):
    im = load_image(image, 0, 0)
    num = c_int(0)
    pnum = pointer(num)
    predict_image(net, im)
    dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, None, 0, pnum)
    num = pnum[0]
    if (nms): do_nms_obj(dets, num, meta.classes, nms);

    res = []
    for j in range(num):
        for i in range(meta.classes):
            if dets[j].prob[i] > 0:
                b = dets[j].bbox
                res.append((meta.names[i], dets[j].prob[i], (b.x, b.y, b.w, b.h)))
    res = sorted(res, key=lambda x: -x[1])
    free_image(im)
    free_detections(dets, num)
    return res

# display the pic after detecting. 2018.04.25
def showPicResult(image):
    img = cv2.imread(image)
    cv2.imwrite(out_img, img)
    for i in range(len(r)):
        x1=r[i][2][0]-r[i][2][2]/2
        y1=r[i][2][1]-r[i][2][3]/2
        x2=r[i][2][0]+r[i][2][2]/2
        y2=r[i][2][1]+r[i][2][3]/2
        im = cv2.imread(out_img)
        cv2.rectangle(im,(int(x1),int(y1)),(int(x2),int(y2)),(0,255,0),3)
        #This is a method that works well. 
        cv2.imwrite(out_img, im)
    cv2.imshow('yolo_image_detector', cv2.imread(out_img))
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    
if __name__ == "__main__":
    #notice the path of every file
    net = load_net("/home/username/darknet/cfg/yolov3.cfg", "/home/username/darknet/weights/yolov3.weights", 0)
    meta = load_meta("/home/username/darknet/cfg/coco.data")
    origin_img = "/home/username/darknet/data/copy_dog.jpg"
    out_img = "/home/username/darknet/data/test_result.jpg"
    r = detect(net, meta, origin_img)
    print r
    #display the rectangle of the objects in window
    showPicResult(origin_img)


yolo.weights文件如果没有的话请自行去yolo官网或Github上下载。

Notice:

1、注意cfg、weights等各个文件的路径,将程序中的各种文件路径全改为自己的(另外可能需要修改coco.data的内容,因为文件中涉及到coco.names的路径);

2、此程序中对图片中识别到的物体画框的代码使用了opencv工具,没有安装的请自行安装(这里使用的是opencv2.4);

3、注意cfg和weights文件的对应,如不对应可能导致识别图片不准确或错误。

3、代码解释

本程序主要增加部分:

import cv2

# display the pic after detecting. 
def showPicResult(image):
    img = cv2.imread(image)
    cv2.imwrite(out_img, img)
    for i in range(len(r)):
        x1=r[i][2][0]-r[i][2][2]/2
        y1=r[i][2][1]-r[i][2][3]/2
        x2=r[i][2][0]+r[i][2][2]/2
        y2=r[i][2][1]+r[i][2][3]/2
        im = cv2.imread(out_img)
        cv2.rectangle(im,(int(x1),int(y1)),(int(x2),int(y2)),(0,255,0),3)
        #This is a method that works well. 
        cv2.imwrite(out_img, im)
    cv2.imshow('yolo_image_detector', cv2.imread(out_img))
    cv2.waitKey(0)
    cv2.destroyAllWindows()

  for i in range(len(r)):

r是一个list,其中存放了检测图片的信息,包括class(检测到的物体类别)、置信度、坐标,其中坐标包括x、y、w、h。

x、y:从左上角到物体中心点距离(float类型);w、h:目标区域的宽和高(float类型)。

cv2.rectangle(im,(int(x1),int(y1)),(int(x2),int(y2)),(0,255,0),3)

此函数实在目标区域绘制一个矩形,参数1:原图片,参数2:绘制矩形的左上角坐标,参数3: 右下角坐标,参数4: 矩形线条颜色,参数5: 线条粗细。(由于cv2中坐标为整数,所以程序中进行了类型转换float-->int)

对OpenCV不太了解的可以参考:

https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_tutorials.html


后记:

程序改动不大,理解起来很简单,在我电脑上是完全可以实现的,如有问题欢迎批评指正!

联系邮箱:2052383522@qq.com

(PS:后续部分,陆续奉上。)

<think>我们正在处理一个基于笔记本电脑摄像头的物体识别应用于垃圾分类的代码实现请求。根据引用[1]和[2],我们知道这是一个图像识别问题,涉及使用卷积神经网络(CNN)进行图像分类,并且需要定位目标(即目标识别)?但根据用户需求,他要求的是垃圾分类,而垃圾分类通常是一个图像分类问题(即给定一张图片,判断它属于哪种垃圾类别)。然而,用户提到了“物体识别”,这可能会涉及到目标检测(即识别图像中的物体并分类)。但根据引用[1]的描述,他们构建的系统是图像识别系统,包括收集图像、处理图像、搭建CNN、训练模型等步骤,最后用GUI封装,并可以调用摄像头识别垃圾物体。因此,我们这里可以理解为:通过摄像头捕获一帧图像,然后对这个图像进行分类(即整个图像中主要物体的分类,属于哪类垃圾)。所以,我们可以按照图像分类来处理。但是,引用[2]中提到了图像分类和目标识别的区别:图像分类是将整个图像分为不同类别,目标识别则要定位图像中的多个目标并分类。考虑到垃圾分类的实际情况,一张图片中可能包含多个垃圾,但通常我们可能假设每次只对一个垃圾进行分类(比如用户将垃圾放在摄像头前,背景干净)。如果用户需要识别多个垃圾,则需要目标检测。由于用户要求基于笔记本电脑摄像头,且引用[1]中描述的系统也是调用摄像头识别垃圾物体,我们这里可以按照图像分类来实现,即对每一帧图像,我们将其分类为某种垃圾类别。步骤:1.收集垃圾分类的图像数据集,并标注类别。2.使用TensorFlow搭建卷积神经网络(CNN)模型。3.训练模型。4.使用训练好的模型对摄像头捕获的图像帧进行分类。但是,用户要求的是代码实现,所以我们提供一个使用TensorFlow和OpenCV(用于摄像头捕获)的示例代码。注意:由于训练一个完整的模型需要大量的数据和计算资源,这里我们只提供代码框架,包括使用预训练模型进行迁移学习,以及使用摄像头捕获图像并进行实时分类的示例。我们将按照以下步骤编写代码:-使用TensorFlow的预训练模型(如MobileNetV2)进行迁移学习,用于垃圾分类。-使用OpenCV捕获摄像头视频流。-对每一帧进行预处理,然后输入模型得到预测结果。-在图像上显示预测结果。但是,由于垃圾分类是一个特定的任务,我们需要有自己的类别。假设我们有四个类别:可回收物、厨余垃圾、有害垃圾、其他垃圾(根据中国的垃圾分类标准)。由于没有现成的数据集,我们假设用户已经收集了数据集并训练了模型。这里我们提供一个训练模型的示例代码(简要)和摄像头实时识别代码。由于时间限制,我们只提供摄像头实时识别代码,并假设模型已经训练好并保存为.h5文件。步骤1:训练模型(简要示例,用户需要自己准备数据)步骤2:使用训练好的模型进行实时分类由于用户请求的是代码实现,我们将重点放在摄像头实时分类的代码上。代码结构:1.导入必要的库(tensorflow,opencv,numpy等)2.加载预训练的模型(这里我们假设模型已经训练好并保存为'model.h5')3.打开摄像头4.循环读取每一帧,预处理(调整大小,归一化等)5.预测并显示结果注意:由于我们使用预训练模型进行迁移学习,输入图像的尺寸需要符合模型的要求(如MobileNetV2要求224x224)。我们将编写一个简单的代码示例。</think>以下是基于笔记本电脑摄像头实现垃圾分类物体识别的完整代码解决方案,结合了深度学习模型和实时摄像头处理技术: ### 核心代码实现 ```python import cv2 import numpy as np from tensorflow.keras.models import load_model from tensorflow.keras.applications.mobilenet_v2 import preprocess_input # 加载预训练的垃圾分类模型 model = load_model('garbage_classification_model.h5') # 需提前训练好的模型 # 定义垃圾分类标签 CLASS_LABELS = { 0: "可回收物", 1: "厨余垃圾", 2: "有害垃圾", 3: "其他垃圾" } # 初始化摄像头 cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break # 预处理图像 resized = cv2.resize(frame, (224, 224)) x = np.expand_dims(resized, axis=0) x = preprocess_input(x) # 实时预测 preds = model.predict(x) label_id = np.argmax(preds[0]) label = CLASS_LABELS[label_id] confidence = preds[0][label_id] # 显示结果 cv2.putText(frame, f"{label}: {confidence:.2%}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow('Garbage Classification', frame) # 退出条件 if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() ``` ### 系统构成步骤 1. **图像采集** - 使用OpenCV调用笔记本电脑摄像头捕获实时视频流 - 推荐分辨率:640×480以上 2. **图像预处理** - 调整尺寸至$224×224$像素(MobileNetV2输入尺寸) - 应用归一化:$$x_{\text{norm}} = \frac{x - 127.5}{127.5}$$ - 使用MobilNetV2的预处理函数 3. **模型推理** - 使用预训练的卷积神经网络(CNN)进行特征提取 - 通过全连接层输出四类垃圾的概率分布:$$P(y=c|x) = \frac{e^{z_c}}{\sum_{k=1}^4 e^{z_k}}$$ - 取最大概率值作为分类结果 4. **结果可视化** - 在视频帧上叠加分类标签和置信度 - 实时刷新显示(30fps) ### 模型训练建议 ```python from tensorflow.keras.applications import MobileNetV2 from tensorflow.keras.layers import Dense, GlobalAveragePooling2D # 迁移学习框架 base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(224,224,3)) x = GlobalAveragePooling2D()(base_model.output) x = Dense(128, activation='relu')(x) predictions = Dense(4, activation='softmax')(x) # 四分类输出 model = Model(inputs=base_model.input, outputs=predictions) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) ``` ### 数据集准备建议 | 垃圾类别 | 建议样本数 | 示例物品 | |----------------|------------|-------------------| | 可回收物 | 2000+ | 塑料瓶、纸箱 | | 厨余垃圾 | 1500+ | 果皮、剩菜 | | 有害垃圾 | 1000+ | 电池、过期药品 | | 其他垃圾 | 1800+ | 卫生纸、陶瓷碎片 | ### 优化方向 1. **数据增强**:应用旋转($\pm 30^\circ$)、缩放($0.8-1.2\times$)、亮度调整($\pm 20\%$)增强鲁棒性 2. **模型量化**:使用TensorFlow Lite减小模型体积,提升推理速度 3. **目标检测**:集成YOLO模型实现物体同时识别[^2]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值