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

音频分类标注工具

pyqt 分类标注工具:

import glob
import sys
import json
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableWidget, QTableWidgetItem,QSplitter, QVBoxLayout, QWidget, QPushButton, QRadioButton,QButtonGroup, QLabel, QHBoxLayout, QMessageBox
)
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QColor
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContentclass AudioAnnotator(QMainWindow):def __init__(self,base_dir):super().__init__()self.setWindowTitle("MP3标注工具 (单选标注)")self.setGeometry(100, 100, 1000, 600)  # 增大窗口尺寸# 初始化媒体播放器self.player = QMediaPlayer()# 主布局main_widget = QWidget()self.setCentralWidget(main_widget)layout = QVBoxLayout()main_widget.setLayout(layout)# 分割左右区域splitter = QSplitter(Qt.Horizontal)# 左侧:音频文件列表(表格)self.table = QTableWidget()self.table.setColumnCount(2)self.table.setHorizontalHeaderLabels(["音频文件", "标注状态"])self.table.setEditTriggers(QTableWidget.NoEditTriggers)self.table.cellClicked.connect(self.play_audio)self.table.setColumnWidth(0, 400)  # 文件名列宽self.table.setColumnWidth(1, 150)  # 状态列宽# 右侧:单选标注区域right_panel = QWidget()right_layout = QVBoxLayout()# 单选按钮组self.radio_group = QButtonGroup()self.radio_1 = QRadioButton("small (1)")self.radio_2 = QRadioButton("normal (2)")self.radio_3 = QRadioButton("3 (3)")self.radio_group.addButton(self.radio_1, 1)self.radio_group.addButton(self.radio_2, 2)self.radio_group.addButton(self.radio_3, 3)self.radio_group.buttonClicked[int].connect(self.on_radio_selected)right_layout.addWidget(QLabel("标注选项:"))right_layout.addWidget(self.radio_1)right_layout.addWidget(self.radio_2)right_layout.addWidget(self.radio_3)right_layout.addStretch()right_panel.setLayout(right_layout)# 底部按钮self.btn_save = QPushButton("保存标注")self.btn_save.clicked.connect(self.save_annotation)# 添加到布局splitter.addWidget(self.table)splitter.addWidget(right_panel)layout.addWidget(splitter)layout.addWidget(self.btn_save)self.json_path=os.path.basename(base_dir)+'.json'files = glob.glob(base_dir + "/*.mp3")self.audio_files = files# 加载历史标注self.annotations = {}self.load_annotations()self.load_audio_files()def on_radio_selected(self, checked_id):print(f"选中了按钮 ID: {checked_id}")current_row = self.table.currentRow()if current_row >= 0:audio_file = self.audio_files[current_row]checked_id = self.radio_group.checkedId()if checked_id == -1:QMessageBox.warning(self, "警告", "请选择标注选项!")return# 更新标注字典self.annotations[audio_file] = checked_id# 保存到JSON文件with open(self.json_path, "w", encoding="utf-8") as f:json.dump(self.annotations, f, ensure_ascii=False, indent=4)# 更新表格显示self.load_audio_files()def load_audio_files(self):"""加载音频文件到表格并显示标注状态"""self.table.setRowCount(len(self.audio_files))# 标注选项映射label_map = {1: "small", 2: "normal", 3: "3"}for i, file in enumerate(self.audio_files):# 文件名列file_item = QTableWidgetItem(file)self.table.setItem(i, 0, file_item)# 状态列status_item = QTableWidgetItem()if file in self.annotations:label_id = self.annotations[file]status_item.setText(f"已标注: {label_map.get(label_id, '未知')}")file_item.setBackground(QColor(200, 255, 200))  # 浅绿色背景status_item.setBackground(QColor(200, 255, 200))else:status_item.setText("未标注")file_item.setBackground(QColor(255, 200, 200))  # 浅红色背景status_item.setBackground(QColor(255, 200, 200))self.table.setItem(i, 1, status_item)def play_audio(self, row, column):if column > 0:  # 只在点击第一列时触发returnfile_path = self.audio_files[row]print('start play',file_path)media_content = QMediaContent(QUrl.fromLocalFile(file_path))self.player.setMedia(media_content)self.player.play()# 加载该音频的历史标注if file_path in self.annotations:checked_id = self.annotations[file_path]self.radio_group.button(checked_id).setChecked(True)else:self.radio_group.setExclusive(False)for btn in self.radio_group.buttons():btn.setChecked(False)self.radio_group.setExclusive(True)def save_annotation(self):"""保存标注到JSON文件"""current_row = self.table.currentRow()if current_row >= 0:audio_file = self.audio_files[current_row]checked_id = self.radio_group.checkedId()if checked_id == -1:QMessageBox.warning(self, "警告", "请选择标注选项!")return# 更新标注字典self.annotations[audio_file] = checked_id# 保存到JSON文件with open(self.json_path, "w", encoding="utf-8") as f:json.dump(self.annotations, f, ensure_ascii=False, indent=4)# 更新表格显示self.load_audio_files()QMessageBox.information(self, "成功", f"标注已保存:{os.path.basename(audio_file)} -> {checked_id}")else:QMessageBox.warning(self, "警告", "请先选中音频文件!")def load_annotations(self):"""加载历史标注文件"""if os.path.exists(self.json_path):try:with open(self.json_path, "r", encoding="utf-8") as f:self.annotations = json.load(f)# 转换键为绝对路径(如果保存的是相对路径)base_dir = os.path.dirname(os.path.abspath(self.json_path))fixed_annotations = {}for k, v in self.annotations.items():if not os.path.isabs(k):fixed_path = os.path.join(base_dir, k)if os.path.exists(fixed_path):fixed_annotations[fixed_path] = velse:fixed_annotations[k] = velse:fixed_annotations[k] = vself.annotations = fixed_annotationsexcept Exception as e:QMessageBox.warning(self, "警告", f"加载标注文件出错: {str(e)}")self.annotations = {}if __name__ == "__main__":base_dir = r"/Users/lbg/Documents/data/audio_0817_low"app = QApplication(sys.argv)window = AudioAnnotator(base_dir)window.show()sys.exit(app.exec_())

