【IP101】图像修复技术精解:从传统插值到深度生成修复的算法演进

图像修复技术详解 🎨

图像修复就像是数字世界的"修复匠"!通过各种"修复技术",我们可以让受损的图像重获新生,就像修复匠修复破损的艺术品一样。让我们一起来探索这个神奇的图像"修复工作室"吧!

目录

  • 1. 什么是图像修复?
  • 2. 基于扩散的修复
  • 3. 基于块匹配的修复
  • 4. 基于PatchMatch的修复
  • 5. 基于深度学习的修复
  • 6. 视频修复
  • 7. 代码实现与优化
  • 8. 实验结果与分析

1. 什么是图像修复?

图像修复就像是数字世界的"修复匠",主要目的是:

  • 🎨 修复图像缺失(就像填补画作的破损)
  • 🖌️ 去除不需要的元素(就像清除画作的污渍)
  • 🔍 恢复图像细节(就像修复画作的细节)
  • 📸 提升图像质量(就像让画作焕然一新)

常见的修复方法包括:

  • 基于扩散的修复(最基础的"修复工具")
  • 基于块匹配的修复(智能"拼图"修复)
  • 基于PatchMatch的修复(快速"匹配"修复)
  • 基于深度学习的修复(AI"智能"修复)
  • 视频修复(动态"修复"技术)

2. 基于扩散的修复

想象一下,当你在沙滩上画了一个图案,海浪会慢慢把图案边缘的沙子冲走,这个过程就像扩散修复!扩散修复法通过将已知区域的像素值逐渐"扩散"到未知区域,实现图像修复。

算法原理

扩散修复基于偏微分方程(PDE)理论,主要使用以下方程:

  1. 各向同性扩散方程:
    ∂ I ∂ t = ∇ 2 I \frac{\partial I}{\partial t} = \nabla^2 I tI=2I

  2. 各向异性扩散方程:
    ∂ I ∂ t = ∇ ⋅ ( c ( ∣ ∇ I ∣ ) ∇ I ) \frac{\partial I}{\partial t} = \nabla \cdot (c(|\nabla I|)\nabla I) tI=(c(∣∇I)I)

其中:

  • I I I 是图像强度
  • t t t 是时间参数
  • ∇ \nabla 是梯度算子
  • c ( ∣ ∇ I ∣ ) c(|\nabla I|) c(∣∇I) 是扩散系数函数

代码实现

