Python自动化视频混剪工具开发:从素材搜索到合成全流程
1. 项目背景与需求分析在短视频内容创作和自媒体运营中影视素材的剪辑处理是一个高频且耗时的环节。传统剪辑流程需要手动搜索素材、下载视频文件、导入剪辑软件、进行剪切拼接整个过程繁琐且效率低下。特别是对于需要批量处理多个素材的混剪任务手动操作不仅耗时耗力还容易因重复劳动导致错误。基于这样的痛点我们开发了一个自动化影视素材混剪CLI工具。这个工具的核心目标是实现一句话找素材、下载、合成的自动化流程让内容创作者能够通过简单的命令行指令快速完成从素材搜索到最终视频合成的全过程。无论是短视频创作者、自媒体运营人员还是需要制作教学视频的技术人员都可以通过这个工具大幅提升工作效率。从技术层面来看这个项目涉及多个关键技术点网络爬虫技术用于素材搜索、视频下载技术、文件处理、以及最核心的视频合成算法。我们需要考虑不同视频格式的兼容性、下载速度优化、合成质量保证等实际问题。同时作为命令行工具还需要设计清晰的参数接口和友好的用户交互体验。2. 技术选型与环境准备2.1 核心技术与工具选择在技术选型方面我们主要基于Python生态进行开发主要考虑因素包括Python拥有丰富的视频处理库和网络请求库跨平台兼容性好可以在Windows、macOS、Linux系统上运行社区活跃遇到问题容易找到解决方案核心依赖库包括requests用于网络请求和视频下载BeautifulSoup网页解析用于素材搜索moviepy视频处理的核心库支持多种格式argparse命令行参数解析os、sys系统操作相关功能2.2 开发环境配置首先需要确保Python环境正确安装。推荐使用Python 3.8及以上版本可以通过以下命令检查当前Python版本python --version # 或者 python3 --version如果系统中没有安装Python需要先到Python官网下载安装包进行安装。对于Windows用户建议勾选Add Python to PATH选项以便在命令行中直接使用python命令。接下来创建项目目录并安装必要的依赖库# 创建项目目录 mkdir video-mixer-cli cd video-mixer-cli # 创建虚拟环境推荐 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux/macOS: source venv/bin/activate # 安装依赖库 pip install requests beautifulsoup4 moviepy argparse2.3 项目结构设计合理的项目结构是保证代码可维护性的基础。我们设计如下的目录结构video-mixer-cli/ ├── src/ │ ├── __init__.py │ ├── downloader.py # 视频下载模块 │ ├── searcher.py # 素材搜索模块 │ ├── mixer.py # 视频合成模块 │ └── utils.py # 工具函数 ├── tests/ # 测试文件 ├── output/ # 输出目录 ├── temp/ # 临时文件目录 ├── requirements.txt # 依赖列表 └── main.py # 主入口文件3. 核心模块设计与实现3.1 素材搜索模块搜索模块负责根据用户输入的关键词从公开视频资源网站查找相关素材。我们以Pexels视频库为例实现一个简单的搜索功能# src/searcher.py import requests from bs4 import BeautifulSoup import json import re class VideoSearcher: def __init__(self): self.headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } def search_pexels(self, keyword, max_results10): 从Pexels搜索视频素材 search_url fhttps://www.pexels.com/search/videos/{keyword.replace( , %20)} try: response requests.get(search_url, headersself.headers) response.raise_for_status() soup BeautifulSoup(response.text, html.parser) video_elements soup.find_all(video, class_video-item__video) results [] for video in video_elements[:max_results]: source video.find(source) if source and source.get(src): video_data { url: source[src], title: video.get(title, Unknown), duration: self._parse_duration(video) } results.append(video_data) return results except Exception as e: print(f搜索失败: {e}) return [] def _parse_duration(self, video_element): 解析视频时长 # 实现时长解析逻辑 return 00:30 # 默认返回30秒3.2 视频下载模块下载模块负责将搜索到的视频素材下载到本地临时目录# src/downloader.py import requests import os from urllib.parse import urlparse import time class VideoDownloader: def __init__(self, temp_dirtemp): self.temp_dir temp_dir os.makedirs(temp_dir, exist_okTrue) def download_video(self, video_url, filenameNone): 下载视频文件 if not filename: # 从URL提取文件名 parsed_url urlparse(video_url) filename os.path.basename(parsed_url.path) or fvideo_{int(time.time())}.mp4 filepath os.path.join(self.temp_dir, filename) try: response requests.get(video_url, streamTrue) response.raise_for_status() with open(filepath, wb) as f: for chunk in response.iter_content(chunk_size8192): if chunk: f.write(chunk) print(f视频下载完成: {filepath}) return filepath except Exception as e: print(f下载失败: {e}) return None def cleanup_temp_files(self): 清理临时文件 for file in os.listdir(self.temp_dir): file_path os.path.join(self.temp_dir, file) try: if os.path.isfile(file_path): os.unlink(file_path) except Exception as e: print(f清理文件失败 {file_path}: {e})3.3 视频合成模块合成模块是核心功能负责将多个视频素材按照指定规则进行混剪# src/mixer.py from moviepy.editor import VideoFileClip, concatenate_videoclips import os class VideoMixer: def __init__(self, output_diroutput): self.output_dir output_dir os.makedirs(output_dir, exist_okTrue) def mix_videos(self, video_paths, output_namemixed_video.mp4, transition_duration1, max_duration60): 混合多个视频文件 if not video_paths: raise ValueError(没有可用的视频文件) clips [] total_duration 0 for path in video_paths: if not os.path.exists(path): print(f视频文件不存在: {path}) continue try: clip VideoFileClip(path) # 限制单个视频时长 if clip.duration 15: # 超过15秒的视频进行裁剪 clip clip.subclip(0, 15) # 检查总时长限制 if total_duration clip.duration max_duration: # 裁剪最后一个视频以适应总时长 remaining_time max_duration - total_duration if remaining_time 5: # 至少保留5秒 clip clip.subclip(0, remaining_time) else: break clips.append(clip) total_duration clip.duration if total_duration max_duration: break except Exception as e: print(f处理视频失败 {path}: {e}) continue if not clips: raise ValueError(没有有效的视频片段可供合成) # 拼接视频 final_clip concatenate_videoclips(clips, methodcompose) # 设置输出路径 output_path os.path.join(self.output_dir, output_name) # 导出视频 final_clip.write_videofile( output_path, codeclibx264, audio_codecaac, temp_audiofiletemp-audio.m4a, remove_tempTrue ) # 关闭所有剪辑以释放内存 for clip in clips: clip.close() final_clip.close() print(f视频合成完成: {output_path}) return output_path4. 命令行接口设计4.1 参数解析与验证命令行接口是用户与工具交互的主要方式需要设计清晰易用的参数系统# main.py import argparse import sys import os from src.searcher import VideoSearcher from src.downloader import VideoDownloader from src.mixer import VideoMixer def setup_argparse(): 设置命令行参数解析 parser argparse.ArgumentParser( description自动化影视素材混剪CLI工具, formatter_classargparse.RawDescriptionHelpFormatter, epilog 示例用法: python main.py -k 城市夜景 -o my_video.mp4 python main.py -k 自然风景 -d 120 -n 5 ) parser.add_argument(-k, --keyword, requiredTrue, help搜索关键词如城市夜景) parser.add_argument(-o, --output, defaultmixed_video.mp4, help输出文件名默认: mixed_video.mp4) parser.add_argument(-n, --number, typeint, default3, help使用的视频数量默认: 3) parser.add_argument(-d, --duration, typeint, default60, help输出视频时长(秒)默认: 60) parser.add_argument(--keep-temp, actionstore_true, help保留临时文件) return parser def validate_arguments(args): 验证参数有效性 if args.number 0: raise ValueError(视频数量必须大于0) if args.duration 0: raise ValueError(视频时长必须大于0) if not args.keyword.strip(): raise ValueError(搜索关键词不能为空) # 验证输出文件格式 if not args.output.lower().endswith((.mp4, .avi, .mov)): print(警告: 推荐使用.mp4格式作为输出文件) def main(): 主函数 parser setup_argparse() args parser.parse_args() try: validate_arguments(args) print(f开始处理: 关键词{args.keyword}, 时长{args.duration}秒) # 初始化各模块 searcher VideoSearcher() downloader VideoDownloader() mixer VideoMixer() # 搜索素材 print(搜索视频素材中...) video_results searcher.search_pexels(args.keyword, args.number * 2) if not video_results: print(未找到相关视频素材) return 1 # 下载视频 print(下载视频文件中...) downloaded_paths [] for i, video in enumerate(video_results[:args.number]): print(f下载第 {i1} 个视频...) path downloader.download_video(video[url], ftemp_{i}.mp4) if path: downloaded_paths.append(path) if not downloaded_paths: print(视频下载失败) return 1 # 合成视频 print(合成视频中...) output_path mixer.mix_videos( downloaded_paths, args.output, max_durationargs.duration ) # 清理临时文件 if not args.keep_temp: downloader.cleanup_temp_files() print(f处理完成! 输出文件: {output_path}) return 0 except Exception as e: print(f处理失败: {e}) return 1 if __name__ __main__: sys.exit(main())4.2 用户交互优化为了提升用户体验我们添加进度显示和状态反馈# src/utils.py import sys import time class ProgressTracker: def __init__(self, total_steps, description处理中): self.total_steps total_steps self.current_step 0 self.description description def update(self, step_description): self.current_step 1 progress (self.current_step / self.total_steps) * 100 sys.stdout.write(f\r{self.description}: [{ # * int(progress/5) }{ * (20-int(progress/5)) }] {progress:.1f}% {step_description}) sys.stdout.flush() if self.current_step self.total_steps: print() # 换行 def format_duration(seconds): 格式化时长显示 minutes int(seconds // 60) seconds int(seconds % 60) return f{minutes:02d}:{seconds:02d}5. 完整使用示例与测试5.1 基本使用流程让我们通过一个完整示例来演示工具的使用方法# 激活虚拟环境后运行 python main.py -k 海滩日落 -o beach_sunset.mp4 -n 4 -d 90这个命令会执行以下流程搜索与海滩日落相关的视频素材下载前4个符合条件的视频将这些视频合成为一个90秒的混剪视频输出文件保存为beach_sunset.mp45.2 高级功能示例工具还支持一些高级用法# 创建更长的视频使用更多素材 python main.py -k 城市延时摄影 -o city_timelapse.mp4 -n 8 -d 180 # 保留临时文件用于调试 python main.py -k 自然风光 -o nature.mp4 --keep-temp5.3 测试验证创建测试脚本来验证核心功能# tests/test_basic.py import unittest import os import sys sys.path.append(src) from downloader import VideoDownloader from mixer import VideoMixer class TestVideoMixer(unittest.TestCase): def setUp(self): self.downloader VideoDownloader(test_temp) self.mixer VideoMixer(test_output) def test_video_mixing(self): 测试视频合成功能 # 创建测试视频文件这里需要实际存在的视频文件 test_videos [] # 实际测试时需要替换为真实的小视频文件路径 if test_videos: output_path self.mixer.mix_videos(test_videos, test_output.mp4, max_duration30) self.assertTrue(os.path.exists(output_path)) def tearDown(self): # 清理测试文件 import shutil if os.path.exists(test_temp): shutil.rmtree(test_temp) if os.path.exists(test_output): shutil.rmtree(test_output) if __name__ __main__: unittest.main()6. 常见问题与解决方案6.1 下载相关问题问题1视频下载速度慢或失败原因网络连接问题或目标网站限制解决方案添加重试机制和超时设置# 在downloader.py中改进下载函数 def download_video_with_retry(self, video_url, filenameNone, max_retries3): for attempt in range(max_retries): try: return self.download_video(video_url, filename) except Exception as e: if attempt max_retries - 1: raise e time.sleep(2) # 等待2秒后重试问题2视频格式不支持原因某些网站使用非常见视频格式解决方案添加格式检测和转换功能6.2 合成相关问题问题1合成后的视频音画不同步原因原始视频的帧率或编码不一致解决方案统一输出参数添加音频同步处理# 在mixer.py中改进合成函数 def mix_videos_with_audio_sync(self, video_paths, output_name, max_duration60): # 确保所有视频使用相同的音频处理参数 clips [] for path in video_paths: clip VideoFileClip(path) # 统一音频处理 if clip.audio is not None: clip clip.set_audio(clip.audio) clips.append(clip) # 其余合成逻辑不变问题2合成过程内存占用过高原因同时处理多个高分辨率视频解决方案添加内存监控和分块处理机制6.3 性能优化建议并行下载使用多线程同时下载多个视频缓存机制对已下载的素材建立本地缓存分辨率控制根据输出需求自动调整素材分辨率进度保存支持断点续传功能7. 扩展功能与进阶用法7.1 自定义合成规则高级用户可以通过修改合成模块来实现更复杂的混剪逻辑# 高级混剪示例添加转场效果 from moviepy.editor import VideoFileClip, CompositeVideoClip def advanced_mix(video_paths, output_name): clips [VideoFileClip(path) for path in video_paths] # 添加淡入淡出效果 processed_clips [] for i, clip in enumerate(clips): if i 0: # 第一个剪辑不添加淡入 clip clip.crossfadein(1) if i len(clips) - 1: # 最后一个剪辑不添加淡出 clip clip.crossfadeout(1) processed_clips.append(clip) # 合成处理后的剪辑 final_clip concatenate_videoclips(processed_clips, padding-1) # 重叠1秒 final_clip.write_videofile(output_name)7.2 批量处理功能对于需要处理大量关键词的用户可以添加批量处理模式# 批量处理示例 def batch_process(keywords_file, output_dir): with open(keywords_file, r, encodingutf-8) as f: keywords [line.strip() for line in f if line.strip()] for keyword in keywords: output_name f{keyword.replace( , _)}.mp4 # 调用主处理逻辑 process_keyword(keyword, os.path.join(output_dir, output_name))7.3 配置文件支持添加配置文件支持让用户可以保存常用设置# config_loader.py import json import os class ConfigLoader: def __init__(self, config_fileconfig.json): self.config_file config_file self.default_config { default_duration: 60, default_video_count: 3, output_quality: high, temp_dir: temp, output_dir: output } def load_config(self): if os.path.exists(self.config_file): with open(self.config_file, r) as f: user_config json.load(f) return {**self.default_config, **user_config} return self.default_config def save_config(self, config): with open(self.config_file, w) as f: json.dump(config, f, indent2)8. 部署与生产环境建议8.1 环境依赖管理确保生产环境的稳定性需要严格管理依赖版本# requirements.txt requests2.28.1 beautifulsoup44.11.1 moviepy1.0.3 argparse1.4.08.2 错误处理与日志记录在生产环境中完善的错误处理和日志记录至关重要# src/logger.py import logging import os from datetime import datetime def setup_logger(): 设置日志系统 log_dir logs os.makedirs(log_dir, exist_okTrue) log_file os.path.join(log_dir, fvideo_mixer_{datetime.now().strftime(%Y%m%d)}.log) logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(log_file), logging.StreamHandler() ] ) return logging.getLogger(__name__)8.3 性能监控添加性能监控帮助优化资源使用# src/monitor.py import time import psutil import os class PerformanceMonitor: def __init__(self): self.process psutil.Process(os.getpid()) self.start_time time.time() def get_memory_usage(self): 获取内存使用情况 return self.process.memory_info().rss / 1024 / 1024 # MB def get_cpu_usage(self): 获取CPU使用率 return self.process.cpu_percent() def get_elapsed_time(self): 获取运行时间 return time.time() - self.start_time这个自动化影视素材混剪CLI工具虽然基础但提供了一个完整的自动化视频处理流程框架。在实际使用中可以根据具体需求继续扩展功能比如支持更多视频源、添加高级特效、优化合成算法等。工具的核心价值在于将繁琐的手动操作自动化让创作者能够更专注于内容创作本身。

