当前位置: 首页 > ds >正文

图像分类标注小工具

图像分类标注小工具
不说废话
上代码

import os
import cv2
import shutil
import csvclass ImageLabeler:def __init__(self, input_dir, output_dir, class_names, csv_path='label_log.csv', preview_size=(800, 800)):self.input_dir = input_dirself.output_dir = output_dirself.class_names = class_namesself.csv_path = csv_pathself.preview_size = preview_sizeself.image_files = self._get_image_files()self.labeled_images = self._read_labeled_images()  # 读取已经标注过的图像self.image_files = [f for f in self.image_files if f not in self.labeled_images]  # 跳过已标注的self.index = 0self.history = []self._create_class_folders()self._init_csv()def _get_image_files(self):image_paths = []for root, _, files in os.walk(self.input_dir):for f in files:if f.lower().endswith(('.jpg', '.jpeg', '.png')):full_path = os.path.join(root, f)rel_path = os.path.relpath(full_path, self.input_dir)image_paths.append(rel_path)return sorted(image_paths)def _read_labeled_images(self):if not os.path.exists(self.csv_path):return set()with open(self.csv_path, mode='r', newline='') as file:reader = csv.reader(file)next(reader)  # 跳过表头return set(row[0] for row in reader)def _create_class_folders(self):for class_name in self.class_names:os.makedirs(os.path.join(self.output_dir, class_name), exist_ok=True)def _init_csv(self):if not os.path.exists(self.csv_path):with open(self.csv_path, mode='w', newline='') as file:writer = csv.writer(file)writer.writerow(['image_name', 'label'])def _resize_preview(self, img):return cv2.resize(img, self.preview_size, interpolation=cv2.INTER_AREA)def _write_csv(self, image_name, label):with open(self.csv_path, mode='a', newline='') as file:writer = csv.writer(file)writer.writerow([image_name, label])def _remove_last_csv_entry(self):with open(self.csv_path, mode='r', newline='') as file:lines = file.readlines()if len(lines) <= 1:print("CSV 中没有可删除的记录。")returnwith open(self.csv_path, mode='w', newline='') as file:file.writelines(lines[:-1])def label_images(self):print("开始图像标注:")print("按数字键 1、2、3... 进行分类:【1:埃及;2:希腊;3:罗马和方形;4:其他】")print("按 空格键 回退,按 ESC 退出")total = len(self.image_files)while self.index < total:img_name = self.image_files[self.index]img_path = os.path.join(self.input_dir, img_name)img = cv2.imread(img_path)if img is None:print(f"无法读取图像:{img_path}")self.index += 1continueresized_img = self._resize_preview(img)progress_title = f"[{self.index + 1}/{total}] Label: {img_name}"cv2.imshow(progress_title, resized_img)cv2.moveWindow(progress_title, 100, 100)key = cv2.waitKey(0)cv2.destroyWindow(progress_title)if key in [27]:print("退出标注工具。")breakelif key == ord('s'):print(f"跳过: {img_name}")self.index += 1continueelif key == 32:if self.history:last = self.history.pop()self.index = last['index']if os.path.exists(last['copied_path']):os.remove(last['copied_path'])self._remove_last_csv_entry()print(f"撤销: {last['image_name']}{last['label']}")else:print("无历史记录可撤销。")continueelse:class_index = key - ord('1')if 0 <= class_index < len(self.class_names):class_name = self.class_names[class_index]dst_path = os.path.join(self.output_dir, class_name, img_name)# 确保目标文件夹存在(包括子目录)os.makedirs(os.path.dirname(dst_path), exist_ok=True)shutil.copy(img_path, dst_path)self._write_csv(img_name, class_name)self.history.append({'index': self.index,'image_name': img_name,'label': class_name,'copied_path': dst_path})print(f"{img_name}{class_name}   ({self.index + 1}/{total})")self.index += 1else:print("无效按键,跳过该图片。")cv2.destroyAllWindows()if __name__ == '__main__':input_folder = 'batch_0002'output_folder = 'labeled_images'categories = ['1_Egyptian', '2_Greek', '3_Roman', '4_Other']  # 可自定义分类名labeler = ImageLabeler(input_dir=input_folder,output_dir=output_folder,class_names=categories,csv_path='label_log.csv',# preview_size=(640, 480)preview_size=(800, 800))labeler.label_images()
http://www.xdnf.cn/news/345.html

相关文章:

  • ABAP OLE
  • 『前端样式分享』联系我们卡片式布局 自适应屏幕 hover动效 在wikijs中使用 (代码拿来即用)
  • 使用Gone MCP 组件编写MCP Server
  • 《系统分析师-第三阶段—总结(一)》
  • LUN Capacity(Blocks) 是什么意思
  • Java项目—— 拼图小游戏(进阶版)
  • 表征流体作用力的参数及其特性
  • 2025年MathorCup数学应用挑战赛【B题成品论文第二版】(免费分享)
  • Allure测试报告按测试终端和测试类型智能分类查看
  • 杭州小红书代运营公司-品融电商:全域增长策略的实践者
  • Oracle 19c部署之手工建库(四)
  • Deno 包管理器:现代 JavaScript/TypeScript 运行时的新范式
  • 标题:民锋视角下的节奏演变逻辑:探寻市场波动的内在秩序
  • 网络互连与互联网3
  • SPWM-H桥逆变器工作原理
  • 关于防火墙
  • 解决 pip install tts 报错问题-—SadTalker的AI数字人视频—未来之窗超算中心
  • openEuler系统下源码编译安装Nginx实践教程
  • 磁盘文件管理与库
  • 深度学习3.2 线性回归的从零开始实现
  • 深度学习中的卷积神经网络
  • git -- 对远程仓库的操作 -- 查看,添加(与clone对比),抓取和拉取,推送(注意点,抓取更新+合并的三种方法,解决冲突,对比),移除
  • 模块内聚:理解和优化模块设计的关键
  • C#如何动态生成实体类?5种方法详解与实战演示
  • 运营商二要素API接口有哪些应用场景?
  • 2025年03月中国电子学会青少年软件编程(Python)等级考试试卷(三级)真题
  • 练习(杨辉三角、字符串旋转)
  • 算法-链表
  • datasheet数据手册-阅读方法
  • 拆机装机,通电主板亮灯风扇不转无法开机解决办法