Mat diffusion_inpaint(const Mat& src,      // 输入图像const Mat& mask,     // 修复区域掩码int radius,          // 扩散半径int num_iterations)  // 迭代次数
{Mat result = src.clone();Mat mask_float;mask.convertTo(mask_float, CV_32F, 1.0/255.0);// 迭代扩散for(int iter = 0; iter < num_iterations; iter++) {Mat next = result.clone();#pragma omp parallel forfor(int i = radius; i < result.rows-radius; i++) {for(int j = radius; j < result.cols-radius; j++) {if(mask.at<uchar>(i,j) > 0) {Vec3f sum(0,0,0);float weight_sum = 0;// 在邻域内进行扩散for(int di = -radius; di <= radius; di++) {for(int dj = -radius; dj <= radius; dj++) {if(di == 0 && dj == 0) continue;Point pt(j+dj, i+di);if(mask.at<uchar>(pt) == 0) {float w = 1.0f / (abs(di) + abs(dj));sum += Vec3f(result.at<Vec3b>(pt)) * w;weight_sum += w;}}}if(weight_sum > EPSILON) {sum /= weight_sum;next.at<Vec3b>(i,j) = Vec3b(sum);}}}}result = next;}return result;
}

3. 基于块匹配的修复

这就像是拼图游戏!我们在图像中寻找与缺失区域最相似的图像块,然后把它"拼"到缺失区域。这种方法特别适合修复有重复纹理的区域。

算法原理

块匹配修复基于以下数学原理:

  1. 块相似度度量:
    d ( p , q ) = ∑ i = 1 n ∑ j = 1 m ∥ I p ( i , j ) − I q ( i , j ) ∥ 2 d(p,q) = \sum_{i=1}^{n} \sum_{j=1}^{m} \|I_p(i,j) - I_q(i,j)\|^2 d(p,q)=i=1nj=1mIp(i,j)Iq(i,j)2

  2. 最佳匹配块选择:
    p ∗ = arg ⁡ min ⁡ p ∈ Ω d ( p , q ) p^* = \arg\min_{p \in \Omega} d(p,q) p=argpΩmind(p,q)

其中:

  • p p p 是待修复块
  • q q q 是候选块
  • Ω \Omega Ω 是已知区域
  • I p ( i , j ) I_p(i,j) Ip(i,j) 是块p在位置(i,j)的像素值

代码实现

Mat patch_match_inpaint(const Mat& src,       // 输入图像const Mat& mask,      // 修复区域掩码int patch_size,       // 块大小int search_area)      // 搜索范围
{Mat result = src.clone();int half_patch = patch_size / 2;// 获取需要修复的点vector<Point> inpaint_points;for(int i = half_patch; i < mask.rows-half_patch; i++) {for(int j = half_patch; j < mask.cols-half_patch; j++) {if(mask.at<uchar>(i,j) > 0) {inpaint_points.push_back(Point(j,i));}}}// 对每个需要修复的点找最佳匹配块#pragma omp parallel forfor(int k = 0; k < static_cast<int>(inpaint_points.size()); k++) {Point p = inpaint_points[k];double min_dist = numeric_limits<double>::max();Point best_match;// 在搜索区域内寻找最佳匹配for(int i = max(half_patch, p.y-search_area);i < min(src.rows-half_patch, p.y+search_area); i++) {for(int j = max(half_patch, p.x-search_area);j < min(src.cols-half_patch, p.x+search_area); j++) {if(mask.at<uchar>(i,j) == 0) {double dist = compute_patch_similarity(src, src, p, Point(j,i), patch_size);if(dist < min_dist) {min_dist = dist;best_match = Point(j,i);}}}}// 复制最佳匹配块if(min_dist < numeric_limits<double>::max()) {for(int di = -half_patch; di <= half_patch; di++) {for(int dj = -half_patch; dj <= half_patch; dj++) {Point src_pt = best_match + Point(dj,di);Point dst_pt = p + Point(dj,di);if(mask.at<uchar>(dst_pt) > 0) {result.at<Vec3b>(dst_pt) = src.at<Vec3b>(src_pt);}}}}}return result;
}

4. 基于PatchMatch的修复

PatchMatch算法就像是"快速拼图"!它通过随机搜索和传播快速找到最佳匹配,大大提高了块匹配的效率。

算法原理

PatchMatch算法基于以下数学原理:

  1. 随机初始化:
    ϕ 0 ( x ) = random offset \phi_0(x) = \text{random offset} ϕ0(x)=random offset

  2. 传播步骤:
    ϕ n ( x ) = arg ⁡ min ⁡ ϕ ∈ { ϕ n ( x ) , ϕ n ( x − 1 ) , ϕ n ( x + 1 ) } d ( x , x + ϕ ) \phi_n(x) = \arg\min_{\phi \in \{\phi_n(x), \phi_n(x-1), \phi_n(x+1)\}} d(x, x+\phi) ϕn(x)=argϕ{ϕn(x),ϕn(x1),ϕn(x+1)}mind(x,x+ϕ)

  3. 随机搜索:
    ϕ n ( x ) = arg ⁡ min ⁡ ϕ ∈ { ϕ n ( x ) , ϕ r a n d o m } d ( x , x + ϕ ) \phi_n(x) = \arg\min_{\phi \in \{\phi_n(x), \phi_{random}\}} d(x, x+\phi) ϕn(x)=argϕ{ϕn(x),ϕrandom}mind(x,x+ϕ)

其中:

  • ϕ ( x ) \phi(x) ϕ(x) 是偏移场
  • d ( x , y ) d(x,y) d(x,y) 是块相似度度量
  • n n n 是迭代次数

代码实现

Mat patchmatch_inpaint(const Mat& src,       // 输入图像const Mat& mask,      // 修复区域掩码int patch_size,       // 块大小int num_iterations)   // 迭代次数
{Mat result = src.clone();int half_patch = patch_size / 2;// 初始化随机匹配RNG rng;Mat offsets(mask.size(), CV_32SC2);for(int i = 0; i < mask.rows; i++) {for(int j = 0; j < mask.cols; j++) {if(mask.at<uchar>(i,j) > 0) {int dx = rng.uniform(0, src.cols);int dy = rng.uniform(0, src.rows);offsets.at<Vec2i>(i,j) = Vec2i(dx-j, dy-i);}}}// 迭代优化for(int iter = 0; iter < num_iterations; iter++) {// 传播for(int i = 0; i < mask.rows; i++) {for(int j = 0; j < mask.cols; j++) {if(mask.at<uchar>(i,j) > 0) {// 检查相邻像素的匹配vector<Point> neighbors = {Point(j-1,i), Point(j+1,i),Point(j,i-1), Point(j,i+1)};for(const auto& n : neighbors) {if(n.x >= 0 && n.x < mask.cols &&n.y >= 0 && n.y < mask.rows) {Vec2i offset = offsets.at<Vec2i>(n);Point match = Point(j+offset[0], i+offset[1]);if(match.x >= 0 && match.x < src.cols &&match.y >= 0 && match.y < src.rows) {double dist = compute_patch_similarity(src, src, Point(j,i), match, patch_size);Vec2i currOffset = offsets.at<Vec2i>(i,j);Point currMatch(j+currOffset[0], i+currOffset[1]);if(dist < compute_patch_similarity(src, src, Point(j,i), currMatch, patch_size)) {offsets.at<Vec2i>(i,j) = offset;}}}}}}}// 随机搜索for(int i = 0; i < mask.rows; i++) {for(int j = 0; j < mask.cols; j++) {if(mask.at<uchar>(i,j) > 0) {int searchRadius = src.cols;while(searchRadius > 1) {int dx = rng.uniform(-searchRadius, searchRadius);int dy = rng.uniform(-searchRadius, searchRadius);Point match(j+dx, i+dy);if(match.x >= 0 && match.x < src.cols &&match.y >= 0 && match.y < src.rows) {double dist = compute_patch_similarity(src, src, Point(j,i), match, patch_size);Vec2i currOffset = offsets.at<Vec2i>(i,j);Point currMatch(j+currOffset[0], i+currOffset[1]);if(dist < compute_patch_similarity(src, src, Point(j,i), currMatch, patch_size)) {offsets.at<Vec2i>(i,j) = Vec2i(dx, dy);}}searchRadius /= 2;}}}}}// 应用最佳匹配for(int i = 0; i < mask.rows; i++) {for(int j = 0; j < mask.cols; j++) {if(mask.at<uchar>(i,j) > 0) {Vec2i offset = offsets.at<Vec2i>(i,j);Point match(j+offset[0], i+offset[1]);if(match.x >= 0 && match.x < src.cols &&match.y >= 0 && match.y < src.rows) {result.at<Vec3b>(i,j) = src.at<Vec3b>(match);}}}}return result;
}

5. 基于深度学习的修复

深度学习修复就像是训练一个"智能修复师"!通过学习大量图像,网络可以理解图像的结构和内容,从而生成更自然的修复结果。

深度学习图像修复的实现通常包括:

  • 编码器-解码器结构(如U-Net、GatedConv等)
  • 注意力机制或门控机制以增强修复效果
  • 判别器用于对抗训练,提升生成图像的真实性
  • 多种损失函数(重建损失、对抗损失、感知损失等)共同优化

具体实现可参考以下开源项目:

  • Gated Convolution(ICCV 2019)
  • Partial Convolution(ECCV 2018)
  • LaMa(高效大掩码修复)

这些项目提供了完整的网络结构、训练代码和预训练模型,适合实际应用和学习。

算法原理

深度学习修复基于以下数学原理:

  1. 生成器损失函数:
    L g e n = L r e c o n + λ a d v L a d v + λ p e r L p e r L_{gen} = L_{recon} + \lambda_{adv}L_{adv} + \lambda_{per}L_{per} Lgen=Lrecon+λadvLadv+λperLper

  2. 重建损失:
    L r e c o n = ∥ G ( x ) − y ∥ 1 L_{recon} = \|G(x) - y\|_1 Lrecon=G(x)y1

  3. 对抗损失:
    L a d v = E x ∼ p d a t a [ log ⁡ D ( x ) ] + E z ∼ p z [ log ⁡ ( 1 − D ( G ( z ) ) ) ] L_{adv} = \mathbb{E}_{x\sim p_{data}}[\log D(x)] + \mathbb{E}_{z\sim p_z}[\log(1-D(G(z)))] Ladv=Expdata[logD(x)]+Ezpz[log(1D(G(z)))]

  4. 感知损失:
    L p e r = ∑ i = 1 N 1 C i H i W i ∥ ϕ i ( G ( x ) ) − ϕ i ( y ) ∥ 1 L_{per} = \sum_{i=1}^N \frac{1}{C_iH_iW_i}\|\phi_i(G(x)) - \phi_i(y)\|_1 Lper=i=1NCiHiWi1ϕi(G(x))ϕi(y)1

其中:

  • G G G 是生成器
  • D D D 是判别器
  • ϕ i \phi_i ϕi 是预训练网络的特征提取器
  • λ a d v \lambda_{adv} λadv λ p e r \lambda_{per} λper 是权重系数

6. 视频修复

视频修复就像是"动态修复"!需要考虑时间维度的连续性,确保修复结果在时间上保持平滑。

算法原理

视频修复基于以下数学原理:

  1. 光流方程:
    I x u + I y v + I t = 0 I_xu + I_yv + I_t = 0 Ixu+Iyv+It=0

  2. 时空一致性约束:
    E t e m p o r a l = ∑ t = 1 T − 1 ∥ I t − I t + 1 ∥ 2 E_{temporal} = \sum_{t=1}^{T-1} \|I_t - I_{t+1}\|^2 Etemporal=t=1T1ItIt+12

  3. 空间平滑约束:
    E s p a t i a l = ∑ t = 1 T ∥ ∇ I t ∥ 2 E_{spatial} = \sum_{t=1}^T \|\nabla I_t\|^2 Espatial=t=1T∥∇It2

其中:

  • I x , I y , I t I_x, I_y, I_t Ix,Iy,It 是图像在x、y方向和时间上的梯度
  • u , v u, v u,v 是光流场
  • T T T 是视频帧数

代码实现

vector<Mat> video_inpaint(const vector<Mat>& frames,     // 输入视频帧const vector<Mat>& masks,      // 每帧的修复掩码int patch_size,                // 块大小int num_iterations)            // 迭代次数
{vector<Mat> results;for(const auto& frame : frames) {results.push_back(frame.clone());}int half_patch = patch_size / 2;// 计算光流场vector<Mat> flow_forward, flow_backward;for(size_t i = 0; i < frames.size()-1; i++) {Mat flow;calcOpticalFlowFarneback(frames[i], frames[i+1], flow,0.5, 3, 15, 3, 5, 1.2, 0);flow_forward.push_back(flow);}for(size_t i = frames.size()-1; i > 0; i--) {Mat flow;calcOpticalFlowFarneback(frames[i], frames[i-1], flow,0.5, 3, 15, 3, 5, 1.2, 0);flow_backward.push_back(flow);}// 迭代修复for(int iter = 0; iter < num_iterations; iter++) {for(size_t t = 0; t < frames.size(); t++) {// 获取时空邻域vector<Mat> temporal_patches;if(t > 0) {Mat map1, map2;Mat& flow = flow_backward[t-1];convertMaps(flow, Mat(), map1, map2, CV_32FC1);Mat warped;remap(results[t-1], warped, map1, map2, INTER_LINEAR);temporal_patches.push_back(warped);}if(t < frames.size()-1) {Mat map1, map2;Mat& flow = flow_forward[t];convertMaps(flow, Mat(), map1, map2, CV_32FC1);Mat warped;remap(results[t+1], warped, map1, map2, INTER_LINEAR);temporal_patches.push_back(warped);}// 修复当前帧for(int i = half_patch; i < frames[t].rows-half_patch; i++) {for(int j = half_patch; j < frames[t].cols-half_patch; j++) {if(masks[t].at<uchar>(i,j) > 0) {double min_dist = numeric_limits<double>::max();Point best_match;// 空间匹配for(int di = -half_patch; di <= half_patch; di++) {for(int dj = -half_patch; dj <= half_patch; dj++) {if(masks[t].at<uchar>(i+di,j+dj) == 0) {double dist = compute_patch_similarity(results[t], results[t],Point(j,i), Point(j+dj,i+di), patch_size);if(dist < min_dist) {min_dist = dist;best_match = Point(j+dj,i+di);}}}}// 时间匹配for(const auto& patch : temporal_patches) {for(int di = -half_patch; di <= half_patch; di++) {for(int dj = -half_patch; dj <= half_patch; dj++) {Point pt(j+dj, i+di);if(pt.x >= 0 && pt.x < patch.cols &&pt.y >= 0 && pt.y < patch.rows) {double dist = compute_patch_similarity(results[t], patch,Point(j,i), pt, patch_size);if(dist < min_dist) {min_dist = dist;best_match = pt;}}}}}// 应用最佳匹配if(min_dist < numeric_limits<double>::max()) {results[t].at<Vec3b>(i,j) =results[t].at<Vec3b>(best_match);}}}}}}return results;
}

7. 代码实现与优化

7.1 并行计算优化

  • 使用OpenMP进行并行计算
  • 合理设置线程数
  • 避免线程竞争

7.2 内存优化

  • 使用连续内存
  • 避免频繁的内存分配
  • 使用内存池

7.3 算法优化

  • 使用查找表
  • 减少重复计算
  • 使用SIMD指令

7.4 算法选择建议

  • 根据修复区域大小选择
  • 考虑图像复杂度
  • 权衡质量和速度

8. 实验结果与分析

8.1 修复效果对比

  • 不同算法的修复效果对比
  • 不同场景下的适用性分析
  • 修复质量评估

8.2 性能分析

  • 计算时间对比
  • 内存占用分析
  • 优化效果评估

8.3 应用案例

  • 老照片修复案例
  • 水印去除案例
  • 视频修复案例

总结

图像修复就像是数字世界的"修复匠"!通过基于扩散、块匹配、PatchMatch和深度学习的"修复技术",我们可以让受损的图像重获新生。在实际应用中,需要根据具体情况选择合适的"修复方案",就像修复匠为每件艺术品制定专属的修复计划一样。

记住:好的图像修复就像是一个经验丰富的"修复匠",既要精确修复,又要保持图像的自然性!🎨

参考资料

  1. Bertalmio M, et al. Image inpainting[C]. SIGGRAPH, 2000
  2. Barnes C, et al. PatchMatch: A randomized correspondence algorithm for structural image editing[J]. TOG, 2009
  3. Yu J, et al. Free-form image inpainting with gated convolution[C]. ICCV, 2019
  4. Liu G, et al. Image inpainting for irregular holes using partial convolutions[C]. ECCV, 2018
  5. OpenCV官方文档: https://docs.opencv.org/
  6. 更多资源: IP101项目主页

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

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

相关文章

Qt enabled + geometry 属性(2)

文章目录 enabled属性可用与禁用的概念API接口代码演示 阐述说明1. 先简单描述下要如何演示出上面两个接口的效果&#xff08;思路&#xff09;2. 事先规范按钮对象的命名3. 定义两个按钮对象的槽函数 动图演示效果4. widget.cpp geometry属性预备知识API接口上下左右移动 ta…

Linux下 使用 SSH 完成 Git 绑定 GitHub

文章目录 1、检查 SSH2、生成 SSH key3、添加 SSH key4、验证绑定是否成功 1、检查 SSH Git Bash 中输入ssh命令&#xff0c;查看本机是否安装 SSH&#xff1a; 2、生成 SSH key &#xff08;1&#xff09;输入 ssh-keygen -t rsa 命令&#xff0c;表示我们指定 RSA 算法生…

ubuntu18.04通过cuda_11.3_xxx.run安装失败,电脑黑屏解决办法

项目场景&#xff1a; ubuntu18.04跑DG-SLAM相关代码&#xff0c;安装lietorch包报错&#xff0c;需要用到GPU。 问题描述 跑代码需要cuda11.3&#xff0c;系统里面有另外一个版本&#xff0c;运行cuda_11.3_xxx.run&#xff0c;同时也选择了driver&#xff0c;安装成功后&am…

基于Qwen1.5-0.5B指令监督微调数据集的模型训练

1、安装 LLaMA Factory 输出:检查LLaMA Factory版本&#xff0c;日志或截图。 2、更新数据集 输出:样本数据集(zh.test.csv)处理后形成微调训练格式的json文件&#xff0c;部分数据或截图。 <数据集> dataset_info.json文件指定 &#xff08;1&#xff09;格式转换&…

JVM梳理(逻辑清晰)

JVM总览 JVM 是什么&#xff0c;作用是什么 JVM&#xff08;Java Virtual Machine&#xff0c;Java 虚拟机&#xff09;是一个可以运行 Java 字节码的虚拟计算机 核心作用&#xff1a;实现跨平台&#xff08;“一次编写&#xff0c;到处运行”&#xff09;&#xff0c;JVM 是…

【typenum】 9 与常量泛型桥接(generic_const_mappings.rs)

一、源码 该代码提供了常量结构体与库类型的转换。 // THIS IS GENERATED CODE //! Module with some const-generics-friendly definitions, to help bridge the gap //! between those and typenum types. //! //! - It requires the const-generics crate feature to be…

SOPHGO算能科技BM1688内存使用与编解码开发指南

1. BM1688内存分配接口详解 1.1 设备内存分配接口区别 BM1688提供了三个主要的设备内存分配接口,它们的主要区别如下: // 基本设备内存分配接口 void* bm_malloc_device_byte(bm_handle_t handle, unsigned int size);// 指定heap区域的设备内存分配 void*</

解决软件连接RabbitMQ突发System.IO.IOException: 无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接异常

一、问题描述 系统再运行时&#xff0c;突然出现 System.Exception: [RabbitMQ.Send Error] RabbitMQ.Client.Exceptions.AlreadyClosedException: Already closed: The AMQP operation was interrupted: AMQP close-reason, initiated by Library, code541, text“Unexpected…

STM32单片机GUI系统1 GUI基本内容

目录 一、GUI简介 1、emWin 2、LVGL (Light and Versatile Graphics Library) 3、TouchGFX 4、Qt for Embedded 5、特性对比总结 二、LVGL移植要求 三、优化LVGL运行效果方法 四、LVGL系统文件 一、GUI简介 在嵌入式系统中&#xff0c;emWin、LVGL、TouchGFX 和 Qt 是…

基于vue框架的动漫论坛g2392(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户 开题报告内容 基于Vue框架的动漫论坛开题报告 一、研究背景与意义 &#xff08;一&#xff09;研究背景 随着互联网技术的飞速发展&#xff0c;动漫文化在全球范围内迅速传播&#xff0c;成为连接各国青年的重要文化纽带。动漫…

网络安全管理之钓鱼演练应急预案

文章目录 网络安全管理之钓鱼演练应急预案前言一、背景和目的1.1背景1.2目的 二、整体思路三、演练所需四、风险评估和演练目标4.1 风险评估4.2 演练目标 五、演练计划5.1 演练时间和地点5.2 参与人员5.3 演练场景5.4 演练流程5.5 演练评估 六、 应急响应流程七、钓鱼邮件防范7…

Hooks实现原理与自定义Hooks

React Hooks 是 React 16.8 引入的一种机制&#xff0c;允许在函数组件中使用状态&#xff08;state&#xff09;、副作用&#xff08;effect&#xff09;等功能&#xff0c;而无需编写 class 组件。其核心原理是通过闭包和链表结构&#xff0c;在 React 的 Fiber 架构中管理组…

单片机设计_四轴飞行器(STM32)

四轴飞行器&#xff08;STM32&#xff09; 想要更多项目私wo!!! 一、系统简介 四轴飞行器是一种通过四个旋翼产生的升力实现飞行的无人机&#xff0c;其核心控制原理基于欧拉角动力学模型。四轴飞行器通过改变四个电机的转速来实现六自由度控制&#xff08;前后、左右、上下…

服务器的基础知识

什么是服务器 配置牛、运行稳、价格感人的高级计算机&#xff0c;家用电脑不能比拟的。 服务器的组成&#xff1a;电源、raid卡、网卡、内存、cpu、主板、风扇、硬盘。 服务器的分类 按计算能力分类 超级计算机 小型机AIX x86服务器&#xff08;服务器cpu架构&#xff09; …

单目测距和双目测距 bev 3D车道线

单目视觉测距原理 单目视觉测距有两种方式。 第一种&#xff0c;是通过深度神经网络来预测深度&#xff0c;这需要大量的训练数据。训练后的单目视觉摄像头可以认识道路上最典型的参与者——人、汽车、卡车、摩托车&#xff0c;或是其他障碍物&#xff08;雪糕桶之类&#xf…

C语言链表的操作

初学 初学C语言时&#xff0c;对于链表节点的定义一般是这样的&#xff1a; typedef struct node {int data;struct node *next; } Node; 向链表中添加节点&#xff1a; void addNode(Node **head, int data) {Node *newNode (Node*)malloc(sizeof(Node));newNode->dat…

STM32 OTA 中断向量表重定向

在STM32的OTA&#xff08;Over-the-Air&#xff09;升级中&#xff0c;​中断向量表重定向是关键技术需求&#xff0c;其核心原因在于STM32的硬件架构和固件运行机制。以下从原理、实现方式及必要性三个角度详细分析&#xff1a; 一、中断向量表的作用与默认机制 ​中断向量表的…

Win11上安装docker

Win11上安装docker 一、安装WSL&#xff08;Windows Subsystem for Linux&#xff09;二、安装docker到D盘三、启动docker四、测试启动容器 一、安装WSL&#xff08;Windows Subsystem for Linux&#xff09; 以管理员身份打开cmd 更新WSL wsl --update3. 安装WSL wsl --ins…

Vue3+ElementPlus 开箱即用后台管理系统,支持白天黑夜主题切换,通用管理组件,

Vue3ElementPlus后台管理系统&#xff0c;支持白天黑夜主题切换&#xff0c;专为教育管理场景设计。主要功能包括用户管理&#xff08;管理员、教师、学生&#xff09;、课件资源管理&#xff08;课件列表、下载中心&#xff09;和数据统计&#xff08;使用情况、教学效率等&am…

java云原生实战之graalvm 环境安装

windows环境安装 在Windows环境下安装GraalVM并启用原生镜像功能时&#xff0c;需要Visual Studio的组件支持。具体要点如下&#xff1a; 核心依赖&#xff1a; 需要安装Visual Studio 2022或更新版本&#xff0c;并确保勾选以下组件&#xff1a; "使用C的桌面开发"…