视频硬字幕提取方法(可完全离线),开发个小工具辅助一下

作者分享了一款集成硬字幕提取、文字识别和图片缩放功能的工具Wondertool,基于Java开发并已在Gitee和GitHub开源。用户可以通过提供的教程进行操作,使用VideoSubFinder捕获字幕图片,然后通过PearOCR进行离线识别,最终由作者的工具生成TXT字幕文件。工具适用于需要大量视频字幕处理的场景,但OCR的准确性可能需要人工校对。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

没想到这么多人需要这些功能,本人整合了在这个最新的工具中,打开有教程

本人的最新工具:wondertool: 硬字幕提取、文字物体识别、图片缩放工具 (gitee.com)

3.0版本下载地址:wondertool 发行版 - Gitee.com

下载这4个包解压即可:

WonderTool_win-x64.zip
 WonderTool_win-x64.z01
 WonderTool_win-x64.z03
 WonderTool_win-x64.z02

原文如下:

最近博主闲下来了,思考人生接下来的方向,无聊时帮别人做了点小东西,贡献出来:

jre-17.0.7_win-x64的生成方式:

以管理员方式运行PowerShell执行命令:

cd $env:JAVA_HOME

jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.xml,java.desktop,jdk.management.agent --output E:\jre-17.0.7_win-x64

内部参数:

java -Dfile.encoding=UTF-8 -jar single-subtitle-text-1.0.0.jar

使用教程:

注意该图片的两个文件夹,都在下面这个软件的安装目录中。

VideoSubFinderWXW 拿来做字幕图片截取捕获,这是下载地址:

VideoSubFinder download | SourceForge.net

下载安装完成后,步骤:打开视频框选字幕位置,清空所有图片(之前识别的图片),开始识别。

捕获完在安装目录图片所示的第一个文件夹RGBImages中,PearOCR可以安装成浏览器应用可以离线识别,pearOCR官网如下:

PearOCR,在线图片转文字,免费OCR,在线图片文字提取,本地运算,无上传

上传RGBImages所有图片识别完后导出为txt。(如果后续出现问题,文件路径及文件名不建议带有中文)

接下来是我开发的小工具(代码已开源到github上),下载地址如下,

Release single-subtitle-text · Aaron-CJ/single-subtitle-text · GitHub

下载single-subtitle-text_win-x64.zip解压,看到single-subtitle-text_win-x64.exe

安全无毒,下面是代码:

package pers.lcj.tool;

import lombok.extern.log4j.Log4j2;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Aaron on 2023/4/28 0:29
 */
@Log4j2
public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in, "GBK");

        System.out.println("请输入导入文件路径:");
        Path inputPath = getPath(scanner, "导入文件");
        System.out.println("请输入导出目录路径:");
        Path outputPath = getPath(scanner, "导出目录");

        Map<String, String> result = readFile(inputPath.toString());

        writeOutputFiles(outputPath, result);
    }

    public static Path getPath(Scanner sc, String pathType) {
        Path path;
        do {
            String inputPath = sc.nextLine().replaceAll("^\"+|\"+$", "");
            path = Paths.get(inputPath);
            if (pathType.equals("导入文件") && !Files.isRegularFile(path)) {
                System.out.println("输入路径不是一个有效文件路径,请重新输入:");
                path = null;
            } else if (pathType.equals("导出目录") && !Files.isDirectory(path)) {
                System.out.println("输入路径不是一个有效文件路径,请重新输入:");
                path = null;
            }
        } while (path == null);
        return path;
    }

    private static final int BUFFER_SIZE = 8192;
    private static final Pattern REGEX_PATTERN = Pattern.compile("(?<=-\\s)([^.]+)(?=\\.jpeg)");

    private static Map<String, String> readFile(String inputFilePath) {
        Map<String, String> result = new HashMap<>();
        try (BufferedReader br = new BufferedReader(new FileReader(inputFilePath), BUFFER_SIZE)) {
            StringBuilder currentValueBuilder = new StringBuilder(1024); // 初始化StringBuilder大小,避免过多扩容
            Matcher matcher;
            String key = null;
            String currentLine;
            while ((currentLine = br.readLine()) != null) {
                matcher = REGEX_PATTERN.matcher(currentLine);
                if (matcher.find()) {
                    if (key != null) {
                        String value = currentValueBuilder.toString().trim();
                        result.put(key, value.isEmpty() ? "null" : value); // 添加新的结果到Map中,并清空StringBuilder
                        currentValueBuilder.setLength(0);
                    }
                    key = matcher.group(1);
                } else if (key != null) { // 对currentValue进行构建
                    currentValueBuilder.append(currentLine.trim()).append(" "); // 添加空格,避免拼接相邻字符串时出现语义混淆
                }
            }
            if (key != null) { // 处理最后一个结果
                result.put(key, currentValueBuilder.toString().trim().replace("  ------------ prower by PearOCR.com ------------", ""));
            }
        } catch (IOException e) {
            log.error("Error reading file:", e);
        }
        return result;
    }

    private static void writeOutputFiles(Path outputFolderPath, Map<String, String> result) {
        System.out.println("正在处理,请稍等......");
        result.entrySet().parallelStream().forEach(entry -> {
            String fileName = entry.getKey();
            Path txtFilePath = outputFolderPath.resolve(fileName + ".txt");
            try (BufferedWriter bw = Files.newBufferedWriter(txtFilePath, StandardCharsets.UTF_8)) {
                bw.write(entry.getValue());
            } catch (IOException e) {
                log.error("Error write file:", e);
            }
        });
        System.out.println("文件总计(个):" + result.size());
    }

}

