labelImg安装、设置颜色、打包成exe
本文更改了如下几个功能:
- 打包的labelImg.exe自动识别同目录的predefined_classes.txt,请标注前定义好具体的标签。保存目录里不再需要classes.txt。
- 默认YOLO格式,且勾选Auto Save mode。
- 去掉透明度,使用红色框,方便浏览。
- 标签界面高度依据标签数自动加大,避免标签多了每次下拉滑动条。当超过18个标签,出现滚动条。
- 不允许编辑标签,单击标签就可以保存,不需要双击。
需要python3.9,不建议更高版本。
0、创建python3.9环境
conda create --name=labelImg python=3.9 conda activate labelImg
1、安装labelImg
pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple
2.1 默认使用同目录的predefined_classes.txt,不再需要classes.txt。默认YOLO格式,且勾选Auto Save mode




保存目录不再需要classes.txt。为了防止读取txt有问题,指定utf8

52行附近
def save(self, class_list=[], target_file=None): out_file = None # Update yolo .txt #out_class_file = None # Update class list .txt if target_file is None: out_file = open( self.filename + TXT_EXT, 'w', encoding=ENCODE_METHOD) #classes_file = os.path.join(os.path.dirname(os.path.abspath(self.filename)), "classes.txt") #out_class_file = open(classes_file, 'w') else: out_file = codecs.open(target_file, 'w', encoding=ENCODE_METHOD) #classes_file = os.path.join(os.path.dirname(os.path.abspath(target_file)), "classes.txt") #out_class_file = open(classes_file, 'w') for box in self.box_list: class_index, x_center, y_center, w, h = self.bnd_box_to_yolo_line(box, class_list) # print (classIndex, x_center, y_center, w, h) out_file.write("%d %.6f %.6f %.6f %.6f\n" % (class_index, x_center, y_center, w, h)) # print (classList) # print (out_class_file) ''' for c in class_list: out_class_file.write(c+'\n') out_class_file.close() ''' out_file.close()

2.2、设置颜色

纯透明、红框
DEFAULT_LINE_COLOR = QColor(0, 255, 0, 255) DEFAULT_FILL_COLOR = QColor(255, 0, 0, 0) DEFAULT_SELECT_LINE_COLOR = QColor(255, 0, 0) DEFAULT_SELECT_FILL_COLOR = QColor(0, 128, 255, 0) DEFAULT_VERTEX_FILL_COLOR = QColor(0, 255, 0, 255) DEFAULT_HVERTEX_FILL_COLOR = QColor(255, 0, 0)
打开看下效果,先删除 C:\Users\YourAccount\.labelImgSettings.pkl,重新打开labelImg
2种打开方式:
- 终端里直接输入labelImg,回车。即开篇的第1个图中labelImg.py
- 如下目录双击labelImg.exe

2.3、 不允许编辑标签,单击标签就可以保存。标签界面高度加大。


