From 2f5a269866ee85e2b86525d3c5b2f8b1a8ce3784 Mon Sep 17 00:00:00 2001 From: OpenClaw Agent Date: Mon, 9 Feb 2026 23:51:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(bilibili-analyzer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=AD=97=E5=B9=95=E5=8C=BA=E5=9F=9F=E8=A3=81=E5=89=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 --crop-ratio 参数,提取底部1/N区域(默认1/4) - 新增 --no-crop 参数,禁用裁剪提取完整帧 - 优化字幕识别效率,只处理字幕区域 --- skills/bilibili-analyzer/SKILL.md | 10 +++++- skills/bilibili-analyzer/scripts/prepare.cs | 36 ++++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/skills/bilibili-analyzer/SKILL.md b/skills/bilibili-analyzer/SKILL.md index 027a93f..1f76f9a 100644 --- a/skills/bilibili-analyzer/SKILL.md +++ b/skills/bilibili-analyzer/SKILL.md @@ -118,7 +118,7 @@ python3 -m venv .venv ### 使用方法 ```bash -# 基本用法 +# 基本用法(默认裁剪底部1/4,用于提取字幕) 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 --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 | | `--similarity` | 相似度阈值(0-1),超过此值的相邻帧会被去重 | 0.80 | | `--no-dedup` | 禁用相似帧去重 | false | +| `--crop-ratio` | 裁剪比例(提取底部1/N) | 4(底部1/4) | +| `--no-crop` | 禁用裁剪,提取完整帧 | false | | `--video-only` | 只下载视频,不提取帧 | false | | `--frames-only` | 只提取帧(需已有video.mp4) | false | diff --git a/skills/bilibili-analyzer/scripts/prepare.cs b/skills/bilibili-analyzer/scripts/prepare.cs index fcb70e7..c9a28af 100644 --- a/skills/bilibili-analyzer/scripts/prepare.cs +++ b/skills/bilibili-analyzer/scripts/prepare.cs @@ -27,6 +27,13 @@ if (!double.TryParse(fpsStr, NumberStyles.Float, CultureInfo.InvariantCulture, o Console.WriteLine($"[ERROR] Invalid fps value: {fpsStr}"); 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"; 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($"Similarity Threshold: {similarityThreshold:P0}"); Console.WriteLine($"Deduplication: {(noDedup ? "Disabled" : "Enabled")}"); +Console.WriteLine($"Crop: {(noCrop ? "Disabled" : $"Bottom 1/{cropRatio}")}"); Console.WriteLine(new string('=', 50)); // Download video @@ -71,7 +79,7 @@ if (!videoOnly) Environment.Exit(1); } - if (!await ExtractFramesAsync(videoPath, imagesDir, fps)) + if (!await ExtractFramesAsync(videoPath, imagesDir, fps, !noCrop, cropRatio)) { Environment.Exit(1); } @@ -237,9 +245,9 @@ HttpClient CreateHttpClient() return client; } -async Task ExtractFramesAsync(string videoPath, string outputDir, double fps) +async Task 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"); if (ffmpeg == null) @@ -258,10 +266,20 @@ async Task ExtractFramesAsync(string videoPath, string outputDir, double f { 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 { 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, RedirectStandardError = true, UseShellExecute = false, @@ -576,6 +594,8 @@ Options: --fps Frames per second (default: 1.0) --similarity Similarity threshold for deduplication (default: 0.80) --no-dedup Disable frame deduplication + --crop-ratio 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 --frames-only Only extract frames (requires existing video.mp4) -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"" --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"" --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: Consecutive frames with similarity >= threshold will be deduplicated.