feat(bilibili-analyzer): 支持字幕区域裁剪
- 新增 --crop-ratio 参数,提取底部1/N区域(默认1/4) - 新增 --no-crop 参数,禁用裁剪提取完整帧 - 优化字幕识别效率,只处理字幕区域
This commit is contained in:
@@ -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 |
|
||||
|
||||
|
||||
@@ -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<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");
|
||||
if (ffmpeg == null)
|
||||
@@ -258,10 +266,20 @@ async Task<bool> 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 <value> Frames per second (default: 1.0)
|
||||
--similarity <value> Similarity threshold for deduplication (default: 0.80)
|
||||
--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
|
||||
--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.
|
||||
|
||||
Reference in New Issue
Block a user