feat: Add comprehensive Topaz Video AI filter combinations and model management
This commit is contained in:
325
cargos/tvai/examples/filter_combinations_demo.rs
Normal file
325
cargos/tvai/examples/filter_combinations_demo.rs
Normal file
@@ -0,0 +1,325 @@
|
||||
//! Topaz Video AI 滤镜组合演示
|
||||
//!
|
||||
//! 展示如何使用新的滤镜组合库进行各种视频和图片处理
|
||||
|
||||
use std::path::Path;
|
||||
use tvai::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("🎬 Topaz Video AI 滤镜组合演示");
|
||||
println!("================================\n");
|
||||
|
||||
// 检查 Topaz 安装
|
||||
if let Some(topaz_path) = detect_topaz_installation() {
|
||||
println!("✅ 找到 Topaz Video AI: {}", topaz_path.display());
|
||||
} else {
|
||||
println!("❌ 未找到 Topaz Video AI 安装");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 检查测试文件
|
||||
let demo_video = Path::new("target/demo.mp4");
|
||||
let demo_image = Path::new("target/demo.jpg");
|
||||
|
||||
if !demo_video.exists() {
|
||||
println!("❌ 测试视频文件不存在: {}", demo_video.display());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !demo_image.exists() {
|
||||
println!("❌ 测试图片文件不存在: {}", demo_image.display());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("✅ 测试文件检查完成\n");
|
||||
|
||||
// 创建输出目录
|
||||
let output_dir = Path::new("target/filter_demo_output");
|
||||
std::fs::create_dir_all(output_dir)?;
|
||||
|
||||
// 演示各种滤镜组合
|
||||
demo_basic_usage(demo_video, demo_image, output_dir).await?;
|
||||
demo_builder_pattern(demo_video, output_dir).await?;
|
||||
demo_presets(demo_video, output_dir).await?;
|
||||
demo_quick_functions(demo_video, output_dir).await?;
|
||||
demo_advanced_combinations(demo_video, output_dir).await?;
|
||||
|
||||
println!("\n🎉 所有演示完成!");
|
||||
println!("输出文件位于: {}", output_dir.display());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示基本用法
|
||||
async fn demo_basic_usage(
|
||||
demo_video: &Path,
|
||||
demo_image: &Path,
|
||||
output_dir: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("📋 1. 基本用法演示");
|
||||
println!("------------------");
|
||||
|
||||
// 创建处理器
|
||||
let topaz_path = detect_topaz_installation().unwrap();
|
||||
let config = TvaiConfig::builder()
|
||||
.topaz_path(topaz_path)
|
||||
.use_gpu(true)
|
||||
.build()?;
|
||||
|
||||
let processor = TvaiProcessor::new(config)?;
|
||||
let mut filter_processor = FilterProcessor::new(processor);
|
||||
|
||||
// 1. 视频超分辨率放大
|
||||
println!("🔍 视频超分辨率放大 (2x)...");
|
||||
let upscale_combination = FilterCombination::Upscale {
|
||||
model: UpscaleModel::Iris3,
|
||||
scale: 2.0,
|
||||
quality: QualityLevel::Balanced,
|
||||
};
|
||||
|
||||
let progress_callback = create_progress_callback("视频放大");
|
||||
let result = filter_processor.apply_to_video(
|
||||
demo_video,
|
||||
&output_dir.join("basic_upscale_2x.mp4"),
|
||||
upscale_combination,
|
||||
ProcessOptions::default(),
|
||||
Some(&progress_callback),
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
// 2. 图片超分辨率放大
|
||||
println!("\n🖼️ 图片超分辨率放大 (2x)...");
|
||||
let image_combination = FilterCombination::Upscale {
|
||||
model: UpscaleModel::Iris3,
|
||||
scale: 2.0,
|
||||
quality: QualityLevel::High,
|
||||
};
|
||||
|
||||
let image_options = ProcessOptions {
|
||||
output_format: Some("png".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let result = filter_processor.apply_to_image(
|
||||
demo_image,
|
||||
&output_dir.join("basic_upscale_image_2x.png"),
|
||||
image_combination,
|
||||
image_options,
|
||||
Some(&progress_callback),
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示构建器模式
|
||||
async fn demo_builder_pattern(
|
||||
demo_video: &Path,
|
||||
output_dir: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("\n📋 2. 构建器模式演示");
|
||||
println!("--------------------");
|
||||
|
||||
let topaz_path = detect_topaz_installation().unwrap();
|
||||
let config = TvaiConfig::builder()
|
||||
.topaz_path(topaz_path)
|
||||
.use_gpu(true)
|
||||
.build()?;
|
||||
|
||||
let processor = TvaiProcessor::new(config)?;
|
||||
let mut filter_processor = FilterProcessor::new(processor);
|
||||
|
||||
// 使用构建器创建复杂配置
|
||||
println!("🔧 使用构建器创建高质量放大配置...");
|
||||
let (combination, options) = FilterCombinationBuilder::new()
|
||||
.upscale(UpscaleModel::Ahq12, 2.0)
|
||||
.quality(QualityLevel::High)
|
||||
.output_format("mp4".to_string())
|
||||
.output_resolution(1920, 1080)
|
||||
.vram_limit(0.8)
|
||||
.build()?;
|
||||
|
||||
let progress_callback = create_progress_callback("构建器模式");
|
||||
let result = filter_processor.apply_to_video(
|
||||
demo_video,
|
||||
&output_dir.join("builder_hq_upscale.mp4"),
|
||||
combination,
|
||||
options,
|
||||
Some(&progress_callback),
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
// 使用快速构建器
|
||||
println!("\n⚡ 使用快速构建器...");
|
||||
let (combination, options) = quick_builders::social_media()
|
||||
.quality(QualityLevel::Balanced)
|
||||
.build()?;
|
||||
|
||||
let result = filter_processor.apply_to_video(
|
||||
demo_video,
|
||||
&output_dir.join("builder_social_media.mp4"),
|
||||
combination,
|
||||
options,
|
||||
Some(&progress_callback),
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示预设功能
|
||||
async fn demo_presets(
|
||||
demo_video: &Path,
|
||||
output_dir: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("\n📋 3. 预设功能演示");
|
||||
println!("------------------");
|
||||
|
||||
let topaz_path = detect_topaz_installation().unwrap();
|
||||
let config = TvaiConfig::builder()
|
||||
.topaz_path(topaz_path)
|
||||
.use_gpu(true)
|
||||
.build()?;
|
||||
|
||||
let processor = TvaiProcessor::new(config)?;
|
||||
let mut filter_processor = FilterProcessor::new(processor);
|
||||
|
||||
// 使用内置预设
|
||||
println!("🎮 游戏录像预设...");
|
||||
let preset = PresetType::Gaming;
|
||||
let combination = preset.get_filter_combination();
|
||||
let options = preset.get_process_options();
|
||||
|
||||
let progress_callback = create_progress_callback("游戏预设");
|
||||
let result = filter_processor.apply_to_video(
|
||||
demo_video,
|
||||
&output_dir.join("preset_gaming.mp4"),
|
||||
combination,
|
||||
options,
|
||||
Some(&progress_callback),
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
// 创建自定义预设
|
||||
println!("\n🛠️ 创建自定义预设...");
|
||||
let custom_preset = CustomPreset::builder("我的自定义预设".to_string())
|
||||
.with_combination(FilterCombination::RestoreOldVideo {
|
||||
upscale_factor: 2.5,
|
||||
denoise_level: 0.4,
|
||||
quality: QualityLevel::Maximum,
|
||||
})
|
||||
.with_options(ProcessOptions {
|
||||
output_format: Some("mov".to_string()),
|
||||
keep_audio: true,
|
||||
vram_limit: 1.0,
|
||||
..Default::default()
|
||||
})
|
||||
.with_description("用于修复老电影的自定义预设".to_string())
|
||||
.build()?;
|
||||
|
||||
// 保存预设
|
||||
let preset_file = output_dir.join("custom_preset.json");
|
||||
custom_preset.save_to_file(&preset_file)?;
|
||||
println!("💾 预设已保存到: {}", preset_file.display());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示快速函数
|
||||
async fn demo_quick_functions(
|
||||
demo_video: &Path,
|
||||
output_dir: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("\n📋 4. 快速函数演示");
|
||||
println!("------------------");
|
||||
|
||||
// 快速视频放大
|
||||
println!("⚡ 快速视频放大...");
|
||||
let result = filters::quick::upscale_video(
|
||||
demo_video,
|
||||
&output_dir.join("quick_upscale.mp4"),
|
||||
2.0,
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
// 快速视频稳定化
|
||||
println!("\n🎯 快速视频稳定化...");
|
||||
let result = filters::quick::stabilize_video(
|
||||
demo_video,
|
||||
&output_dir.join("quick_stabilize.mp4"),
|
||||
1.0,
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示高级组合
|
||||
async fn demo_advanced_combinations(
|
||||
demo_video: &Path,
|
||||
output_dir: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("\n📋 5. 高级组合演示");
|
||||
println!("------------------");
|
||||
|
||||
let topaz_path = detect_topaz_installation().unwrap();
|
||||
let config = TvaiConfig::builder()
|
||||
.topaz_path(topaz_path)
|
||||
.use_gpu(true)
|
||||
.build()?;
|
||||
|
||||
let processor = TvaiProcessor::new(config)?;
|
||||
let mut filter_processor = FilterProcessor::new(processor);
|
||||
|
||||
// 完整增强 (放大 + 稳定化)
|
||||
println!("🚀 完整增强 (放大 + 稳定化)...");
|
||||
let combination = FilterCombination::FullEnhance {
|
||||
upscale_factor: 1.5,
|
||||
stabilize: true,
|
||||
quality: QualityLevel::High,
|
||||
};
|
||||
|
||||
let options = ProcessOptions {
|
||||
output_format: Some("mp4".to_string()),
|
||||
vram_limit: 1.0,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let progress_callback = create_progress_callback("完整增强");
|
||||
let result = filter_processor.apply_to_video(
|
||||
demo_video,
|
||||
&output_dir.join("advanced_full_enhance.mp4"),
|
||||
combination,
|
||||
options,
|
||||
Some(&progress_callback),
|
||||
).await?;
|
||||
|
||||
println!("✅ 完成!处理时间: {:?}", result.processing_time);
|
||||
|
||||
// 智能推荐
|
||||
println!("\n🧠 智能推荐组合...");
|
||||
let recommended = filter_processor.get_recommended_combination(demo_video).await?;
|
||||
println!("推荐的组合: {:?}", recommended);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 创建进度回调
|
||||
fn create_progress_callback(operation_name: &str) -> ProgressCallback {
|
||||
let name = operation_name.to_string();
|
||||
Box::new(move |progress| {
|
||||
let percentage = (progress * 100.0) as u32;
|
||||
print!("\r{}: {}%", name, percentage);
|
||||
if progress >= 1.0 {
|
||||
println!();
|
||||
}
|
||||
})
|
||||
}
|
||||
218
cargos/tvai/examples/model_management_demo.rs
Normal file
218
cargos/tvai/examples/model_management_demo.rs
Normal file
@@ -0,0 +1,218 @@
|
||||
//! Topaz Video AI 模型管理演示
|
||||
//!
|
||||
//! 展示如何使用模型管理器检查、下载和管理 AI 模型
|
||||
|
||||
use std::path::Path;
|
||||
use tvai::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("🧠 Topaz Video AI 模型管理演示");
|
||||
println!("==============================\n");
|
||||
|
||||
// 检查 Topaz 安装
|
||||
let topaz_path = match detect_topaz_installation() {
|
||||
Some(path) => {
|
||||
println!("✅ 找到 Topaz Video AI: {}", path.display());
|
||||
path
|
||||
}
|
||||
None => {
|
||||
println!("❌ 未找到 Topaz Video AI 安装");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 创建模型管理器
|
||||
let model_manager = match ModelManager::new(&topaz_path) {
|
||||
Ok(manager) => {
|
||||
println!("✅ 模型管理器初始化成功");
|
||||
manager
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ 模型管理器初始化失败: {}", e);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// 演示各种功能
|
||||
demo_model_status(&model_manager).await?;
|
||||
demo_model_recommendations(&model_manager).await?;
|
||||
demo_download_guide(&model_manager).await?;
|
||||
demo_model_testing(&model_manager).await?;
|
||||
|
||||
println!("\n🎉 模型管理演示完成!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示模型状态检查
|
||||
async fn demo_model_status(model_manager: &ModelManager) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("📊 1. 模型状态检查");
|
||||
println!("------------------");
|
||||
|
||||
// 获取所有模型
|
||||
let all_models = model_manager.get_all_models()?;
|
||||
println!("总模型数量: {}", all_models.len());
|
||||
|
||||
// 统计各类型模型
|
||||
let upscale_count = all_models.iter().filter(|m| m.model_type == ModelType::Upscale).count();
|
||||
let interpolation_count = all_models.iter().filter(|m| m.model_type == ModelType::Interpolation).count();
|
||||
let other_count = all_models.iter().filter(|m| m.model_type == ModelType::Other).count();
|
||||
|
||||
println!(" 🔍 超分辨率模型: {} 个", upscale_count);
|
||||
println!(" 🎬 帧插值模型: {} 个", interpolation_count);
|
||||
println!(" 🔧 其他模型: {} 个", other_count);
|
||||
|
||||
// 检查下载状态
|
||||
let downloaded_models = model_manager.get_downloaded_models()?;
|
||||
let missing_models = model_manager.get_missing_models()?;
|
||||
|
||||
println!("\n📥 下载状态:");
|
||||
println!(" ✅ 已下载: {} 个模型", downloaded_models.len());
|
||||
println!(" ❌ 缺失: {} 个模型", missing_models.len());
|
||||
|
||||
if !downloaded_models.is_empty() {
|
||||
println!("\n✅ 已下载的模型:");
|
||||
for model_name in &downloaded_models {
|
||||
if let Some(model) = all_models.iter().find(|m| m.short_name == *model_name) {
|
||||
println!(" {} - {}",
|
||||
model.short_name,
|
||||
model.display_name.as_deref().unwrap_or("N/A"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !missing_models.is_empty() {
|
||||
println!("\n❌ 缺失的模型 (前10个):");
|
||||
for model in missing_models.iter().take(10) {
|
||||
println!(" {} - {}",
|
||||
model.short_name,
|
||||
model.display_name.as_deref().unwrap_or("N/A"));
|
||||
}
|
||||
if missing_models.len() > 10 {
|
||||
println!(" ... 还有 {} 个模型", missing_models.len() - 10);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示模型推荐
|
||||
async fn demo_model_recommendations(model_manager: &ModelManager) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("\n💡 2. 模型推荐");
|
||||
println!("-------------");
|
||||
|
||||
let use_cases = vec![
|
||||
("general", "通用处理"),
|
||||
("high_quality", "高质量处理"),
|
||||
("fast", "快速处理"),
|
||||
("gaming", "游戏内容"),
|
||||
("old_video", "老视频修复"),
|
||||
("portrait", "人像视频"),
|
||||
];
|
||||
|
||||
for (use_case, description) in use_cases {
|
||||
let recommended = model_manager.get_recommended_models(use_case)?;
|
||||
println!("🎯 {} ({}):", description, use_case);
|
||||
|
||||
if recommended.is_empty() {
|
||||
println!(" (无推荐模型)");
|
||||
} else {
|
||||
for model_name in recommended {
|
||||
let is_downloaded = model_manager.is_model_downloaded(&model_name)?;
|
||||
let status = if is_downloaded { "✅" } else { "❌" };
|
||||
println!(" {} {}", status, model_name);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示下载指南生成
|
||||
async fn demo_download_guide(model_manager: &ModelManager) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("📋 3. 生成下载指南");
|
||||
println!("------------------");
|
||||
|
||||
let guide_path = Path::new("model_download_guide_demo.md");
|
||||
|
||||
match model_manager.generate_download_guide(guide_path) {
|
||||
Ok(()) => {
|
||||
println!("✅ 下载指南已生成: {}", guide_path.display());
|
||||
|
||||
// 显示指南的前几行
|
||||
if let Ok(content) = std::fs::read_to_string(guide_path) {
|
||||
let lines: Vec<&str> = content.lines().take(15).collect();
|
||||
println!("\n📄 指南预览:");
|
||||
for line in lines {
|
||||
println!(" {}", line);
|
||||
}
|
||||
if content.lines().count() > 15 {
|
||||
println!(" ... (更多内容请查看文件)");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ 生成指南失败: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 演示模型测试
|
||||
async fn demo_model_testing(model_manager: &ModelManager) -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("\n🧪 4. 模型测试");
|
||||
println!("-------------");
|
||||
|
||||
let test_video = Path::new("target/demo.mp4");
|
||||
|
||||
if !test_video.exists() {
|
||||
println!("❌ 测试视频不存在: {}", test_video.display());
|
||||
println!("💡 请确保测试视频文件存在以进行模型测试");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("✅ 找到测试视频: {}", test_video.display());
|
||||
|
||||
// 获取一些常用模型进行测试
|
||||
let test_models = vec!["iris", "amq", "prob", "chr"];
|
||||
|
||||
println!("\n🔍 测试常用模型可用性:");
|
||||
|
||||
for model_name in test_models {
|
||||
print!(" 测试 {} ... ", model_name);
|
||||
|
||||
match model_manager.attempt_model_download(model_name, test_video) {
|
||||
Ok(true) => {
|
||||
println!("✅ 可用或已触发下载");
|
||||
}
|
||||
Ok(false) => {
|
||||
println!("❌ 模型不可用");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ 测试失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("\n💡 提示:");
|
||||
println!(" - 如果模型显示'不可用',需要先在 Topaz 应用中下载");
|
||||
println!(" - 某些模型可能需要特定的输入格式才能正确加载");
|
||||
println!(" - 建议使用生成的下载指南进行手动下载");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 创建进度回调
|
||||
fn create_progress_callback(operation_name: &str) -> ProgressCallback {
|
||||
let name = operation_name.to_string();
|
||||
Box::new(move |progress| {
|
||||
let percentage = (progress * 100.0) as u32;
|
||||
print!("\r{}: {}%", name, percentage);
|
||||
if progress >= 1.0 {
|
||||
println!();
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user