python 比较两个文件夹中的文件名(Annotation标注完全检查)

查找并列出标注缺失的图片文件
该代码段用于比较Annotations和Object_split两个文件夹中的XML和JPEG文件,找出那些在其中一个文件夹中有而另一个文件夹中没有的文件。它利用Python的set操作和os库来检查文件名的差异,特别是关注那些XML标注文件可能缺失的情况。
原因

Annotations和JPEGS的文件夹,有部分图片的标注缺失。

代码
import os
def compare_folders(folder1, folder2):
    # files1 = set(os.listdir(folder1))
    # files2 = set(os.listdir(folder2))

    files1 = set(os.path.splitext(file)[0] for file in os.listdir(folder1))
    files2 = set(os.path.splitext(file)[0] for file in os.listdir(folder2))
    unique_files = files1.symmetric_difference(files2)

    return unique_files


folder1 = './Annotations'
folder2 = './Object_split'

unique_files = compare_folders(folder1, folder2)

def get_files_with_extension(folder, extension):
    files = []
    for file in os.listdir(folder):
        if file.endswith(extension):
            files.append(file)
    return files
print(len(unique_files))
# for file in unique_files:
#     print(file)


for file in get_files_with_extension(folder1, ".xml"):
    if os.path.splitext(file)[0] in unique_files:
        print(file)

for file in get_files_with_extension(folder2, ".jpg"):
    if os.path.splitext(file)[0] in unique_files:
        print(file)

python中使用Set函数可以清楚list中的重复项
splitext分割文件名
endswith获取拓展名
symmetric_difference进行list比较

