AI助力,制作视频裁剪软件

news2025/7/24 4:00:11

1. 视频裁剪软件套路多

最近再做一些测试,经常需要录屏什么的,有时候录制的时长视频,需要裁剪,比如去掉开头一些帧或者结尾的一些帧,就想保留关键点。但是网上下的一些软件,打开一用都是要付费的。所以想着手撸一个吧。。。

2. AI选择

比如chatgpt,豆包,kimi,deepseek等。个人比较推荐chatgpt,,理由??没有

3. 关键代码

 AI生成后,直接修改下细节就可以用

using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;

namespace VideoTools
{
    public partial class MainWindow : Window
    {
        private DispatcherTimer timer;
        private bool isPlaying = false;
        private bool isUserSeeking = false;
        private TimeSpan frameStep = TimeSpan.FromSeconds(0.04); // 约25帧/秒

        private TimeSpan startTime = TimeSpan.Zero;
        private TimeSpan endTime = TimeSpan.Zero;
        private string ffmpegPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FFmpeg", "ffmpeg.exe");

        public MainWindow()
        {
            InitializeComponent();

            // 初始化计时器用于更新进度条和时间显示
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(30); // 更频繁更新以显示毫秒变化
            timer.Tick += Timer_Tick;

            // 媒体状态改变事件
            mediaElement.MediaOpened += MediaElement_MediaOpened;
            mediaElement.MediaEnded += MediaElement_MediaEnded;
            mediaElement.MediaFailed += MediaElement_MediaFailed;

            // 检查FFmpeg是否可用
            CheckFFmpegAvailability();
        }
        // 检查FFmpeg是否可用
        private void CheckFFmpegAvailability()
        {
            try
            {
                if (!File.Exists(ffmpegPath))
                {
                    exportStatusText.Text = "错误: 未找到FFmpeg。请确保ffmpeg.exe已包含在应用程序目录中。";
                    exportButton.IsEnabled = false;
                    return;
                }

                // 测试运行
                Process.Start(new ProcessStartInfo
                {
                    FileName = ffmpegPath,
                    Arguments = "-version",
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    WindowStyle = ProcessWindowStyle.Hidden
                });

                exportStatusText.Text = "";//"FFmpeg已就绪";
            }
            catch (Exception ex)
            {
                exportStatusText.Text = $"错误: 无法运行FFmpeg - {ex.Message}";
                exportButton.IsEnabled = false;
            }
        }
        // 计时器事件,更新进度条和时间显示
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (mediaElement.NaturalDuration.HasTimeSpan && !isUserSeeking)
            {
                progressSlider.Value = mediaElement.Position.TotalSeconds;
                currentTimeText.Text = FormatTime(mediaElement.Position);
            }
        }


