图像标注工具python+opencv

1 功能

  • 使用 opencv 对图像进行矩形框标注
  • 因为在使用 labelmg 的过程中感觉不太方便,主要是我所使用的图像长宽比差别大,所以在 labelImg 中标记起来很费劲,而 opencv 可以自由缩放图像,更加方便一些

2 使用方法

2.1 标记

  • 在命令行中运行label_main.py程序后,用选框拖动一个矩形框
    图像标注工具python+opencv_第1张图片
  • 会出现一个确认框,如果标注正确,点击正确,那么该标记框就会加入到列表中保存;如果点击错误,那么该标记框不会保存;如果该图片标记完成,点击结束,进行下一张图片的标记(请不要直接关闭图像,而是应该点击结束进行下一张图片的标记)
  • 点击正确后,之前的蓝色矩形框会变成红色
    图像标注工具python+opencv_第2张图片
  • 可以自由缩放图像比例进行标记
    图像标注工具python+opencv_第3张图片
  • 标记完毕后,每张图片的标记都会生成一个 csv 文件
  • 运行日志
C:\Users>python label_main.py
--当前标记的图片: 0
已经增加一处标记,请继续框选,标记框数量: 1
已经增加一处标记,请继续框选,标记框数量: 2
已经增加一处标记,请继续框选,标记框数量: 3
已经增加一处标记,请继续框选,标记框数量: 4
已经增加一处标记,请继续框选,标记框数量: 5
--结束当前图片标记--

--当前标记的图片: 1
已经增加一处标记,请继续框选,标记框数量: 1
--结束当前图片标记--

2.2 读取标记框并可视化

  • 运行read_label.py文件,可视化如图所示

2.3 注意

  • 该程序需最好在命令行运行,在 spyder 和 ipython 中可能会出错
  • 注意结束当前标记图片在弹出的确认框中点击结束,而不是直接关掉图片

3 程序

  • github 链接:链接
  • label_main.py
"""
Discription: python + opencv 对图片进行标记
Notes:
    该程序需最好在命令行运行,在 spyder 和 ipython 中可能会出错
    注意结束当前标记图片在弹出的确认框中点击结束,而不是直接关掉图片
"""
import os
import cv2
import tkinter as tk
import numpy as np

global point1, point2
global ensure
global point_list

point_list = []

def createWinSure():
    """ 创建一个确认框
    """
    global ensure
    win=tk.Tk()
    label=tk.Label(win,text="确认图像标注正确",bg="white",fg="black")
    label.pack()
    buttony=tk.Button(win,text="正确",command=lambda:confirm(1,win)) #收到消息执行这个函数
    buttony.pack() # 加载到窗体
    buttonn=tk.Button(win,text="错误",command=lambda:confirm(0,win)) #收到消息执行这个函数
    buttonn.pack() # 加载到窗体
    buttonn=tk.Button(win,text="结束",command=lambda:confirm(2,win)) #收到消息执行这个函数
    buttonn.pack() # 加载到窗体
    win.mainloop()

def confirm(flag,win):
    """ 点击确认框后,将结果保存到全局变量 ensure 中
    """
    global ensure
    ensure = flag
    win.destroy()

def on_mouse(event, x, y, flags, param):
    """ 鼠标响应,每次确认完一次都会重新绘制图像
    Notes:
        矩形框颜色(B, G, R)
    """
    global point1,point2
    global point_list
    global ensure
    global pressure
    img = param[0]
    index = param[1]
    box_length = 2 # 矩形框宽度
    img2 = img.copy() # 每次鼠标响应都会重新绘制
    if event == cv2.EVENT_LBUTTONDOWN: #左键点击
        point1 = (x,y)
        cv2.circle(img2, point1, 10, (0,255,0), box_length) # 单击时绘制 绿色圆形框 示意
        cv2.imshow('image', img2)
    elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON): #按住左键拖曳
        cv2.rectangle(img2, point1, (x,y), (255,0,0), box_length) # 绘制 蓝色矩形框
        cv2.imshow('image', img2)
    elif event == cv2.EVENT_LBUTTONUP: #左键释放
        point2 = (x,y)
        cv2.rectangle(img2, point1, point2, (0,0,255), box_length) # 绘制 红色矩形框
        createWinSure() # 创建一个确认框
        
        if ensure == 0: # 框选错误,重新框选
            print('未标记,请在图片上重新框选!')
            
        elif ensure == 1: # 框选正确,继续
            point_list.append([point1[0], point1[1], point2[0], point2[1]])
            print('已经增加一处标记,请继续框选,标记框数量:', len(point_list))
            img2 = cv2.rectangle(img2, point1, point2, (0,0,255), box_length) # 绘制 蓝色矩形框
            cv2.imshow('image', img2)
            
        else: # 结束
            print("--结束当前图片标记--\n")
            np.savetxt(str(index) + ".csv", point_list, delimiter=",", fmt='%d')
            point_list = [] # 将列表清零
            cv2.imshow('image', img2)
            cv2.destroyAllWindows()

def main():
    for root, dirs, files in os.walk('./data/'): 
        for i in range(0,len(files)):
            print("--当前标记的图片:", i)
            img = cv2.imread('./data/'+files[i])
            cv2.namedWindow('image', 0)
            cv2.setMouseCallback('image', on_mouse, [img,i])
            cv2.imshow('image', img)
            cv2.waitKey(0)

if __name__ == '__main__':
    main()
  • read_label.py
# -*- coding: utf-8 -*-
"""
Discription: 读取 csv 格式的标签信息,并绘制矩形框显示
"""
import cv2
import numpy as np

def cv_rect(data_r, i_xmin, i_xmax, i_ymin, i_ymax):
    """ 根据标签绘制矩形框
    Args:
        data_r: 
        others: 起点终点坐标,必须为整型
    Returns:
        data_rect:绘制矩形框后数据,矩形框位置的数据值为 0
    """
    gx_start, gx_end = i_xmin, i_xmax
    gy_start, gy_end = i_ymin, i_ymax
    data_rect = data_r.copy()
    cv2.rectangle(data_rect, (gx_start, gy_start), (gx_end, gy_end), (0,0,255), 2)
    return data_rect

def main():
    index = 0
    src = cv2.imread("./" + str(index) + ".jpeg")
    src_rect = src.copy()
    label_list = np.loadtxt("./" + str(index) + ".csv", delimiter=",", dtype='int')
    for label in label_list:
        i_xmin, i_ymin, i_xmax, i_ymax = label[0], label[1], label[2], label[3]
        src_rect = cv_rect(src_rect, i_xmin, i_xmax, i_ymin, i_ymax)
    cv2.namedWindow('img', 0)
    cv2.imshow('img', src_rect)

if __name__ == '__main__':
    main()

参考链接

  • 参考:机器学习 人工标注样本工具Python+OpenCV

你可能感兴趣的:(python,opencv)