相关新闻

TMS320F2802x SCI与I2C寄存器深度配置:从FIFO优化到实战调试

TMS320F2802x SCI与I2C寄存器深度配置:从FIFO优化到实战调试

1. 项目概述与核心价值在嵌入式系统开发,尤其是基于TI C2000系列微控制器(如TMS320F2802x)的电机控制、数字电源或工业自动化项目中,串行通信是连接主控芯片与传感器、上位机、存储芯片或其他微控制器的生命线。其中,串…

2026/10/13 12:50:35 阅读更多 →
【Git】GitLab 全部权限角色详解

【Git】GitLab 全部权限角色详解

📚 GitLab 全部权限角色详解 GitLab 的权限体系分为项目/群组角色和管理员角色,其中项目/群组角色从低到高依次为:Guest → Reporter → Developer → Maintainer → Owner,部分版本还新增了 Planner 角色,下面为你逐一…

2026/10/8 8:57:12 阅读更多 →
SpringBoot+Vue超市管理系统:从零搭建全栈毕设项目实战指南

SpringBoot+Vue超市管理系统:从零搭建全栈毕设项目实战指南

这次我们来看一个面向Java初学者的毕业设计项目——基于SpringBootVue的鲜享超市管理系统。这个项目最大的特点不是技术栈有多前沿,而是它提供了一个从零开始、手把手教学的完整实现路径,并且附带了可直接运行的源码、数据库和文档。对于正在为毕设发愁、…

