一.背景
还是之前的主题,使用开源软件为公司搭建安全管理平台,从视觉模型识别安全帽开始。我是从运行、训练、标注倒过来学习的。本次主要是学习标注工具labelimg的安装及简单使用。
二.下载
LabelImg是一款广受欢迎的开源图像标注工具,为计算机视觉和机器学习项目提供了便捷的图像标注功能。它的项目地址在这里https://github.com/HumanSignal/labelImg。把这个项目下载下来就行了。如过你打不开,就下载我这里的吧https://download.csdn.net/download/qq_37372909/90151034
三.安装
安装主要是看的官方文档,我选择的anaconda在windows的安装方法。在刚刚github项目的主页下面有说明怎么安装。
我英语也勉强,但我大概看得懂。我理解是先Anaconda,这个就参考我之前的文章在windows系统用Anaconda搭建运行PyTorch识别安全帽项目的环境-CSDN博客就可以了。然后是进入到Anaconda模式中和labelimg目录。怎么进入到Anaconda模式呢?在cmd打开后,用这个命令啊,之前文章也写了的。这里的myenv 是我的anaconda的环境名称哦,你如果也是这个就没有问题。
bash
conda activate myenv
进入到labelimg目录,当然就是把之前github下载的压缩包解压咯。注意不要放到包含中文目录或者特殊符合的路径下面。在刚刚conda环境激活后,cd到我们解压的项目目录。
然后就是项目主页上说的这几个命令了。
bash
conda install pyqt=5
conda install -c anaconda lxml
pyrcc5 -o libs/resources.py resources.qrc
#这里就是运行了哦
python labelImg.py
过程中,可能要让你输入几次 y ,同意安装关联的组件吧
四.怎么标注图片
1.工具长什么样?
2.怎么标注图片中的安全帽?
打开图片后, 点击左边的"创建区块",在图片上按住鼠标左键拖动就可以画一个矩形框,松开鼠标后,弹出标注名称的输入,我输入的是安全帽的单词helmet,点击OK后,右中部就出现了一个标注信息。
3.标注信息存储的格式与内容
另存后,是一个xml文件,里面有图片的存放路径和标注的信息。
xml文件内容如下:
XML
<annotation>
<folder>images</folder>
<filename>hard_hat_workers2.png</filename>
<path>D:\zsp\works\temp\20241119-zsp-helmet\Safety-Helmet-Detection-main\data\images\hard_hat_workers2.png</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>416</width>
<height>415</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>helmet</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>295</xmin>
<ymin>219</ymin>
<xmax>326</xmax>
<ymax>249</ymax>
</bndbox>
</object>
<object>
<name>helmet</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>321</xmin>
<ymin>212</ymin>
<xmax>365</xmax>
<ymax>244</ymax>
</bndbox>
</object>
</annotation>
五.对Safety-Helmet-Detection项目中标注数据的理解
1.Safety-Helmet-Detection项目中标注数据的格式
bash
0 0.914663 0.349760 0.112981 0.141827
0 0.051683 0.396635 0.084135 0.091346
0 0.634615 0.379808 0.052885 0.091346
0 0.748798 0.391827 0.055288 0.086538
0 0.305288 0.397837 0.052885 0.069712
0 0.216346 0.397837 0.048077 0.069712
1 0.174279 0.379808 0.050481 0.067308
1 0.801683 0.383413 0.055288 0.088942
1 0.443510 0.411058 0.045673 0.072115
1 0.555288 0.400240 0.043269 0.074519
1 0.500000 0.383413 0.038462 0.064904
0 0.252404 0.360577 0.033654 0.048077
1 0.399038 0.393029 0.043269 0.064904
2.Safety-Helmet-Detection项目中标注数据的理解
我个人的理解 第一列可能是0、1代表了两种类型。比如:0是没有带安全帽的头。1是带的安全帽。后面4个数字我理解应该跟标注对象的位置有关,但都是小于1的数字,我有点迷糊。于是我去看了Safety-Helmet-Detection项目的主页,有这么一段话:
又要使用我中式英语技能了。大概意思是运行tools目录下的coverter.py程序把标注信息从xml文件转换为.txt文件。那打开程序代码读一读吧:
python
from xml.dom import minidom
import os
classes={"helmet":0,"head":1,"person":2}
def convert_coordinates(size, box):
dw = 1.0/size[0]
dh = 1.0/size[1]
x = (box[0]+box[1])/2.0
y = (box[2]+box[3])/2.0
w = box[1]-box[0]
h = box[3]-box[2]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
def converter(classes):
old_labels_path = "../data/validations_old"
new_labels_path = "../data/validations/"
for file_name in os.listdir(old_labels_path):
old_file = minidom.parse(f"{old_labels_path}/{file_name}")
name_out = (file_name[:-4]+'.txt')
with open(f"{new_labels_path}/{name_out}", "w") as new_file:
itemlist = old_file.getElementsByTagName('object')
size = old_file.getElementsByTagName('size')[0]
width = int((size.getElementsByTagName('width')[0]).firstChild.data)
height = int((size.getElementsByTagName('height')[0]).firstChild.data)
for item in itemlist:
# get class label
class_name = (item.getElementsByTagName('name')[0]).firstChild.data
if class_name in classes:
label_str = str(classes[class_name])
else:
label_str = "-1"
print (f"{class_name} not in function classes")
# get bbox coordinates
xmin = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('xmin')[0]).firstChild.data
ymin = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('ymin')[0]).firstChild.data
xmax = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('xmax')[0]).firstChild.data
ymax = ((item.getElementsByTagName('bndbox')[0]).getElementsByTagName('ymax')[0]).firstChild.data
b = (float(xmin), float(xmax), float(ymin), float(ymax))
bb = convert_coordinates((width,height), b)
#print(bb)
#new_file.write(f"{label_str} {' '.join([(f'{a}.6f') for a in bb])}\n")
new_file.write(f"{label_str} {' '.join([(f'{a:.6f}') for a in bb])}\n")
print (f"wrote {name_out}")
def main():
converter(classes)
if __name__ == '__main__':
main()
读了之后就明白了,4个数字中第一个代表标记对象中心x坐标/图片宽度(就是Xmax),第二个代表标记对象中心y坐标/图片高度(就是Ymax),第三个是标记对象占图片的宽度比例,第四个是标记对象占图片的高度比例。其实跟两个坐标来表达标记物没有太大区别。我这里还不明白作者为何使用这样的数据结构?是所有的模型都是这样?还是这一个模型是这样的?后面深度学习后,肯定能明白的。
3.在运行coverter.py中遇到的一些问题
我记得主要是目录的问题。主要是:
python
old_labels_path = "../data/validations_old"
new_labels_path = "../data/validations/"
不对的话就注意一下当前目录在哪里,你标注的文件放哪里的就行了。开源项目里面没有validations_old和validations目录,可以手动创建一个就行了。哦忘了说,运行文件可以用
python converter.py