羽毛球剪辑算法集锦
目录good-badminton 推荐看起来还行racquet-sports-analyzerhuji推理脚本羽球时刻 推荐Badminton-Highlight-Extractiongood-badminton 推荐看起来还行https://github.com/qwpyyx/Good-Badmintonracquet-sports-analyzerBot-Derpy/racquet-sports-analyzerhujihttps://github.com/hhoao/huji https://github.com/hhoao/huji-algorithmconda create -p E:\soft\envs\py312 python3.12 -y conda activate E:\soft\envs\py312 pip install -r requirements.txt推理脚本python main.py --video-path C:\Users\ChanJing-01\Videos\yumao\yumao.mp4 --sport badmintonimport argparse import importlib.util import json import os import sys from pathlib import Path from typing import Any import os import re import sys import shutil from datetime import datetime # 修复 auto_clipper 的排序问题 def patch_auto_clipper(): try: from src.main.core import auto_clipper # 保存原始方法 original_handle_video auto_clipper.AutoClipper.handle_video def patched_handle_video(self, *args, **kwargs): result original_handle_video(self, *args, **kwargs) # 修复 all_ball_video_list 排序 if hasattr(self, all_ball_video_list): def extract_number(filepath): filename os.path.basename(filepath) name_without_ext os.path.splitext(filename)[0] numbers re.findall(r\d, name_without_ext) return int(numbers[0]) if numbers else 0 self.all_ball_video_list.sort(keyextract_number) return result # 替换方法 auto_clipper.AutoClipper.handle_video patched_handle_video print(✅ AutoClipper 排序修复已应用) except Exception as e: print(f⚠️ 无法应用修复: {e}) def _venv_python() - str | None: venv_dir Path(__file__).resolve().parent / .venv if sys.platform win32: candidate venv_dir / Scripts / python.exe else: candidate venv_dir / bin / python return str(candidate) if candidate.is_file() else None def _check_runtime_deps() - None: if importlib.util.find_spec(ruamel.yaml) is None: print(未找到 Python 依赖请先安装并激活虚拟环境, filesys.stderr) if sys.platform win32: print( .\\setup.ps1, filesys.stderr) print( .venv\\Scripts\\activate, filesys.stderr) else: print( ./setup.sh, filesys.stderr) print( source .venv/bin/activate, filesys.stderr) venv_python _venv_python() if venv_python: print(f 或直接: {venv_python} main.py ..., filesys.stderr) sys.exit(1) _check_runtime_deps() from src import CONFIG_PATH from src.main.config.config import Config, load_config from src.main.constant.autoclip_constant import BadmintonAutoClipConfig, MatchType from src.main.constant.common_constant import JobType from src.main.core.badminton_auto_clipper import BadmintonAutoClipper from src.main.core.pingpong_auto_clipper import PingPongAutoClipper from src.main.logger import LOG from src.main.service.large_model_service import LargeModelService from src.main.utils import path_utils def _build_parser() - argparse.ArgumentParser: parser argparse.ArgumentParser(description乒乓球、羽毛球比赛视频自动剪辑, formatter_classargparse.RawDescriptionHelpFormatter, epilog 示例: python main.py --video-path videos/demo.mp4 --sport ping_pong python main.py --video-path videos/demo.mp4 --sport badminton --match-type doubles python main.py --video-path videos/demo.mp4 --sport badminton --export-rounds python main.py --serve python main.py --train python main.py , ) parser.add_argument(--config, defaultCONFIG_PATH, helpf配置目录含 application.yml默认 {CONFIG_PATH}, ) parser.add_argument(--video-path, -v, metavarPATH, defaultrC:\Users\ChanJing-01\Videos\yumao\yumao1.mp4, help本地视频文件路径) parser.add_argument(--sport, defaultbadminton, choices[ping_pong, badminton], help运动类型clip 模式必填, ) parser.add_argument(--match-type, choices[singles, doubles], defaultsingles, help羽毛球比赛类型默认 singles, ) parser.add_argument(--output-dir, -o, metavarDIR, help剪辑输出目录) parser.add_argument(--serve, actionstore_true, help启动 Kafka HTTP 服务) parser.add_argument(--train, actionstore_true, help训练模型) # 新增回合导出相关参数 parser.add_argument(--export-rounds, actionstore_true, defaultTrue, help将每个回合单独导出为独立视频文件) parser.add_argument(--rounds-dir, metavarDIR, help回合视频导出目录默认在输出目录下创建 rounds_时间戳 子目录) parser.add_argument(--export-format, choices[mp4, avi, mov], defaultmp4, help导出视频格式默认 mp4) # 新增低回合阈值参数 parser.add_argument(--low-rounds-threshold, typeint, default5, help低回合阈值默认5个回合少于该值将被分类到低回合文件夹) # 新增视频优化参数 parser.add_argument(--optimize-video, actionstore_true, defaultTrue, help优化导出视频确保播放流畅默认开启) parser.add_argument(--target-fps, typefloat, defaultNone, help目标帧率不指定则保持原始帧率) parser.add_argument(--video-quality, choices[low, medium, high], defaulthigh, help视频质量默认 high) return parser def _resolve_mode(args: argparse.Namespace) - str: modes [bool(args.video_path), args.serve, args.train] if sum(modes) 1: LOG.error(不能同时指定 --video-path、--serve、--train) sys.exit(1) if args.video_path: return clip if args.serve: return serve if args.train: return train return config def _build_auto_clip_config(args: argparse.Namespace) - dict[str, Any] | None: if args.sport ! badminton: return None match_type (MatchType.DOUBLES_MATCH if args.match_type doubles else MatchType.SINGLES_MATCH) return json.loads(BadmintonAutoClipConfig(match_typematch_type).model_dump_json()) def optimize_video_export(input_path: str, output_path: str, target_fps: float None, quality: str high) - bool: try: import cv2 cap cv2.VideoCapture(input_path) if not cap.isOpened(): LOG.error(f无法打开视频: {input_path}) return False # 获取原始参数 original_fps cap.get(cv2.CAP_PROP_FPS) width int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) total_frames int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 验证参数 if width 0 or height 0: LOG.error(f无效的视频尺寸: {width}x{height}) cap.release() return False # 确定最终帧率 fps target_fps if target_fps and target_fps 0 else original_fps if fps 0 or fps 120: fps 30 # 默认30fps # 根据质量设置编码参数 quality_settings {low: {fourcc: cv2.VideoWriter_fourcc(*mp4v), fps: min(fps, 25), scale: 0.5 # 缩放比例 }, medium: {fourcc: cv2.VideoWriter_fourcc(*mp4v), fps: fps, scale: 0.75}, high: {fourcc: cv2.VideoWriter_fourcc(*mp4v), fps: fps, scale: 1.0}} settings quality_settings.get(quality, quality_settings[high]) # 应用缩放 if settings[scale] ! 1.0: width int(width * settings[scale]) height int(height * settings[scale]) # 确保宽高为偶数编码要求 width width if width % 2 0 else width 1 height height if height % 2 0 else height 1 LOG.info(f导出参数: {width}x{height}, {settings[fps]:.2f}fps, {total_frames}帧, 质量:{quality}) # 创建写入器 out cv2.VideoWriter(str(output_path), settings[fourcc], settings[fps], (width, height)) if not out.isOpened(): LOG.error(无法创建视频写入器) cap.release() return False # 逐帧处理 frame_count 0 success_count 0 while True: ret, frame cap.read() if not ret: break # 如果需要缩放 if settings[scale] ! 1.0: frame cv2.resize(frame, (width, height), interpolationcv2.INTER_LINEAR) # 写入帧 out.write(frame) frame_count 1 success_count 1 # 每100帧显示进度 if frame_count % 100 0: LOG.debug(f处理进度: {frame_count}/{total_frames}) cap.release() out.release() # 验证输出 if success_count 0: LOG.error(没有帧被写入) return False # 验证输出文件是否存在且有效 if os.path.exists(output_path) and os.path.getsize(output_path) 0: LOG.info(f✅ 成功导出 {success_count} 帧到: {output_path}) return True else: LOG.error(f输出文件无效: {output_path}) return False except ImportError: LOG.warning(OpenCV未安装请运行: pip install opencv-python) # 回退到简单复制 try: shutil.copy2(input_path, output_path) LOG.info(f使用简单复制: {output_path}) return True except Exception as e: LOG.error(f简单复制失败: {e}) return False except Exception as e: LOG.error(f视频优化失败: {e}) # 尝试简单复制作为备选 try: shutil.copy2(input_path, output_path) LOG.info(f优化失败使用简单复制: {output_path}) return True except: return False def _export_metadata(export_dir: Path, video_path: str, exported_files: list, result, export_format: str, low_rounds: bool False, total_rounds: int 0, optimize_info: dict None) - Path | None: metadata_file export_dir / rounds_metadata.json try: metadata {source_video: video_path, export_time: datetime.now().isoformat(), total_rounds: len(exported_files), format: export_format, rounds: []} # 如果是低回合视频添加标记 if low_rounds: metadata[is_low_rounds] True metadata[low_rounds_threshold] 5 metadata[actual_rounds] total_rounds metadata[reason] f少于5个回合实际{total_rounds}个 # 添加优化信息 if optimize_info: metadata[optimization] optimize_info # 尝试获取每个回合的时间信息 for i, file_path in enumerate(exported_files, 1): round_info {round_number: i, file_name: Path(file_path).name, file_path: file_path} # 如果有时间信息可以添加 if hasattr(result, round_timestamps) and result.round_timestamps: if i len(result.round_timestamps): round_info[timestamp] result.round_timestamps[i - 1] metadata[rounds].append(round_info) with open(metadata_file, w, encodingutf-8) as f: json.dump(metadata, f, ensure_asciiFalse, indent2) LOG.info(f 元数据已导出: {metadata_file}) return metadata_file except Exception as e: LOG.warning(f导出元数据失败: {e}) return None def export_rounds_videos(result, video_path: str, output_dir: str, export_format: str mp4, low_rounds_threshold: int 5, optimize_video: bool True, target_fps: float None, video_quality: str high) - dict: exported_info {total_rounds: 0, exported_files: [], export_dir: output_dir, success: False, low_rounds_dir: None, low_rounds_files: [], low_rounds_count: 0, is_low_rounds: False, metadata_file: None, low_metadata_file: None, optimization_info: {optimized: optimize_video, target_fps: target_fps, quality: video_quality}} # 尝试获取回合视频列表 - 检查多个可能的属性名 round_videos [] possible_attrs [ball_video_list, round_video_list, all_ball_video_list, segment_video_list] for attr in possible_attrs: if hasattr(result, attr): video_list getattr(result, attr) if video_list and isinstance(video_list, list): round_videos video_list LOG.info(f找到回合视频列表: {attr}, 共 {len(round_videos)} 个) break if not round_videos: LOG.warning(未找到回合视频列表请检查剪辑结果对象) # 尝试从 result 的 dict 中获取 if hasattr(result, __dict__): for key, value in result.__dict__.items(): if isinstance(value, list) and value and any(str(v).endswith((.mp4, .avi, .mov)) for v in value): round_videos value LOG.info(f从 {key} 找到回合视频列表) break if not round_videos: LOG.error(无法找到回合视频请确保剪辑过程生成了独立的回合视频文件) return exported_info # 创建导出目录 export_dir Path(output_dir) export_dir.mkdir(parentsTrue, exist_okTrue) # 创建回合子目录 base_name Path(video_path).stem timestamp datetime.now().strftime(%Y%m%d_%H%M%S) # 先统计总回合数 total_rounds len(round_videos) LOG.info(f检测到总回合数: {total_rounds}) # 判断是否少于阈值 is_low_rounds total_rounds low_rounds_threshold if is_low_rounds: LOG.warning(f⚠️ 视频只有 {total_rounds} 个回合少于{low_rounds_threshold}个将导出到低回合文件夹) rounds_subdir export_dir / f{base_name}_low_rounds_{timestamp} else: LOG.info(f✅ 视频有 {total_rounds} 个回合正常) rounds_subdir export_dir / f{base_name}_rounds_{timestamp} rounds_subdir.mkdir(parentsTrue, exist_okTrue) # 导出每个回合 exported_files [] export_stats {total_frames: 0, total_size: 0, avg_fps: 0} for i, round_video_path in enumerate(round_videos, 1): if not os.path.exists(round_video_path): LOG.warning(f回合 {i} 视频文件不存在: {round_video_path}) continue # 构建目标文件名 round_filename fround_{i:03d}.{export_format} dest_path rounds_subdir / round_filename try: success False # 如果启用优化使用优化导出 if optimize_video: LOG.info(f 优化导出回合 {i}...) success optimize_video_export(input_pathround_video_path, output_pathstr(dest_path), target_fpstarget_fps, qualityvideo_quality) # 如果优化失败或未启用使用简单复制 if not success: LOG.info(f 使用简单复制回合 {i}) shutil.copy2(round_video_path, dest_path) success True if success: exported_files.append(str(dest_path)) # 统计信息 file_size os.path.getsize(dest_path) export_stats[total_size] file_size LOG.info(f✅ 回合 {i} 导出成功: {dest_path} ({file_size / 1024 / 1024:.2f}MB)) else: LOG.error(f❌ 回合 {i} 导出失败) except Exception as e: LOG.error(f❌ 回合 {i} 导出异常: {e}) # 最后尝试直接复制 try: shutil.copy2(round_video_path, dest_path) exported_files.append(str(dest_path)) LOG.warning(f⚠️ 回合 {i} 使用应急复制) except Exception as e2: LOG.error(f❌ 回合 {i} 所有导出方式都失败: {e2}) # 更新统计信息 export_stats[exported_count] len(exported_files) if exported_files: export_stats[avg_size] export_stats[total_size] / len(exported_files) # 导出元数据 metadata_file _export_metadata(export_dirrounds_subdir, video_pathvideo_path, exported_filesexported_files, resultresult, export_formatexport_format, low_roundsis_low_rounds, total_roundstotal_rounds, optimize_infoexported_info[optimization_info] if optimize_video else None) # 更新返回信息 exported_info.update({total_rounds: total_rounds, exported_files: exported_files, export_dir: str(rounds_subdir), metadata_file: str(metadata_file) if metadata_file else None, success: len(exported_files) 0, is_low_rounds: is_low_rounds, low_rounds_count: len(exported_files) if is_low_rounds else 0, low_rounds_dir: str(rounds_subdir) if is_low_rounds else None, export_stats: export_stats}) # 打印总结信息 print(\n * 60) print( 导出完成统计) print( * 60) if is_low_rounds: print(f⚠️ 低回合视频) print(f 总回合数: {total_rounds} (少于{low_rounds_threshold}个)) else: print(f✅ 正常视频) print(f 总回合数: {total_rounds}) print(f 成功导出: {len(exported_files)} 个) print(f 导出目录: {rounds_subdir}) if optimize_video: print(f 视频优化: 已启用) if target_fps: print(f 目标帧率: {target_fps} fps) print(f 视频质量: {video_quality}) else: print(f 视频优化: 未启用) if metadata_file: print(f 元数据: {metadata_file}) print( * 60 \n) return exported_info def run_clip(args: argparse.Namespace, config: Config) - None: video_path os.path.abspath(args.video_path) if not os.path.isfile(video_path): LOG.error(f视频文件不存在: {video_path}) sys.exit(1) if not args.sport: LOG.error(clip 模式需要指定 --sportping_pong 或 badminton) sys.exit(1) auto_clip_config config.auto_clip_config common_options auto_clip_config.common_options if args.output_dir: common_options.output_dir path_utils.get_project_path(args.output_dir) large_model_service LargeModelService(config.large_model_service_config) if args.sport ping_pong: clipper PingPongAutoClipper(auto_clip_config.ping_pong, common_options, large_model_service) else: clipper BadmintonAutoClipper(auto_clip_config.badminton, common_options, large_model_service) LOG.info(f开始剪辑: {video_path}) result clipper.autoclip_video(video_path, auto_clip_config_build_auto_clip_config(args)) # 导出合并视频 merged_video_path result.all_match_merged_video_path LOG.info(f✅ 合并视频完成: {merged_video_path}) print(f\n合并视频: {merged_video_path}) # 如果启用了回合导出 if args.export_rounds: LOG.info( 开始导出回合分段视频...) # 确定输出目录 if args.rounds_dir: output_dir os.path.abspath(args.rounds_dir) else: output_dir args.output_dir or str(common_options.output_dir) # 导出回合视频 exported_info export_rounds_videos(resultresult, video_pathvideo_path, output_diroutput_dir, export_formatargs.export_format, low_rounds_thresholdargs.low_rounds_threshold, optimize_videoargs.optimize_video, target_fpsargs.target_fps, video_qualityargs.video_quality) if exported_info[success]: LOG.info(f✅ 所有回合导出完成共 {exported_info[total_rounds]} 个回合) # 显示详细信息 print(f\n 最终结果:) print(f 视频文件: {Path(video_path).name}) print(f 总回合数: {exported_info[total_rounds]}) print(f 成功导出: {len(exported_info[exported_files])} 个) if exported_info[is_low_rounds]: print(f 状态: ⚠️ 低回合视频 ( {args.low_rounds_threshold} 个)) else: print(f 状态: ✅ 正常视频) print(f 导出目录: {exported_info[export_dir]}) if exported_info.get(metadata_file): print(f 元数据: {exported_info[metadata_file]}) # 显示优化信息 if args.optimize_video: print(f 优化: ✅ 已启用 (质量: {args.video_quality})) else: print(f 优化: ❌ 未启用) else: LOG.warning(⚠️ 没有回合视频被导出请检查剪辑结果) print(f\n✅ 处理完成: {merged_video_path}) def run_serve(config: Config) - None: from src.main.http.internal_http import InternalHttp from src.main.service.video_edit_service import VideoEditService auto_clip_config config.auto_clip_config common_options auto_clip_config.common_options large_model_service LargeModelService(config.large_model_service_config) http_client InternalHttp(config.internal.http).client pingpong_auto_clipper PingPongAutoClipper(auto_clip_config.ping_pong, common_options, large_model_service) badminton_auto_clipper BadmintonAutoClipper(auto_clip_config.badminton, common_options, large_model_service) video_edit_service VideoEditService(service_configconfig.service_config, mysql_configconfig.datasource_config.mysql, pingpong_auto_clipperpingpong_auto_clipper, badminton_auto_clipperbadminton_auto_clipper, kafka_configconfig.kafka_config, http_clienthttp_client, ) try: video_edit_service.start() except Exception as e: video_edit_service.stop() LOG.error(f启动服务失败: {e}) def run_from_config(config: Config) - None: if config.job_type JobType.SERVICE: run_serve(config) else: LOG.error(f未知的 job_type: {config.job_type}) sys.exit(1) def main() - None: parser _build_parser() args parser.parse_args() config load_config(args.config) mode _resolve_mode(args) if mode clip: run_clip(args, config) elif mode serve: run_serve(config) else: run_from_config(config) if __name__ __main__: # patch_auto_clipper() main()羽球时刻 推荐yuqiushike.comBadminton-Highlight-Extractionhttps://github.com/Manoj-A-Anandan/Badminton-Highlight-Extraction