2026/9/28 23:47:42 阅读更多 →

最新新闻

WhoDB 的 Impeccable 设计技能:`delight` 命令如何把“产品个性“注入用户界面

WhoDB 的 Impeccable 设计技能:`delight` 命令如何把“产品个性“注入用户界面

数据库客户端后端前端CLI桌面应用数据可视化AI 应用 【免费下载链接】whodb Where data access meets operational intelligence 项目地址: https://gitcode.com/gh_mirrors/wh/whodb 点击查看 免费下载 本文以 WhoDB 仓库中 .agents 目录下 Impeccable 设计技能的…

2026/10/13 12:50:59 阅读更多 →
RBCADS 5.0实战:快速生成轴承二维三维装配图与说明书

RBCADS 5.0实战:快速生成轴承二维三维装配图与说明书

简介:RBCADS 5.0 是一套面向轴承产品设计人员的滚动轴承计算机辅助设计系统,2005 正式版涵盖 6A 角接触球、6B 四点接触式角接触球、6C 单列圆锥滚子(公制与英制)等常见结构类型,适合轴承企业设计、工艺及报价核算岗位…

2026/10/13 12:50:59 阅读更多 →
CUDA运行期与驱动分层解析:版本兼容与排查指南

CUDA运行期与驱动分层解析:版本兼容与排查指南