http://www.xdnf.cn/news/1316341.html

相关文章:

  • 矿物分类案列 (一)六种方法对数据的填充
  • Java零基础笔记20(Java高级技术:单元测试、反射、注解、动态代理)
  • RAC环境redo在各节点本地导致数据库故障恢复---惜分飞
  • 勾股数-洛谷B3845 [GESP样题 二级]
  • 平行双目视觉-动手学计算机视觉18
  • Linux应用软件编程---多任务(线程)(线程创建、消亡、回收、属性、与进程的区别、线程间通信、函数指针)
  • (一)React企业级后台(Axios/localstorage封装/动态侧边栏)
  • Android 对话框 - 基础对话框补充(不同的上下文创建 AlertDialog、AlertDialog 的三个按钮)
  • WPFC#超市管理系统(6)订单详情、顾客注册、商品销售排行查询和库存提示、LiveChat报表
  • C#WPF实战出真汁13--【营业查询】
  • [辩论] TDD(测试驱动开发)
  • ZKmall开源商城的移动商城搭建:Uni-app+Vue3 实现多端购物体验
  • Collections.synchronizedList是如何将List变为线程安全的
  • Trae 辅助下的 uni-app 跨端小程序工程化开发实践分享
  • 李宏毅NLP-11-语音合成
  • 在 Element UI 的 el-table 中实现某行标红并显示删除线
  • 【PHP】Hyperf:接入 Nacos
  • Centos中内存CPU硬盘的查询
  • vscode无法检测到typescript环境解决办法
  • OpenCV 图像处理核心技术:边界填充、算术运算与滤波处理实战
  • 大模型应用发展与Agent前沿技术趋势(中)
  • JVM常用工具:jstat、jmap、jstack
  • 【Linux】IO多路复用
  • 17-线程
  • Python自学10-常用数据结构之字符串
  • Python异常、模块与包(五分钟小白从入门)
  • 文件快速复制工具,传输速度提升10倍
  • riscv中断处理软硬件流程总结
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day6
  • Vue3 中的 ref、模板引用和 defineExpose 详解