相关新闻

C++高性能序列化与数据传输:大数据架构师的底层优化指南

C++高性能序列化与数据传输:大数据架构师的底层优化指南

1. 项目概述:从C基础到大数据架构的必经之路在技术这条路上,我见过太多开发者,尤其是那些从后端或大数据领域切入的朋友,对C的态度总是有些微妙。一方面,它被誉为“性能之王”,是构建底层基础设施、处理海量…

2026/7/27 7:35:22阅读更多 →
GHelper终极指南:10MB轻量化工具如何彻底掌控华硕笔记本性能

GHelper终极指南:10MB轻量化工具如何彻底掌控华硕笔记本性能

GHelper终极指南:10MB轻量化工具如何彻底掌控华硕笔记本性能 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbo…

2026/7/27 7:35:22阅读更多 →
(二十六)BLSG方案

(二十六)BLSG方案

先看方案设计: 插入一条分析:假设哈希函数H是一个随机预言机。如果CDH问题是困难的, 那么BLSG签名方案在EU - CMA安全模型下是可证明安全的, 约化损失为2根号qH,其中qH是对随机预言机的哈希查询次数。规约损失是如何得到的呢?慢慢分析,继续往下看证明如下: 假定存在一…

2026/7/27 7:35:22阅读更多 →
Ubuntu下libevent安装指南与常见问题解决