3、打包exe
安装pyinstaller
pip install pyinstaller
进入目录
cd /d D:\miniconda3\envs\labelImg\Lib\site-packages\labelImg
修改labelImg.py文件,在文件末尾
1557行附近
def load_yolo_txt_by_filename(self, txt_path):
if self.file_path is None:
return
if os.path.isfile(txt_path) is False:
return
self.set_format(FORMAT_YOLO)
if getattr(sys, 'frozen', False):# 打包环境下使用可执行文件同目录的predefined_classes.txt
default_class_file = os.path.join(os.path.dirname(sys.executable), "predefined_classes.txt")
else:# 开发环境下使用labelImg.py同目录的predefined_classes.txt
default_class_file = os.path.join(os.path.dirname(__file__), "predefined_classes.txt")
#t_yolo_parse_reader = YoloReader(txt_path, self.image, os.path.join(os.path.dirname(__file__), "predefined_classes.txt"))
t_yolo_parse_reader = YoloReader(txt_path, self.image, default_class_file)#修改下
shapes = t_yolo_parse_reader.get_shapes()
1620行附近
# Tzutalin 201705+: Accept extra agruments to change predefined class file argparser = argparse.ArgumentParser() argparser.add_argument("image_dir", nargs="?") ''' argparser.add_argument("class_file", default=os.path.join(os.path.dirname(__file__), "predefined_classes.txt"), nargs="?") ''' if getattr(sys, 'frozen', False):# 打包环境下使用可执行文件同目录的predefined_classes.txt default_class_file = os.path.join(os.path.dirname(sys.executable), "predefined_classes.txt") else:# 开发环境下使用labelImg.py同目录的predefined_classes.txt default_class_file = os.path.join(os.path.dirname(__file__), "predefined_classes.txt") argparser.add_argument("class_file", default=default_class_file, #修改下 nargs="?") argparser.add_argument("save_dir", nargs="?") args = argparser.parse_args(argv[1:])
打包,--windowed不带小黑窗口
pyinstaller --onefile --windowed labelImg.py
得到的exe可以放到其他地方,使用时请先编辑好predefined_classes.txt

继续修改功能------------------
删除框后,如果图中没有任何框了,对应的标注文件也删除,如txt等。
labelImg.py里save_labels方法,加粗字体为新增
print('Image:{0} -> Annotation:{1}'.format(self.file_path, annotation_file_path)) #保存后检查如果没有任何标签框,删除文件 if self.no_shapes() and os.path.exists(annotation_file_path): try: os.remove(annotation_file_path) self.status("已删除空标签文件: {}".format(os.path.basename(annotation_file_path))) except Exception as e: self.status("删除文件时出错: {}".format(str(e))) return True except LabelFileError as e:
删除当前图片,如果有标注文件,也一起删除。删除快捷键改为R
labelImg.py里delete_image函数
def delete_image(self): delete_path = self.file_path ''' if delete_path is not None: self.open_next_image() self.cur_img_idx -= 1 self.img_count -= 1 if os.path.exists(delete_path): os.remove(delete_path) self.import_dir_images(self.last_open_dir) ''' if delete_path is not None: # 记录当前索引 current_idx = self.cur_img_idx # 删除图像文件和对应的标注文件 if os.path.exists(delete_path): # 删除图像文件 os.remove(delete_path) # 删除对应的标注文件 base_name = os.path.splitext(delete_path)[0] # 删除所有可能的标注文件格式 annotation_files = [ base_name + '.txt', # YOLO格式 base_name + '.xml', # Pascal VOC格式 base_name + '.json', # Create ML格式 ] for ann_file in annotation_files: try: if os.path.exists(ann_file): os.remove(ann_file) print(f"已删除标注文件: {os.path.basename(ann_file)}") except Exception as e: print(f"删除标注文件 {ann_file} 时出错: {str(e)}") # 删除文件 if os.path.exists(delete_path): os.remove(delete_path) # 手动执行 import_dir_images 的部分逻辑,但不调用 open_next_image self.last_open_dir = self.last_open_dir self.dir_name = self.last_open_dir self.file_list_widget.clear() self.m_img_list = self.scan_all_images(self.last_open_dir) self.img_count = len(self.m_img_list) # 重新填充文件列表 for imgPath in self.m_img_list: item = QListWidgetItem(imgPath) self.file_list_widget.addItem(item) # 如果还有图片,打开正确的图片 if self.m_img_list: # 确定要打开的索引 if current_idx < len(self.m_img_list): next_idx = current_idx # 打开下一张 else: next_idx = len(self.m_img_list) - 1 # 打开上一张 # 打开图片 self.cur_img_idx = next_idx filename = self.m_img_list[next_idx] if filename: self.load_file(filename) else: # 没有图片了,清空界面 self.file_path = None self.reset_state()
labelImg.py里__init__函数
delete_image = action(get_str('deleteImg'), self.delete_image, 'R', 'close', get_str('deleteImgDetail'))

浙公网安备 33010602011771号