python在图片上绘制标注框

本文介绍了一种方法,通过在图片上绘制标注框来检查数据集的准确性,帮助识别标注文件中可能存在的问题。代码读取数据集的txt文件,获取类别名,然后使用hsv转rgb生成颜色,为每个类别分配不同颜色的边框。此外,还展示了如何在图片上绘制目标框和类别标签,以便于观察和验证。该方法适用于检测网络预测的box框与实际标注的匹配情况。

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

前言

最近帮人跑代码的时候遇到了不少问题,后来发现他提供给我的数据集中标注文件不太准确,部分box框没有很好地框到物体。所以写了一个代码,通过在图片上绘制标注框来直观地判断标注文件是否存在问题,也可以绘制经过网络预测之后的box框。
参考文档:python读取数据集并生成txt文件

一、文件路径

# -*- coding:utf-8 -*-
import os
import numpy as np
import colorsys
import random
from PIL import Image,ImageFont, ImageDraw

annotation_path = '../model_data/dataset/boats/boats.txt'
classes_name = '../model_data/dataset/boats/boat.txt'
font_path = '../model_data/simhei.ttf'

annotation_path 是数据集的txt文件索引,classes_name 存放了所有类别名称,font_path存放的是字体文件(也可以不设置)

二、在图片上绘制标注框

#获取所有类别
def get_classes(classes_path):
    classes = os.path.expanduser(classes_path)
    with open(classes) as f:
        class_names = f.readlines()
    class_names = [c.strip() for c in class_names]
    return class_names

def show_ground_truth(annotation_line):
    print(annotation_line)
    line = annotation_line.split()
    #获取图片
    image = Image.open(line[0])
    #获取GT_box框
    boxes = np.array([np.array(list(map(int, box.split(',')))) for box in line[1:]])
    #获取类别数
    class_names = get_classes(classes_name)

    # 生成绘制边框的颜色。
    # h(色调):x/len(self.class_names)  s(饱和度):1.0  v(明亮):1.0
    # 对于所有种类的目标,确定每一种目标框的绘制颜色,即:将(x/80, 1.0, 1.0)的颜色转换为RGB格式,并随机调整颜色以便于肉眼识别,
    hsv_tuples = [(x / len(class_names), 1., 1.) for x in range(len(class_names))]
    colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))  # hsv转换为rgb
    # hsv取值范围在[0,1],而RBG取值范围在[0,255],所以乘上255
    colors = list(map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)),colors))
    # 定义字体
    font = ImageFont.truetype(font=font_path,size=np.floor(3e-2 * np.shape(image)[1] + 0.5).astype('int32'))
    # 设置目标框线条的宽度
    model_image_size=[416,416,3]
    thickness = (np.shape(image)[0] + np.shape(image)[1]) // model_image_size[0]

    for i in range(len(boxes)):
        # 创建一个可以在给定图像上绘图的对象
        draw = ImageDraw.Draw(image)

        #获取目标框
        left, top, right, bottom, predicted_class = boxes[i]
        predicted_class = class_names[predicted_class]
        label = '{}'.format(predicted_class)
        top = top - 5
        left = left - 5
        bottom = bottom + 5
        right = right + 5

        # 防止目标框溢出
        top = max(0, np.floor(top + 0.5).astype('int32'))
        left = max(0, np.floor(left + 0.5).astype('int32'))
        bottom = min(np.shape(image)[0], np.floor(bottom + 0.5).astype('int32'))
        right = min(np.shape(image)[1], np.floor(right + 0.5).astype('int32'))

        #定义标签文字
        label_size = draw.textsize(label, font)
        label = label.encode('utf-8')
        # 确定标签(label)起始点位置:标签的左、下
        if top - label_size[1] >= 0:
            text_origin = np.array([left, top - label_size[1]])
        else:
            text_origin = np.array([left, top + 1])

        #画目标框,线条宽度为thickness(这里画了很多个框重叠起来)
        for i in range(thickness):
            draw.rectangle(
                [left + i, top + i, right - i, bottom - i],
                outline=colors[class_names.index(predicted_class)])
        #画标签框
        # draw.rectangle(
        #     [tuple(text_origin), tuple(text_origin + label_size)],
        #     fill=colors[class_names.index(predicted_class)])
        # 填写标签内容
        # draw.text(text_origin, str(label, 'UTF-8'), fill=(0, 0, 0), font=font)
        del draw
    #展示图片
    image.show()