<think>我们正在开发一个图像标注工具,目标是使用Python实现。根据引用[1]和引用[3],我们了解到图像标注工具通常用于生成训练数据,例如目标检测(矩形框标注)或抓取检测(点与角度标注)。引用[1]中提到了labelImg,它是一个使用Python和Qt开发的跨平台工具,支持多种标签格式。引用[3]则提到一个轻量级的抓取检测标注工具,通过简单的GUI界面实现标注。 我们的工具将专注于矩形框标注(类似labelImg),考虑以下功能: 1.支持加载图像显示。2.用户可以通过鼠标绘制矩形框。3.支持修改和删除已绘制的矩形框。 4.支持保存标注结果(例如PASCALVOC格式的XML文件)。技术选型:- GUI框架:使用PyQt5(与labelImg相同)或Tkinter(Python标准库)。由于PyQt5功能更强大,我们选择PyQt5。-图像处理:使用OpenCV或PIL(Pillow)。这里我们使用PIL,因为PyQt5可以很好地与PIL结合。 实现步骤:1.创建一个主窗口,用于显示图像和标注。2.实现鼠标事件:按下鼠标左键开始绘制矩形框,拖动鼠标调整矩形框大小,释放鼠标左键完成绘制。3.记录每个矩形框的位置(xmin, ymin,xmax, ymax)和类别。4.提供类别输入(例如通过下拉菜单或文本框)。5.实现保存功能,将标注信息写入XML文件(PASCALVOC格式)。 代码结构:-主窗口类(MainWindow)继承自QMainWindow。-包含一个QLabel用于显示图像。 -事件处理:mousePressEvent, mouseMoveEvent, mouseReleaseEvent。 -存储矩形框的列表,每个矩形框包含坐标和类别。由于代码较长,我们将分步骤实现。以下是一个简化的示例代码框架:```pythonimportsysfrom PyQt5.QtWidgetsimport (QApplication, QMainWindow, QLabel,QWidget, QVBoxLayout,QHBoxLayout, QPushButton, QFileDialog, QLineEdit, QComboBox) fromPyQt5.QtCoreimport Qt, QPoint,QRectfromPyQt5.QtGuiimport QImage,QPixmap, QPainter, QPen,QColorfromPIL importImage,ImageDrawclassImageLabel(QLabel):def __init__(self,parent=None):super().__init__(parent)self.setMouseTracking(True)self.drawing= Falseself.rect_start= QPoint()self.rect_end= QPoint()self.rectangles= []#存储矩形框,每个元素为(QRect,label)self.current_rect =Noneself.current_label= "object"def mousePressEvent(self,event):ifevent.button() ==Qt.LeftButton:self.drawing =Trueself.rect_start =event.pos()self.rect_end= event.pos()self.update()defmouseMoveEvent(self, event):ifself.drawing:self.rect_end =event.pos()self.update()def mouseReleaseEvent(self,event):ifevent.button() ==Qt.LeftButtonand self.drawing:self.drawing =Falserect= QRect(self.rect_start,self.rect_end).normalized()if rect.width()>5 andrect.height() >5:#避免误操作self.rectangles.append((rect,self.current_label))self.current_rect =Noneself.update()defpaintEvent(self,event):super().paintEvent(event)painter= QPainter(self)painter.setPen(QPen(QColor(255,0,0),2,Qt.SolidLine))for rect, labelin self.rectangles:painter.drawRect(rect)painter.drawText(rect.topLeft(), label)if self.drawing:painter.drawRect(QRect(self.rect_start, self.rect_end))class MainWindow(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("图像标注工具")self.central_widget= QWidget()self.setCentralWidget(self.central_widget)layout =QVBoxLayout()self.image_label =ImageLabel()self.image_label.setAlignment(Qt.AlignCenter)layout.addWidget(self.image_label)#按钮和标签选择hbox =QHBoxLayout()self.btn_open =QPushButton("打开图像")self.btn_open.clicked.connect(self.open_image)hbox.addWidget(self.btn_open)self.btn_save= QPushButton("保存标注")self.btn_save.clicked.connect(self.save_annotation)hbox.addWidget(self.btn_save)self.label_combo =QComboBox()self.label_combo.addItems(["person", "car","dog", "cat"])self.label_combo.currentTextChanged.connect(self.change_label)hbox.addWidget(self.label_combo)layout.addLayout(hbox)self.central_widget.setLayout(layout)self.image =Nonedefopen_image(self):file_name, _= QFileDialog.getOpenFileName(self, "打开图像", "","ImageFiles (*.png*.jpg*.bmp)")iffile_name:self.image= Image.open(file_name)#转换为QImageqimage =QImage(self.image.tobytes(),self.image.width,self.image.height,self.image.width*3,QImage.Format_RGB888)pixmap= QPixmap.fromImage(qimage)self.image_label.setPixmap(pixmap)self.image_label.rectangles= []#清除之前的标注def change_label(self, text):self.image_label.current_label =textdefsave_annotation(self):#保存为PASCALVOC格式的XML文件ifnotself.imageor notself.image_label.rectangles:returnfile_name,_ =QFileDialog.getSaveFileName(self,"保存标注","", "XML Files(*.xml)")iffile_name:#创建XML文件#这里需要实现XML的生成,包括图像尺寸和每个矩形框的坐标和类别#由于代码较长,此处省略,可以参考labelImg的XML生成方式passif__name__ =="__main__":app =QApplication(sys.argv)window =MainWindow()window.show()sys.exit(app.exec_())``` 注意:上述代码是一个基础框架,实际应用中需要完善以下功能: 1.保存标注时生成PASCALVOC格式的XML文件。需要记录图像文件名、尺寸以及每个矩形框的坐标和类别。2.支持修改和删除矩形框(例如通过右键菜单或键盘事件)。 3.支持调整类别和添加新类别。由于时间限制,我们提供了一个基本框架。您可以根据需要扩展功能。 §§相关问题§§1.如何将标注信息保存为PASCAL VOC格式的XML文件? 2.如何实现矩形框的编辑(移动、调整大小)和删除?3.如何支持多类别标注允许用户自定义类别?4.如何优化标注工具的用户体验(例如快捷键、撤销重做)?</think>以下是使用Python开发图像标注工具的完整实现方案及代码示例: ### 图像标注工具实现方案 #### 核心功能设计 1. **图像加载与显示**:支持常见图像格式(PNG/JPG等) 2. **标注绘制**:矩形框标注(支持拖拽调整) 3. **标签管理**:自定义类别和颜色 4. **标注保存**:支持PASCAL VOC XML格式 5. **交互功能**:撤销/重做、缩放、导航 #### 技术选型 - **GUI框架**:PyQt5(跨平台,功能强大) - **图像处理**:OpenCV + Pillow - **标注格式**:PASCAL VOC XML - **数据结构**:JSON存储配置 ### 代码实现示例 ```python import sys import os import cv2 import json from lxml import etree from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QFileDialog, QLineEdit, QComboBox) from PyQt5.QtCore import Qt, QPoint, QRect from PyQt5.QtGui import QImage, QPixmap, QPainter, QPen, QColor class ImageLabel(QLabel): def __init__(self, parent=None): super().__init__(parent) self.setMouseTracking(True) self.drawing = False self.rect_start = QPoint() self.rect_end = QPoint() self.rectangles = [] # 存储所有标注框 self.current_rect = None self.current_label = "object" def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.drawing = True self.rect_start = event.pos() self.rect_end = event.pos() self.update() def mouseMoveEvent(self, event): if self.drawing: self.rect_end = event.pos() self.update() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton and self.drawing: self.drawing = False rect = QRect(self.rect_start, self.rect_end).normalized() if rect.width() > 5 and rect.height() > 5: # 避免误操作 self.rectangles.append((rect, self.current_label)) self.current_rect = None self.update() def paintEvent(self, event): super().paintEvent(event) painter = QPainter(self) painter.setPen(QPen(QColor(255, 0, 0), 2, Qt.SolidLine)) # 绘制已有标注 for rect, label in self.rectangles: painter.drawRect(rect) painter.drawText(rect.topLeft(), label) # 绘制当前标注 if self.drawing: painter.drawRect(QRect(self.rect_start, self.rect_end)) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("图像标注工具 v1.0") self.setGeometry(100, 100, 1200, 800) # 主布局 central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout() # 图像显示区域 self.image_label = ImageLabel() self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setStyleSheet("background-color: #333;") main_layout.addWidget(self.image_label, 1) # 控制面板 control_layout = QHBoxLayout() # 打开图像按钮 self.btn_open = QPushButton("打开图像") self.btn_open.clicked.connect(self.open_image) control_layout.addWidget(self.btn_open) # 保存标注按钮 self.btn_save = QPushButton("保存标注") self.btn_save.clicked.connect(self.save_annotation) control_layout.addWidget(self.btn_save) # 标签选择 control_layout.addWidget(QLabel("类别:")) self.label_combo = QComboBox() self.label_combo.addItems(["person", "car", "dog", "cat"]) self.label_combo.currentTextChanged.connect(self.change_label) control_layout.addWidget(self.label_combo) # 自定义标签输入 control_layout.addWidget(QLabel("自定义:")) self.custom_label = QLineEdit() self.custom_label.setPlaceholderText("输入新类别") control_layout.addWidget(self.custom_label) # 添加自定义标签按钮 self.btn_add_label = QPushButton("添加") self.btn_add_label.clicked.connect(self.add_custom_label) control_layout.addWidget(self.btn_add_label) main_layout.addLayout(control_layout) central_widget.setLayout(main_layout) # 当前图像路径 self.current_image = None # 加载配置 self.load_config() def open_image(self): file_name, _ = QFileDialog.getOpenFileName( self, "打开图像", "", "Image Files (*.png *.jpg *.bmp)") if file_name: self.current_image = file_name # 使用OpenCV读取图像 img = cv2.imread(file_name) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换为QImage height, width, channel = img.shape bytes_per_line = 3 * width q_img = QImage(img.data, width, height, bytes_per_line, QImage.Format_RGB888) # 显示图像 self.image_label.setPixmap(QPixmap.fromImage(q_img)) self.image_label.rectangles = [] # 清除之前的标注 def change_label(self, text): self.image_label.current_label = text def add_custom_label(self): new_label = self.custom_label.text().strip() if new_label and new_label not in [self.label_combo.itemText(i) for i in range(self.label_combo.count())]: self.label_combo.addItem(new_label) self.label_combo.setCurrentText(new_label) self.custom_label.clear() def save_annotation(self): if not self.current_image or not self.image_label.rectangles: return # 创建XML结构 root = etree.Element("annotation") # 添加文件名 filename = os.path.basename(self.current_image) etree.SubElement(root, "filename").text = filename # 添加图像尺寸 size = etree.SubElement(root, "size") pixmap = self.image_label.pixmap() etree.SubElement(size, "width").text = str(pixmap.width()) etree.SubElement(size, "height").text = str(pixmap.height()) etree.SubElement(size, "depth").text = "3" # RGB图像 # 添加每个标注对象 for rect, label in self.image_label.rectangles: obj = etree.SubElement(root, "object") etree.SubElement(obj, "name").text = label etree.SubElement(obj, "pose").text = "Unspecified" etree.SubElement(obj, "truncated").text = "0" etree.SubElement(obj, "difficult").text = "0" bndbox = etree.SubElement(obj, "bndbox") etree.SubElement(bndbox, "xmin").text = str(rect.left()) etree.SubElement(bndbox, "ymin").text = str(rect.top()) etree.SubElement(bndbox, "xmax").text = str(rect.right()) etree.SubElement(bndbox, "ymax").text = str(rect.bottom()) # 保存XML文件 xml_file = os.path.splitext(self.current_image)[0] + ".xml" with open(xml_file, "wb") as f: f.write(etree.tostring(root, pretty_print=True, xml_declaration=True, encoding="UTF-8")) # 保存标签配置 self.save_config() print(f"标注已保存至: {xml_file}") def load_config(self): try: with open("label_config.json", "r") as f: config = json.load(f) self.label_combo.clear() self.label_combo.addItems(config["labels"]) except FileNotFoundError: pass # 使用默认标签 def save_config(self): labels = [self.label_combo.itemText(i) for i in range(self.label_combo.count())] config = {"labels": labels} with open("label_config.json", "w") as f: json.dump(config, f) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` ### 功能说明 1. **图像加载**:支持常见格式,显示在中央区域 2. **矩形标注**:鼠标拖拽绘制标注框 3. **类别管理**: - 预设常见类别(人/车/狗/猫) - 支持添加自定义类别 - 自动保存类别配置 4. **标注保存**: - 生成PASCAL VOC格式XML文件 - 包含图像尺寸、对象位置和类别 5. **用户界面**: - 直观的控制面板 - 实时标注显示 - 响应式设计 ### 使用指南 1. 点击"打开图像"加载图片 2. 从下拉框选择类别(或添加新类别) 3. 在图像上拖拽鼠标绘制标注框 4. 点击"保存标注"生成XML文件 5. XML文件与图像同目录保存 ### 扩展建议 1. **标注类型扩展**:支持多边形、关键点标注 2. **数据集管理**:添加图像目录浏览功能 3. **自动标注**:集成预训练模型辅助标注[^3] 4. **导出格式**:增加YOLO、COCO等格式支持[^1] 5. **协作功能**:添加多用户标注管理
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值