Gradle 8.1.1引入的依赖:

plugins {
    // Java插件,该插件提供了Java应用和库的基本功能
    id 'java'

    // lombok插件,该插件支持在Java项目中使用Lombok注解
    id 'io.freefair.lombok' version '8.0.1'
}

group = 'pers.lcj.tool'
version = '1.0.0'

repositories {
    mavenLocal {
        url 'file:///D:/m2/repository'
    }
    maven { url 'https://maven.aliyun.com/repository/public/' }
    mavenCentral()
}

dependencies {
    // Lombok
    compileOnly 'org.projectlombok:lombok:1.18.26'
    annotationProcessor 'org.projectlombok:lombok:1.18.26'

    // Log4j2
    implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
    implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
    implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'

    // JUnit 5
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
}

jar {
    duplicatesStrategy = 'exclude'
    from {
        configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
    manifest {
        attributes 'Main-Class': 'pers.lcj.tool.Main'
    }
}

test {
    useJUnitPlatform()
}

log4j2.properties log4j2 配置文件

# 设置日志级别为info
rootLogger.level = info

# 控制台Appender的配置
appender.console.type = Console
appender.console.name = consoleLogger
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# 根日志记录器引用控制台Appender
rootLogger.appenderRef.stdout.ref = consoleLogger

# 日志文件存放路径
property.basePath = logs

# 组件Appender的名称、模式、路径和滚动策略
appender.rolling.type = RollingFile
appender.rolling.name = fileLogger
appender.rolling.fileName= ${basePath}/sst.log
appender.rolling.filePattern= ${basePath}/sst_%d{yyyyMMdd}.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} %level [%t] [%l] - %msg%n
appender.rolling.policies.type = Policies

# 组件Appender的滚动策略,包括按大小滚动和按时间滚动两种策略。
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
# 按大小滚动策略大小限制
appender.rolling.policies.size.size = 310MB
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
# 按时间滚动策略间隔时间(单位:天)
appender.rolling.policies.time.interval = 1
# 按时间滚动策略是否调整时区
appender.rolling.policies.time.modulate = true

# 组件Appender的滚动策略,包括按大小滚动和按时间滚动两种策略。
appender.rolling.strategy.type = DefaultRolloverStrategy

# 组件Appender的删除策略。
appender.rolling.strategy.delete.type = Delete
# 删除文件所在目录路径。
appender.rolling.strategy.delete.basePath = ${basePath}
# 删除最旧的文件之前可以在目录中保留的最大文件数。默认值为0,这意味着不会删除任何文件。
appender.rolling.strategy.delete.maxDepth = 92
# 用于指定删除文件的条件类型,按最后修改时间删除。
appender.rolling.strategy.delete.ifLastModified.type = IfLastModified
# 删除所有早于92天的文件。
appender.rolling.strategy.delete.ifLastModified.age = 92d

# 配置根日志记录器,引用组件Appender。
rootLogger.appenderRef.rolling.ref = fileLogger

打开single-subtitle-text_win-x64.exe,根据提示输入该txt文本文件路径和输入安装目录图片所示的第二个文件夹TXTResults的路径,生成相应的TXTResults后

点击软件ocr菜单中的这个即可生成你想要的视频字幕了,贡献给所有做视频的朋友,市面上做这个的基本都收费,特别视频多且视频时长 长的工作,可以带来助力,大大缩短工作时长,但毕竟ocr识别不是完全准确的,还是需要一些人工审核。虽然意义不是很大但是对同声传译的视频提取字幕,新闻传播类等的二次制作等有帮助,以及博主不知道的领域等有帮助。