1、按空格将annotation_line分隔开,获取图片的路径和所有标注框的坐标和类别信息。
2、定义绘制边框的颜色,将hsv格式转换成RGB格式。定义字体样式。设置目标框线条的宽度(为了保证线条的宽度在不同的图片上看起来都比较合适,这里将宽度设置为图片的长宽加起来除以416)。
3、利用for循环在图片上依次画框。为防止目标框溢出,目标框的上、左两个坐标小数点后一位四舍五入;目标框的下、右两个坐标小数点后一位四舍五入,与图片的尺寸相比,取最小值。
4、最后画目标框(这里实际上画了很多框聚在一起,所以看起来才有宽度)和标签框(如果目标太多显得拥挤可以将代码注释掉),显示图片。

三、主函数

if __name__ == '__main__':
    file = open(annotation_path)
    lines = file.read().splitlines()
    #随机读取一张图片
    #show_ground_truth(random.choice(lines))

    #读取所有图片
    for line in lines:
        show_ground_truth(random.choice(lines))
        os.system("pause");

既可以随机读取一张图片,也可以遍历所有图片。

四、总结

如果你在处理过程中遇到了任何问题,都可以在下方进行留言和评论。

<think>好的,用户想用Python和OpenCV在图像上画矩形。我之前看到过相关的博客和文档,需要先回忆一下具体的函数和步骤。 首先,我记得OpenCV有一个cv2.rectangle函数,用来绘制矩形。参数应该包括图像、左上角和右下角坐标、颜色、线宽等。需要确认参数顺序是否正确,比如pt1和pt2是矩形的两个对角点,通常是左上和右下。颜色可能需要用BGR格式,比如(0, 255, 0)代表绿色。 接下来,用户可能需要载图像,这可以通过cv2.imread函数实现。要注意路径是否正确,以及读取后的图像格式是否是numpy数组。然后,绘制矩形后需要用cv2.imshow显示图像,或者保存为文件。 可能还需要考虑线宽的类型,比如如果thickness为负数的话是否填充矩形。另外,线型lineType的默认值是什么,用户是否需要调整。例如,cv2.LINE_AA可以用于抗锯齿,使线条更平滑。 用户可能遇到的问题包括坐标是否正确,颜色是否正确应用,以及如何保存处理后的图像。示例代码需要包括完整的步骤,从读取图像到显示或保存结果。此外,引用相关的资料来源,比如CSDN博客和官方文档,可以增回答的可信度。 另外,生成的相关问题应该覆盖常见的使用场景,比如如何画多个矩形、如何动态交互绘制、调整样式的方法等。这些问题可以帮助用户进一步探索OpenCV的功能。 需要检查代码是否正确,比如函数名是否正确,变量命名是否合理,是否添了必要的等待按键和窗口销毁步骤。例如,cv2.waitKey(0)和cv2.destroyAllWindows()在显示图像时是必需的,否则窗口可能无法正常显示或关闭。 最后,确保回答结构清晰,分步骤说明,并标注引用来源,符合用户的要求。</think>以下是使用Python OpenCV在图像上绘制矩形的详细教程: ### 步骤说明 1. **导入库** ```python import cv2 ``` 2. **读取图像** ```python image = cv2.imread('image.jpg') # 替换为你的图片路径 ``` 3. **绘制矩形** ```python # 参数说明:图像对象、左上角坐标(x1,y1)、右下角坐标(x2,y2)、颜色(BGR)、线宽 cv2.rectangle(image, (100, 50), (300, 200), (0, 255, 0), 2) ``` 4. **显示/保存结果** ```python cv2.imshow('Result', image) cv2.waitKey(0) # 按任意键关闭窗口 cv2.destroyAllWindows() # 保存结果 cv2.imwrite('output.jpg', image) ``` ### 完整示例代码 ```python import cv2 # 读取图像 img = cv2.imread('input.jpg') # 绘制绿色矩形(线宽为2) cv2.rectangle(img, (50, 30), (200, 150), (0, 255, 0), 2) # 显示结果 cv2.imshow('Rectangle Demo', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` ### 参数详解 - `thickness`参数: - 正整数:边线宽 - `-1`:填充整个矩形区域[^2] - `lineType`参数(可选): - `cv2.LINE_AA`:抗锯齿线型 - `cv2.LINE_8`:默认8连通线型 ### 注意事项 1. 坐标原点在图像左上角,x轴向右,y轴向下 2. 颜色使用BGR格式,例如红色为`(0, 0, 255)` 3. 图像路径建议使用绝对路径,避免相对路径错误 ### 扩展应用 ```python # 绘制半透明矩形(通过叠图层实现) overlay = img.copy() cv2.rectangle(overlay, (100, 80), (250, 180), (255, 0, 0), -1) cv2.addWeighted(overlay, 0.5, img, 0.5, 0, img) ``` [^1]: [Python OpenCV在图像上画矩形(CSDN博客)](https://blog.csdn.net/Vertira/article/details/...) [^2]: [OpenCV官方文档-绘制函数](https://docs.opencv.org/...)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值