Ubuntu下libevent安装指南与常见问题解决

1. 项目概述与背景 libevent是一个轻量级的开源高性能网络库,广泛应用于事件驱动的网络编程中。它封装了操作系统底层的I/O复用机制(如epoll、kqueue等),为开发者提供了统一的编程接口。在Linux-Ubuntu环境下安装libevent看似简单…

2026/7/27 8:55:28阅读更多 →
逻辑回归到浅层神经网络的演进与对比

逻辑回归到浅层神经网络的演进与对比

1. 从逻辑回归到浅层神经网络的演进 在机器学习领域,分类问题是最基础也最重要的任务之一。二分类问题尤其常见,比如判断邮件是否为垃圾邮件、识别图片中是猫还是狗等。最初,我们使用逻辑回归来解决这类问题,但随着数据复杂度的提…

2026/7/27 8:55:28阅读更多 →
Windows 11家庭版安装TIA Portal V19许可证管理器全攻略

Windows 11家庭版安装TIA Portal V19许可证管理器全攻略

1. 项目背景与需求解析最近在给一台预装Windows 11家庭版的设备部署TIA Portal V19时,遇到了Automation License Manager V6.2 SP5的安装难题。不同于专业版和企业版,家庭版系统缺少某些关键组件,导致工业自动化软件的安装过程充满陷阱。这个…

