1 功能
- 使用 opencv 对图像进行矩形框标注
- 因为在使用 labelmg 的过程中感觉不太方便,主要是我所使用的图像长宽比差别大,所以在 labelImg 中标记起来很费劲,而 opencv 可以自由缩放图像,更加方便一些
2 使用方法
2.1 标记
- 在命令行中运行
label_main.py
程序后,用选框拖动一个矩形框
- 会出现一个确认框,如果标注正确,点击
正确
,那么该标记框就会加入到列表中保存;如果点击错误
,那么该标记框不会保存;如果该图片标记完成,点击结束
,进行下一张图片的标记(请不要直接关闭图像,而是应该点击结束进行下一张图片的标记)
- 点击
正确
后,之前的蓝色矩形框会变成红色
- 可以自由缩放图像比例进行标记
- 标记完毕后,每张图片的标记都会生成一个 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()
"""
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