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

image

image

image

image

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

image

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()

image

2.2、设置颜色

image

纯透明、红框

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、 不允许编辑标签,单击标签就可以保存。标签界面高度加大。

image

image

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

image

 

继续修改功能------------------

删除框后,如果图中没有任何框了,对应的标注文件也删除,如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'))

 

posted @ 2025-07-24 12:32  夕西行  阅读(445)  评论(0)    收藏  举报