feat(bilibili-analyzer): 支持字幕区域裁剪

- 新增 --crop-ratio 参数,提取底部1/N区域(默认1/4)
- 新增 --no-crop 参数,禁用裁剪提取完整帧
- 优化字幕识别效率,只处理字幕区域
This commit is contained in:
OpenClaw Agent
2026-02-09 23:51:42 +08:00
parent 732dfb6549
commit 2f5a269866
2 changed files with 41 additions and 5 deletions
+9 -1
View File
@@ -118,7 +118,7 @@ python3 -m venv .venv
### 使用方法 ### 使用方法
```bash ```bash
# 基本用法 # 基本用法(默认裁剪底部1/4,用于提取字幕)
dotnet run scripts/prepare.cs "<视频URL>" -o <输出目录> dotnet run scripts/prepare.cs "<视频URL>" -o <输出目录>
# 示例 # 示例
@@ -126,6 +126,12 @@ dotnet run scripts/prepare.cs "https://www.bilibili.com/video/BV1xx411c7mD" -o .
# 长视频(降低帧率) # 长视频(降低帧率)
dotnet run scripts/prepare.cs "https://www.bilibili.com/video/BV1xx411c7mD" -o ./output --fps 0.5 dotnet run scripts/prepare.cs "https://www.bilibili.com/video/BV1xx411c7mD" -o ./output --fps 0.5
# 提取全帧(不裁剪)
dotnet run scripts/prepare.cs "https://www.bilibili.com/video/BV1xx411c7mD" -o ./output --no-crop
# 调整裁剪比例(底部1/2)
dotnet run scripts/prepare.cs "https://www.bilibili.com/video/BV1xx411c7mD" -o ./output --crop-ratio 2
``` ```
### 参数说明 ### 参数说明
@@ -137,6 +143,8 @@ dotnet run scripts/prepare.cs "https://www.bilibili.com/video/BV1xx411c7mD" -o .
| `--fps` | 每秒提取帧数 | 1.0 | | `--fps` | 每秒提取帧数 | 1.0 |
| `--similarity` | 相似度阈值(0-1),超过此值的相邻帧会被去重 | 0.80 | | `--similarity` | 相似度阈值(0-1),超过此值的相邻帧会被去重 | 0.80 |
| `--no-dedup` | 禁用相似帧去重 | false | | `--no-dedup` | 禁用相似帧去重 | false |
| `--crop-ratio` | 裁剪比例(提取底部1/N) | 4(底部1/4) |
| `--no-crop` | 禁用裁剪,提取完整帧 | false |
| `--video-only` | 只下载视频,不提取帧 | false | | `--video-only` | 只下载视频,不提取帧 | false |
| `--frames-only` | 只提取帧(需已有video.mp4) | false | | `--frames-only` | 只提取帧(需已有video.mp4) | false |
+32 -4
View File
@@ -27,6 +27,13 @@ if (!double.TryParse(fpsStr, NumberStyles.Float, CultureInfo.InvariantCulture, o
Console.WriteLine($"[ERROR] Invalid fps value: {fpsStr}"); Console.WriteLine($"[ERROR] Invalid fps value: {fpsStr}");
Environment.Exit(1); Environment.Exit(1);
} }
var cropRatioStr = GetArgValue(args, "--crop-ratio") ?? "4";
if (!int.TryParse(cropRatioStr, out var cropRatio) || cropRatio < 2 || cropRatio > 10)
{
Console.WriteLine($"[ERROR] Invalid crop-ratio value: {cropRatioStr} (must be 2-10)");
Environment.Exit(1);
}
var noCrop = args.Contains("--no-crop");
var similarityStr = GetArgValue(args, "--similarity") ?? "0.80"; var similarityStr = GetArgValue(args, "--similarity") ?? "0.80";
if (!double.TryParse(similarityStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var similarityThreshold)) if (!double.TryParse(similarityStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var similarityThreshold))
{ {
@@ -51,6 +58,7 @@ Console.WriteLine($"Output: {outputDir}");
Console.WriteLine($"FPS: {fps}"); Console.WriteLine($"FPS: {fps}");
Console.WriteLine($"Similarity Threshold: {similarityThreshold:P0}"); Console.WriteLine($"Similarity Threshold: {similarityThreshold:P0}");
Console.WriteLine($"Deduplication: {(noDedup ? "Disabled" : "Enabled")}"); Console.WriteLine($"Deduplication: {(noDedup ? "Disabled" : "Enabled")}");
Console.WriteLine($"Crop: {(noCrop ? "Disabled" : $"Bottom 1/{cropRatio}")}");
Console.WriteLine(new string('=', 50)); Console.WriteLine(new string('=', 50));
// Download video // Download video
@@ -71,7 +79,7 @@ if (!videoOnly)
Environment.Exit(1); Environment.Exit(1);
} }
if (!await ExtractFramesAsync(videoPath, imagesDir, fps)) if (!await ExtractFramesAsync(videoPath, imagesDir, fps, !noCrop, cropRatio))
{ {
Environment.Exit(1); Environment.Exit(1);
} }
@@ -237,9 +245,9 @@ HttpClient CreateHttpClient()
return client; return client;
} }
async Task<bool> ExtractFramesAsync(string videoPath, string outputDir, double fps) async Task<bool> ExtractFramesAsync(string videoPath, string outputDir, double fps, bool useCrop, int cropRatio)
{ {
Console.WriteLine($"[INFO] Extracting frames (fps={fps})"); Console.WriteLine($"[INFO] Extracting frames (fps={fps}, crop={(useCrop ? $"bottom 1/{cropRatio}" : "disabled")})");
var ffmpeg = FindExecutable("ffmpeg", "ffmpeg.exe"); var ffmpeg = FindExecutable("ffmpeg", "ffmpeg.exe");
if (ffmpeg == null) if (ffmpeg == null)
@@ -258,10 +266,20 @@ async Task<bool> ExtractFramesAsync(string videoPath, string outputDir, double f
{ {
Console.WriteLine($"[INFO] Running ffmpeg: {ffmpeg}"); Console.WriteLine($"[INFO] Running ffmpeg: {ffmpeg}");
// Build filter string
var filter = $"fps={fps.ToString(CultureInfo.InvariantCulture)}";
if (useCrop)
{
// Crop bottom portion using FFmpeg's crop filter
// crop=w=iw:h=ih/{cropRatio}:x=0:y=ih-h/ih-{cropRatio}
// This crops the bottom 1/cropRatio of the frame
filter = $"fps={fps.ToString(CultureInfo.InvariantCulture)},crop=iw:ih/{cropRatio}:0:ih-ih/{cropRatio}";
}
var psi = new ProcessStartInfo var psi = new ProcessStartInfo
{ {
FileName = ffmpeg, FileName = ffmpeg,
Arguments = $"-i \"{videoPath}\" -vf \"fps={fps.ToString(CultureInfo.InvariantCulture)}\" -q:v 2 -y \"{outputPattern}\"", Arguments = $"-i \"{videoPath}\" -vf \"{filter}\" -q:v 2 -y \"{outputPattern}\"",
RedirectStandardOutput = true, RedirectStandardOutput = true,
RedirectStandardError = true, RedirectStandardError = true,
UseShellExecute = false, UseShellExecute = false,
@@ -576,6 +594,8 @@ Options:
--fps <value> Frames per second (default: 1.0) --fps <value> Frames per second (default: 1.0)
--similarity <value> Similarity threshold for deduplication (default: 0.80) --similarity <value> Similarity threshold for deduplication (default: 0.80)
--no-dedup Disable frame deduplication --no-dedup Disable frame deduplication
--crop-ratio <value> Crop to bottom 1/N of frame (default: 4, N=4 means bottom 1/4)
--no-crop Disable cropping (extract full frame)
--video-only Only download video, skip frame extraction --video-only Only download video, skip frame extraction
--frames-only Only extract frames (requires existing video.mp4) --frames-only Only extract frames (requires existing video.mp4)
-h, --help Show this help -h, --help Show this help
@@ -586,6 +606,14 @@ Examples:
dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" -o ./output dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" -o ./output
dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" --similarity 0.85 dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" --similarity 0.85
dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" --no-dedup dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" --no-dedup
dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" --crop-ratio 4
dotnet run prepare.cs ""https://www.bilibili.com/video/BV1xx411c7mD"" --no-crop
Cropping (for subtitle extraction):
By default, only the bottom 1/4 of the frame is extracted (--crop-ratio 4)
This is useful for capturing subtitles without the main video content
Use --no-crop to extract the full frame
Use --crop-ratio 2 for bottom half, --crop-ratio 8 for bottom 1/8, etc.
Deduplication: Deduplication:
Consecutive frames with similarity >= threshold will be deduplicated. Consecutive frames with similarity >= threshold will be deduplicated.