<think>嗯,用户想了解如何利用大模型分析视频文件,获取内容介绍、音频字幕和标签等信息。首先,我需要拆解这个问题,考虑视频分析的各个组成部分。视频文件通常包含视觉、音频和文本(如字幕)信息,所以可能需要结合多模态模型来处理。 首先,视频内容介绍可能需要从视觉信息中提取。大模型比如Vision Transformer或者CLIP可以处理图像或视频帧,识别物体、场景、动作。可能需要分帧处理,然后使用模型生成描述,再汇总成整体内容。 然后是音频部分,用户提到音频字幕。这里可能有语音识别,需要将音频中的语音转成文字,比如用Whisper模型。同时,音频中可能有其他声音信息,比如背景音乐、音效,这些可能需要分类模型来识别,并生成标签。 还有视频的其他内容标签,可能包括情感分析、关键词提取、人物识别等。可能需要结合视觉和音频的分析结果,用多模态模型整合信息,比如Flamingo或者GPT-4V,来生成更全面的标签。 接下来要考虑处理步骤。视频分析通常需要预处理,比如分割成帧和音频,然后分别处理不同模态的数据,最后融合结果。可能需要用到计算机视觉库如OpenCV处理视频帧,用librosa或pytorch处理音频,再用HuggingFace的模型进行文本生成。 用户可能还关心实时性或者处理速度,但问题中没有提到,所以可能需要假设是离线处理。另外,存储和计算资源也是考虑因素,大模型可能需要较高的GPU资源,尤其是处理长视频时。 还有可能的挑战,比如视频时长较长,如何处理大量帧和音频数据,是否需要采样关键帧或者分段处理。此外,多模态信息的对齐,比如时间轴上的字幕和画面同步,可能需要时间戳的处理。 用户的需求可能包括自动生成视频摘要、提取关键词、生成字幕等应用场景,比如内容审核、视频推荐系统或辅助创作工具。需要确保回答覆盖这些应用点,并给出具体的技术方法。 最后,要确保回答结构清晰,分步骤说明,可能包括数据预处理、视觉分析、音频处理、多模态融合等部分,并提到相关模型和工具,帮助用户理解整个流程。同时,提醒可能需要的计算资源和现有工具库,比如FFmpeg、OpenCV、HuggingFace等,让用户有实现的路径。</think>以下为利用大模型分析视频文件的分步骤技术方案: 一、视频预处理阶段 1. 视频拆解 - 使用FFmpeg工具将视频分解为: $$ \text{视频流} \rightarrow \{帧序列\} \quad (fps=30) $$ $$ \text{音频流} \rightarrow \{wav文件\} \quad (采样率16kHz) $$ 2. 关键帧提取 - 采用自适应阈值法选取信息量最大的帧: $$ \Delta_{hist} = \|hist(f_t) - hist(f_{t-1})\|_2 > \theta $$ 二、视觉内容分析 1. 多模态模型处理 - 使用CLIP模型计算图文相似度: $$ S(f,c) = \text{cosine\_similarity}(E_v(f), E_t(c)) $$ - 应用VideoMAE进行时序建模: $$ \hat{y} = \text{Transformer}(f_{1:T}) $$ 2. 目标检测 - YOLOv8检测结果示例: ```python model = YOLO('yolov8x.pt') results = model(frame) # 输出格式: [x_min, y_min, x_max, y_max, confidence, class] ``` 三、音频处理 1. 语音识别 - Whisper模型处理流程: $$ P(w_{1:n}|x) = \prod_{i=1}^n P(w_i|w_{<i}, x) $$ 支持50+语言识别,词错误率(WER)低至3% 2. 声纹分析 - 使用ECAPA-TDNN提取说话人嵌入: $$ e = \text{Mean}([\text{Frame}_1, ..., \text{Frame}_n]) $$ 四、多模态融合 1. 时空对齐 - 建立时间轴映射关系: $$ \forall t \in [0,T], \exists (v_t, a_t, s_t) $$ 其中$v_t$为视觉特征,$a_t$为音频特征,$s_t$为字幕文本 2. 知识增强 - 结合知识图谱进行实体链接: $$ \text{EntityLink}(e) = \arg\max_{k \in KG} \text{Sim}(e, k) $$ 五、输出生成 1. 结构化数据示例 ```json { "summary": "会议场景,多人讨论项目进度", "tags": ["办公室", "白板", "图表", "商务会议"], "transcript": [ {"start": 12.5, "end": 15.2, "text": "我们需要在Q3前完成交付"}, {"start": 16.8, "end": 19.4, "text": "研发部门需要增加资源投入"} ], "metadata": { "duration": "00:23:17", "resolution": "1920x1080", "speakers": 3 } } ``` 技术挑战与解决方案: 1. 计算效率问题: - 采用自适应帧采样策略:$s(t) = \lfloor t/\Delta \rfloor,\ \Delta \propto \text{action\_score}(t)$ 2. 长视频处理: - 分块处理+滑动窗口注意力机制 $$ \text{Attention}(Q,K,V) = \text{Softmax}(\frac{QK^T}{\sqrt{d_k}})V $$ 典型应用场景: - 视频内容审核:识别违规内容准确率可达92.3% - 智能剪辑:自动生成highlight片段 - 教育视频分析:知识点抽取与关联 当前SOTA模型推荐: 1. 视觉:InternVideo(CVPR2023最佳论文) 2. 音频:MMS(支持1100+语言) 3. 多模态:Video-LLaMA(视频问答专用) 注:实际部署时建议采用分布式处理框架,视频处理耗时与视频长度近似线性关系: $$ T_{process} = \alpha L + \beta,\ \alpha \approx 0.7s/min (A100) $$
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值