        // 媒体打开事件
        private void MediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            if (mediaElement.NaturalDuration.HasTimeSpan)
            {
                var duration = mediaElement.NaturalDuration.TimeSpan;
                progressSlider.Maximum = duration.TotalSeconds;
                totalTimeText.Text = FormatTime(duration);
                statusText.Visibility = Visibility.Collapsed;

                // 启用控制按钮
                playPauseButton.IsEnabled = true;
                backwardButton.IsEnabled = true;
                forwardButton.IsEnabled = true;
                progressSlider.IsEnabled = true;
                setStartTimeButton.IsEnabled = true;
                setEndTimeButton.IsEnabled = true;

                // 重置剪辑时间
                startTime = TimeSpan.Zero;
                endTime = duration;
                startTimeText.Text = "开始: " + FormatTime(startTime);
                endTimeText.Text = "结束: " + FormatTime(endTime);

                // 开始更新进度(仅在播放时更新)
                if (isPlaying)
                    timer.Start();
            }
        }
        // 设置开始时间按钮点击事件
        private void SetStartTimeButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan)
            {
                startTime = mediaElement.Position;
                if (startTime >= endTime)
                {
                    endTime = startTime.Add(TimeSpan.FromSeconds(1));
                    if (endTime > mediaElement.NaturalDuration.TimeSpan)
                        endTime = mediaElement.NaturalDuration.TimeSpan;
                    endTimeText.Text = "结束: " + FormatTime(endTime);
                }

                startTimeText.Text = "开始: " + FormatTime(startTime);
                exportButton.IsEnabled = true;
                exportStatusText.Text = "";
            }
        }

        // 设置结束时间按钮点击事件
        private void SetEndTimeButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan)
            {
                endTime = mediaElement.Position;
                if (endTime <= startTime)
                {
                    startTime = endTime.Subtract(TimeSpan.FromSeconds(1));
                    if (startTime < TimeSpan.Zero)
                        startTime = TimeSpan.Zero;
                    startTimeText.Text = "开始: " + FormatTime(startTime);
                }

                endTimeText.Text = "结束: " + FormatTime(endTime);
                exportButton.IsEnabled = true;
                exportStatusText.Text = "";
            }
        }

        // 导出按钮点击事件
        private void ExportButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan)
            {
                // 检查开始和结束时间是否有效
                if (startTime >= endTime)
                {
                    MessageBox.Show("开始时间必须小于结束时间", "错误",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                // 显示保存文件对话框
                SaveFileDialog saveFileDialog = new SaveFileDialog
                {
                    Filter = "视频文件|*.mp4;*.avi;*.mkv;*.wmv|所有文件|*.*",
                    Title = "保存剪辑后的视频",
                    DefaultExt = "mp4"
                };

                if (saveFileDialog.ShowDialog() == true)
                {
                    string outputFilePath = saveFileDialog.FileName;
                    ExportVideoClip(outputFilePath);
                }
            }
        }

        // ✅ 集成导出进度到 ProgressBar(需配合前台 XAML 修改)
        // ✅ 修改点:将进度值通过 Dispatcher.Invoke 更新至 UI 控件

        private void ExportVideoClip(string outputFilePath)
        {
            try
            {
                PausePlayback();

                string inputFilePath = string.Empty;
                TimeSpan duration = TimeSpan.Zero;

                Dispatcher.Invoke(() =>
                {
                    exportStatusText.Text = "正在导出视频片段 (0%)...";
                    exportButton.IsEnabled = false;
                    inputFilePath = mediaElement.Source?.LocalPath ?? string.Empty;
                    duration = endTime - startTime;

                    // 初始化进度条(XAML 中需要定义 exportProgressBar)
                    if (exportProgressBar != null)
                    {
                        exportProgressBar.Minimum = 0;
                        exportProgressBar.Maximum = 100;
                        exportProgressBar.Value = 0;
                        exportProgressBar.Visibility = Visibility.Visible;
                    }
                });

                if (string.IsNullOrWhiteSpace(inputFilePath) || !File.Exists(inputFilePath))
                {
                    Dispatcher.Invoke(() =>
                    {
                        exportStatusText.Text = "导出失败: 无效的输入文件路径";
                        exportButton.IsEnabled = true;
                    });
                    return;
                }

                if (duration.TotalMilliseconds <= 0)
                {
                    Dispatcher.Invoke(() =>
                    {
                        exportStatusText.Text = "导出失败: 选择的时间区间无效";
                        exportButton.IsEnabled = true;
                    });
                    return;
                }

                System.Threading.Thread exportThread = new System.Threading.Thread(() =>
                {
                    try
                    {
                        string arguments = $"-ss {FormatTimeForFFmpeg(startTime)} -i \"{inputFilePath}\" -t {FormatTimeForFFmpeg(duration)} -y -movflags +faststart -preset ultrafast \"{outputFilePath}\"";

                        ProcessStartInfo startInfo = new ProcessStartInfo
                        {
                            FileName = ffmpegPath,
                            Arguments = arguments,
                            UseShellExecute = false,
                            CreateNoWindow = true,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true
                        };

                        using (Process process = new Process { StartInfo = startInfo })
                        {
                            process.Start();

                            while (!process.StandardError.EndOfStream)
                            {
                                string line = process.StandardError.ReadLine();

                                if (line != null && line.Contains("time="))
                                {
                                    var match = System.Text.RegularExpressions.Regex.Match(line, @"time=(\d{2}):(\d{2}):(\d{2})\.(\d+)");
                                    if (match.Success)
                                    {
                                        var t = new TimeSpan(
                                            int.Parse(match.Groups[1].Value),
                                            int.Parse(match.Groups[2].Value),
                                            int.Parse(match.Groups[3].Value)) +
                                            TimeSpan.FromMilliseconds(int.Parse(match.Groups[4].Value.PadRight(3, '0')));

                                        double progress = Math.Min(100.0, t.TotalMilliseconds / duration.TotalMilliseconds * 100);

                                        Dispatcher.Invoke(() =>
                                        {
                                            exportStatusText.Text = $"正在导出视频片段 ({progress:F1}%)...";
                                            if (exportProgressBar != null)
                                                exportProgressBar.Value = progress;
                                        });
                                    }
                                }
                            }

                            process.WaitForExit();

                            Dispatcher.Invoke(() =>
                            {
                                exportProgressBar.Visibility = Visibility.Collapsed;

                                if (process.ExitCode == 0 && File.Exists(outputFilePath) && new FileInfo(outputFilePath).Length > 0)
                                {
                                    exportStatusText.Text = "导出成功!";
                                    MessageBox.Show($"视频片段已成功导出到:\n{outputFilePath}",
                                        "导出完成", MessageBoxButton.OK, MessageBoxImage.Information);
                                }
                                else
                                {
                                    exportStatusText.Text = "导出失败";
                                    MessageBox.Show("导出失败,请检查FFmpeg输出", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                                }
                                exportButton.IsEnabled = true;
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        Dispatcher.Invoke(() =>
                        {
                            exportProgressBar.Visibility = Visibility.Collapsed;
                            exportStatusText.Text = "导出失败";
                            exportButton.IsEnabled = true;
                            MessageBox.Show($"导出视频时出错:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        });
                    }
                });

                exportThread.IsBackground = true;
                exportThread.Start();
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() =>
                {
                    exportStatusText.Text = "导出失败";
                    exportButton.IsEnabled = true;
                    MessageBox.Show($"导出视频时出错:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                });
            }
        }

        // 格式化时间为FFmpeg可用的格式 (HH:MM:SS.mmm)
        private string FormatTimeForFFmpeg(TimeSpan time)
        {
            return time.ToString(@"hh\:mm\:ss\.fff");
        }


        // 媒体播放结束事件
        private void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            PausePlayback();
            mediaElement.Position = TimeSpan.Zero;
            UpdateTimeDisplay();
        }

        // 媒体播放失败事件
        private void MediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            MessageBox.Show($"视频播放失败: {e.ErrorException.Message}", "错误",
                MessageBoxButton.OK, MessageBoxImage.Error);
            statusText.Text = "视频加载失败";
            statusText.Visibility = Visibility.Visible;
            PausePlayback();
        }

        // 窗口拖放事件
        private void Window_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (files.Length > 0)
                {
                    OpenVideoFile(files[0]);
                }
            }
        }

        // 窗口拖入事件
        private void Window_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                if (files.Length == 1 && IsVideoFile(files[0]))
                {
                    e.Effects = DragDropEffects.Copy;
                }
                else
                {
                    e.Effects = DragDropEffects.None;
                }
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
            e.Handled = true;
        }

        // 打开视频文件
        private void OpenVideoFile(string filePath)
        {
            try
            {
                if (File.Exists(filePath) && IsVideoFile(filePath))
                {
                    // 停止当前播放
                    PausePlayback();

                    // 加载新视频
                    mediaElement.Source = new Uri(filePath);
                    mediaElement.LoadedBehavior = MediaState.Manual;
                    StartPlayback();

                    statusText.Text = "加载中...";
                    statusText.Visibility = Visibility.Visible;
                }
                else
                {
                    MessageBox.Show("请选择有效的视频文件", "错误",
                        MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开视频时出错: {ex.Message}", "错误",
                    MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        // 检查文件是否为视频文件
        private bool IsVideoFile(string filePath)
        {
            string extension = System.IO.Path.GetExtension(filePath).ToLower();
            string[] videoExtensions = { ".mp4", ".avi", ".mkv", ".wmv", ".mov", ".flv", ".webm" };
            return Array.IndexOf(videoExtensions, extension) >= 0;
        }

        // 播放/暂停按钮点击事件
        private void PlayPauseButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null)
            {
                if (isPlaying)
                    PausePlayback();
                else
                    StartPlayback();
            }
        }

        // 开始播放
        private void StartPlayback()
        {
            mediaElement.Play();
            playPauseButton.Content = "❚❚";
            isPlaying = true;
            timer.Start();
        }

        // 暂停播放
        private void PausePlayback()
        {
            mediaElement.Pause();
            playPauseButton.Content = "▶";
            isPlaying = false;
            timer.Stop();
        }

        // 后退一帧按钮点击事件
        private void BackwardButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null)
            {
                bool wasPlaying = isPlaying;
                if (wasPlaying) PausePlayback();

                var newPosition = mediaElement.Position - frameStep;
                if (newPosition < TimeSpan.Zero)
                    newPosition = TimeSpan.Zero;

                mediaElement.Position = newPosition;
                UpdateTimeDisplay();

                if (wasPlaying) StartPlayback();
            }
        }

        // 前进一帧按钮点击事件
        private void ForwardButton_Click(object sender, RoutedEventArgs e)
        {
            if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan)
            {
                bool wasPlaying = isPlaying;
                if (wasPlaying) PausePlayback();

                var newPosition = mediaElement.Position + frameStep;
                if (newPosition > mediaElement.NaturalDuration.TimeSpan)
                    newPosition = mediaElement.NaturalDuration.TimeSpan;

                mediaElement.Position = newPosition;
                UpdateTimeDisplay();

                if (wasPlaying) StartPlayback();
            }
        }

        // 进度条值改变事件
        private void ProgressSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (mediaElement.Source != null && progressSlider.IsEnabled)
            {
                if (Mouse.LeftButton == MouseButtonState.Pressed || isUserSeeking)
                {
                    isUserSeeking = true;
                    mediaElement.Position = TimeSpan.FromSeconds(progressSlider.Value);
                    UpdateTimeDisplay();
                }
            }
        }

        // 鼠标释放事件,结束用户拖动
        private void ProgressSlider_MouseUp(object sender, MouseButtonEventArgs e)
        {
            isUserSeeking = false;
        }

        // 更新时间显示
        private void UpdateTimeDisplay()
        {
            currentTimeText.Text = FormatTime(mediaElement.Position);
        }

        // 格式化时间显示(精确到毫秒)
        private string FormatTime(TimeSpan time)
        {
            if (time.TotalHours >= 1)
                return time.ToString(@"hh\:mm\:ss\.fff");
            else if (time.TotalMinutes >= 1)
                return time.ToString(@"mm\:ss\.fff");
            else
                return time.ToString(@"ss\.fff");
        }
    }
}

视频裁剪工具,视频浏览,支持各类视频文件-*.mp4;*.avi;*.mkv;*.wmv播放,支持视频裁剪,完全免费使用资源-CSDN文库 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2386448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[实战]用户系统-2-完善登录和校验以及VIP

这里写目录标题 完善登录和校验新建lib-auth创建配置引入配置和JWT完善登录基本登录单点登录多点登录校验和拦截编写守卫编写装饰器使用完善VIP修改mysql模型编写vip守卫代码进度完善登录和校验 之前我们模拟过用户的登录,本节将实现token的生成,校验,redis做黑名单。我们需…

印度语言指令驱动的无人机导航!UAV-VLN:端到端视觉语言导航助力无人机自主飞行

作者&#xff1a;Pranav Saxena, Nishant Raghuvanshi and Neena Goveas单位&#xff1a;比尔拉理工学院&#xff08;戈瓦校区&#xff09;论文标题&#xff1a;UAV-VLN: End-to-End Vision Language guided Navigation for UAVs论文链接&#xff1a;https://arxiv.org/pdf/250…

mysql都有哪些锁?

MySQL中的锁机制是确保数据库并发操作正确性和一致性的重要组成部分&#xff0c;根据锁的粒度、用途和特性&#xff0c;可以分为多种类型。以下是MySQL中常见的锁及其详细说明&#xff1a; 一、按锁的粒度划分 行级锁&#xff08;Row-level Locks&#xff09; 描述&#xff1a;…

HarmonyOS NEXT 使用 relationalStore 实现数据库操作

大家好&#xff0c;我是V哥。在 HarmonyOS NEXT 开发中&#xff0c;如何操作数据库&#xff0c;V 哥在测试中总结了以下学习代码&#xff0c;分享给你&#xff0c;如何想要系统学习鸿蒙开发&#xff0c;可以了解一下 V 哥最近刚刚上架出版的 《HarmonyOS 鸿蒙开发之路 卷2 从入…

R语言学习--Day04--数据分析技巧

在清洗完数据&#xff0c;在对数据分析前&#xff0c;我们要懂得先梳理一下我们的逻辑&#xff0c;即数据是什么形式的&#xff0c;要进行哪种分析&#xff0c;有可能呈现什么特点&#xff0c;进而再想怎么处理数据去画图可以最大程度地凸显我们要的特点。 一般来讲&#xff0…

SRS流媒体服务器之RTC播放环境搭建

环境概述 srs版本 commit 44f0c36b61bc7c3a1d51cb60be0ec184c840f09d Author: winlin <winlinvip.126.com> Date: Wed Aug 2 10:34:41 2023 0800Release v4.0-r5, 4.0 release5, v4.0.271, 145574 lines. rtc.conf # WebRTC streaming config for SRS. # see full.…

Android 性能优化入门(三)—— ANR 问题分析

需要清楚 ANR 的概念、类型、如何产生以及如何定位分析。 1、概述 1.1 ANR 的概念 ANR&#xff08;Application Not Responding&#xff09;应用程序无响应。如果你应用程序在主线程被阻塞太长时间&#xff0c;就会出现 ANR&#xff0c;通常出现 ANR&#xff0c;系统会弹出一…

鸿蒙Flutter实战:22-混合开发详解-2-Har包模式引入

以 Har 包的方式加载到 HarmonyOS 工程 创建工作 创建一个根目录 mkdir ohos_flutter_module_demo这个目录用于存放 flutter 项目和鸿蒙项目。 创建 Flutter 模块 首先创建一个 Flutter 模块&#xff0c;我们选择与 ohos_app 项目同级目录 flutter create --templatemodu…

游戏引擎学习第302天:使用精灵边界进行排序

在 game_render_group.cpp 中&#xff1a;正确计算 GetBoundFor() 里的 SpriteBound 值 我们正在进行游戏的排序问题调试。虽然这是一个二维游戏&#xff0c;但包含一些三维元素&#xff0c;因此排序变得比较复杂和棘手。混合二维和三维元素时&#xff0c;需要依赖一些比较主观…

SpringBoot+MyBatis

切换数据库连接词 引入数据库连接词的依赖&#xff0c;配置数据库连接池的类型&#xff1b; 编写测试类&#xff1a; package org.example.threelayerdecouplingdomeapplication2;import org.example.threelayerdecouplingdomeapplication2.mapper.UserMapper; import org.ex…

wireshark: Display Filter Reference

https://www.wireshark.org/docs/dfref/// 这个里面的扩展功能还是很强大&#xff0c;可以帮着问题分析。支持大量的自定义化的字段读取功能&#xff0c;支持很多的协议。 https://www.wireshark.org/docs/dfref///f/frame.html frame.time_delta Time delta from previous ca…

Java基础 Day19

一、泛型&#xff08;JDK5引入&#xff09; 1、基本概念 在编译阶段约束操作的数据类型&#xff0c;并进行检查 好处&#xff1a;统一数据类型&#xff0c;将运行期的错误提升到了编译期 泛型的默认类型是 Object 2、泛型类 在创建类的时候写上泛型 在创建具体对象的时候…

VMware+Windows 11 跳过安装阶段微软账号登录

OOBE 阶段 来到这里 断开网络适配器 VMware右下角&#xff0c;点击网络适配器&#xff0c;断开连接 同时按下 Shift 和 F10 &#xff0c;打开命令提示符(cmd.exe) 输入 oobe\BypassNRO.cmd 并回车 接下来正常进行即可

HarmonyOS开发-应用间跳转

1. HarmonyOS开发-应用间跳转 在鸿蒙中,我们再开发过程当中或多或少都会遇见想要从一个App的页面跳转至另一个App的页面,这个时候我们要怎么进行跳转呢,其实在HarmonyOS开发者文档中只需要用到Want对象和startAbility()方法进行跳转就可以了。 1.1. 实现 (1)我们要先准备两个…

校园二手交易系统

该交易平台分为两部分&#xff0c;前台和后台。用户在前台进行商品选购以及交易&#xff1b;管理员登录后台可以对商品进行维护&#xff0c;主要功能包含&#xff1a; 后台系统的主要功能模块如下&#xff1a; 登录功能、注册功能、后台首页 系统设置&#xff1a; 菜单管理、…

基于pycharm,python,flask,sklearn,orm,mysql,在线深度学习sql语句检测系统

详细视频:【基于pycharm,python,flask,sklearn,orm,mysql&#xff0c;在线深度学习sql语句检测系统-哔哩哔哩】 https://b23.tv/JLQDwNn

upload-labs通关笔记-第17关文件上传之二次渲染gif格式

系列目录 upload-labs通关笔记-第1关 文件上传之前端绕过&#xff08;3种渗透方法&#xff09; upload-labs通关笔记-第2关 文件上传之MIME绕过-CSDN博客 upload-labs通关笔记-第3关 文件上传之黑名单绕过-CSDN博客 upload-labs通关笔记-第4关 文件上传之.htacess绕过-CSDN…

STM32中的SPI通信协议

IIC和SPI的对比 IIC是半双工的通信&#xff0c;无法同时收发信息&#xff1b;SPI是全双工通讯&#xff0c;可以同时收发信息&#xff1b;IIC的通讯协议较复杂&#xff0c;而SPI通讯协议较简单&#xff1b;IIC需要通过地址选择从机&#xff0c;而SPI只主要一个引脚即可选中从机…

从版本控制到协同开发:深度解析 Git、SVN 及现代工具链

前言&#xff1a;在当今软件开发的浪潮中&#xff0c;版本控制与协同开发无疑扮演着举足轻重的角色。从最初的单兵作战到如今大规模团队的高效协作&#xff0c;一套成熟且得力的版本控制系统以及围绕其构建的现代工具链&#xff0c;已然成为推动软件项目稳步前行的关键引擎。今…

《黄帝内经》数学建模与形式化表征方式的重构

黄帝内经的数学概括&#xff1a;《黄帝内经》数学建模与形式化表征方式的重构 摘要&#xff1a;《黄帝内经》通过现代数学理论如动力系统、代数拓扑和随机过程&#xff0c;被重构为一个形式化的人体健康模型。该模型包括阴阳动力学的微分几何、五行代数的李群结构、经络拓扑与同…