2026/7/27 8:55:28阅读更多 →
TMS320C5505 DSP硬件设计:电源、时钟与复位电路实战指南

TMS320C5505 DSP硬件设计:电源、时钟与复位电路实战指南

1. 项目概述与核心挑战在嵌入式硬件设计领域,尤其是面对像TI TMS320C5505这样的高性能数字信号处理器,最考验工程师功底的往往不是复杂的算法实现,而是最基础的“水电煤”——电源、时钟和复位。我见过不少项目,代码写得漂亮&…

2026/7/27 8:55:28阅读更多 →
DSP/BIOS 5.x API实战指南:从核心模块到多核通信的嵌入式实时系统设计

DSP/BIOS 5.x API实战指南:从核心模块到多核通信的嵌入式实时系统设计

1. 项目概述如果你正在使用德州仪器(TI)的TMS320C6000系列DSP进行嵌入式开发,并且项目对实时性有严格要求,那么你大概率绕不开一个名字:DSP/BIOS。这不仅仅是一个实时操作系统(RTOS)内核&#x…

2026/7/27 8:55:28阅读更多 →
AI驱动自建CRM:中小企业替代Salesforce的成本效益分析

AI驱动自建CRM:中小企业替代Salesforce的成本效益分析

这次我们来看一个值得关注的现象:美国小企业正在掀起Salesforce的"退订潮",转而使用AI技术自建软件来大幅压缩成本。这个趋势背后反映的是AI工具成熟度提升和中小企业对成本敏感度的双重变化。对于技术从业者来说,这个现象意味着新…

2026/7/27 8:53:28阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/27 1:14:34阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/27 1:14:52阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/27 1:14:56阅读更多 →
SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

SPI实战指南:从时钟模式到寄存器配置,解决嵌入式通信难题

1. 项目概述:从寄存器手册到实战指南 如果你手头有一份类似德州仪器(TI)TMS320x240xA系列DSP的SPI模块技术手册,看着里面密密麻麻的寄存器位定义、时序图和公式,是不是感觉头大?这份资料虽然权威&#xff0…

2026/7/27 0:00:24阅读更多 →
【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于springboot的水果购物管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/27 0:00:24阅读更多 →
2007-2023年各市区县生态文明建设示范区DID

2007-2023年各市区县生态文明建设示范区DID

数据简介 自改革开放以来,我国依赖高投入、高资源消耗和高污染等传统发展模式实现了经济短期内的快速增长, 然而这也导致了严重的生态环境危机。因此,国家有力于推动企业高质量经济发展,协同生态保护的方针,从而从201…

2026/7/27 0:00:24阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/25 23:03:25阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/26 19:05:21阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/26 19:05:21阅读更多 →