1. 从一个编译报错说起:为什么CUDA不是"显卡驱动"那么简单 很多人第一次接触CUDA编程时,脑子里都有一个模糊的印象:CUDA就是让程序跑在显卡上的东西,跟显卡驱动差不多是一回事。直到某天你写了一个 .cu 文件&#xff…

2026/10/13 12:50:59 阅读更多 →
数字艺术设计基础:色彩构图矢量位图与字体排版实战指南

数字艺术设计基础:色彩构图矢量位图与字体排版实战指南

这一讲我们直接进入数字艺术设计里最绕不开、也最容易让人栽跟头的几个底子功夫:色彩、构图、矢量位图认知、字体基础。上一讲我们把软件界面和工作流捋了一遍,这一讲不碰花哨的滤镜和特效,先把地基砸实。无论你是刚开始学平面设计、UI&#…

2026/10/13 12:50:59 阅读更多 →
PLM选型对比表设计与避坑指南:从业务痛点推导权重的结构化决策

PLM选型对比表设计与避坑指南:从业务痛点推导权重的结构化决策

简介:产品生命周期管理(PLM)项目选型对比表是一份面向企业数字化建设决策者、信息化主管及项目实施团队的选型辅助文档。文档围绕法国达索、德国西门子、美国PTC三大主流服务商,从公司综合实力与财务表现、行业客户经验、技术方案…

2026/10/13 12:50:59 阅读更多 →
GongBU模型评估详解:如何用BERTScore、BLEU和Distinct-n指标科学判断微调效果

GongBU模型评估详解:如何用BERTScore、BLEU和Distinct-n指标科学判断微调效果

【免费下载链接】GongBU Paper accepted by CIKM 2024. Codes of GongBU, a LLM fine-tuning platform for domain-specific adaptation. 项目地址: https://gitcode.com/gh_mirrors/go/GongBU 点击查看 免费下载 微调完成之后,最让人头疼的问题往往是&…

2026/10/13 12:49:58 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →