STM32图像识别实战:从传统CV到TinyML的边缘AI部署

news2026/5/20 22:02:03
1. 项目概述当STM32遇上图像识别在嵌入式开发领域STM32系列微控制器因其出色的性能、丰富的外设和极高的性价比早已成为工程师和爱好者的“瑞士军刀”。从简单的LED闪烁到复杂的电机控制、通信协议栈STM32几乎无所不能。但提到“图像识别”很多人的第一反应可能是树莓派、Jetson Nano这类搭载Linux系统、算力强大的单板计算机或者是直接调用云端API。那么用一块主频可能只有几十到几百兆赫兹、内存以KB计的STM32来做图像识别是不是有点“小马拉大车”甚至是不切实际呢恰恰相反在边缘计算和物联网设备小型化、低功耗化的趋势下在资源受限的微控制器上实现轻量级图像识别正成为一个极具价值和挑战性的热门方向。想象一下一个智能门锁需要识别人脸是否为本家庭成员一个工业分拣设备需要快速识别零件缺陷一个农业监测传感器需要辨别作物病虫害——这些场景往往要求设备24小时在线、响应实时、且功耗极低部署一个大型的Linux系统并保持网络连接在成本、功耗和实时性上可能都不是最优解。这时STM32这类MCU的价值就凸显出来了。这个项目的核心就是探索如何在STM32的有限资源框架内设置并执行一个可用的图像识别任务。它不是一个简单的库函数调用而是一套完整的系统工程涉及图像传感器选型与驱动、图像数据的采集与预处理、识别算法的移植与优化、以及最终结果的输出与应用。整个过程充满了权衡与取舍在识别精度、处理速度、内存占用和功耗之间寻找最佳平衡点。对于开发者而言这不仅是对STM32编程能力的考验更是对嵌入式AI、数字图像处理等跨领域知识的综合实践。接下来我将拆解这个过程中的每一个关键环节分享从硬件选型到算法部署的实战经验与避坑指南。2. 核心思路与方案选型不走寻常路的嵌入式AI在STM32上做图像识别绝不能照搬PC或嵌入式Linux上的思路。核心思路可以概括为“前端轻量化算法微型化流程流水线化”。我们的目标不是运行一个庞大的、通用的深度学习模型如YOLO或ResNet而是针对特定任务定制一个极度精简的推理引擎。2.1 算法路径选择传统CV vs. 微型神经网络这是首要的决策点直接决定了后续所有工作的方向。方案一传统计算机视觉算法这种方法不依赖神经网络主要利用数字图像处理DIP和特征提取技术。典型算法颜色空间转换如RGB转灰度、HSV、阈值分割、边缘检测如Sobel、Canny、轮廓查找、特征匹配如ORB但较复杂等。适用场景识别任务简单、规则明确。例如识别流水线上特定颜色的物体、检测屏幕是否出现特定形状的图标、判断LED灯的亮灭状态等。优势确定性高算法逻辑固定没有随机性结果可预测。资源消耗极低通常只需几KB到几十KB的RAM和Flash对CPU要求也相对不高。可解释性强每一步处理的结果都可以直观理解。劣势鲁棒性差对光照变化、角度旋转、背景干扰非常敏感。环境一变可能就需要重新调整参数。特征设计复杂对于稍复杂的任务如区分猫和狗手工设计有效特征非常困难。方案二微型机器学习与神经网络这是当前的主流方向即训练一个超轻量级的神经网络模型然后将其部署到MCU上这个过程称为TinyML。典型模型TensorFlow Lite for Microcontrollers (TFLite Micro) 支持的模型如MobileNetV1/V2的极简版、自己设计的小型CNN卷积神经网络等。也可以使用CMSIS-NNARM针对Cortex-M系列优化的神经网络库来手动构建和运行模型。适用场景需要一定泛化能力的分类任务。例如识别不同手势、分辨几种简单的工业零件、进行关键字唤醒语音识别也属此范畴等。优势鲁棒性好经过充分训练后对光照、角度等变化有一定容忍度。开发效率高特征提取由网络自动完成开发者更专注于数据收集和模型训练。劣势资源消耗大即使是微型模型也可能需要上百KB的Flash存储权重以及几十KB的RAM作为运行时缓冲区Tensor Arena。对STM32的型号有较高要求。工具链复杂涉及Python环境训练、模型转换、量化、集成等一系列步骤。实操心得对于初次尝试者如果你的识别目标非常具体且环境可控比如在固定光照下识别一个红色方块强烈建议从传统CV方法入手。它能帮你快速建立起“采集-处理-判断”的完整流程理解图像数据在MCU中的流动方式。当传统方法无法满足需求时再转向微型神经网络方案。我个人的项目迭代路径通常是先用OpenCV在PC上快速验证算法可行性然后将C/Python算法“翻译”成纯C语言版本最后移植到STM32。2.2 硬件平台选型不是所有STM32都能“看得见”图像识别是计算和内存密集型任务STM32的选型至关重要。核心计算单元Cortex-M4/M7/M33内核是入门门槛。M4带DSP和FPU浮点单元对于传统CV中的滤波、变换等运算有巨大加速作用。M7和M33性能更强是运行微型神经网络的更佳选择。尽量避免使用M0/M3内核它们进行大量乘加运算会非常吃力。内存Flash RAMFlash需要存储程序代码、可能用到的模型权重如果是神经网络、以及字库等资源。神经网络模型通常需要256KB以上的Flash空间。RAM这是最紧张的资源。图像缓冲区是吃RAM的大户。例如一张QVGA320x240的灰度图就需要 320240 76.8KB 的RAM。如果是RGB565彩色图则需要 320240*2 153.6KB。这还没算上处理过程中的中间缓冲区。因此目标STM32的RAM最好在128KB以上推荐256KB或更多。常见型号推荐入门/传统CVSTM32F4系列如F407/F429主频168MHzRAM 192KB性价比高。神经网络入门STM32H7系列如H743/H750主频400MHzRAM 1MB性能强劲是当前TinyML的热门平台。带AI加速STM32N6系列如N6xx内置NPU神经网络处理单元专为AI设计性能有质的飞跃。图像传感器接口DCMISTM32的数字摄像头接口这是连接并行输出摄像头如OV7670、OV2640的专用硬件接口可以高效地将图像数据通过DMA直接搬运到内存中极大节省CPU开销。选型时务必确认芯片是否带有DCMI外设。SPI/I2C用于连接一些低分辨率或串行输出的传感器如一些热成像传感器、手势传感器。对于稍高帧率的图像采集带宽可能成为瓶颈。2.3 图像传感器选型画质、速度与接口的权衡摄像头是项目的“眼睛”选型不当会直接导致项目失败。传感器型号分辨率输出格式接口优点缺点适用场景OV7670最高VGA(640x480)YUV/ RGB565/ RAWDCMI (8-bit)经典便宜资料多画质一般需外部晶振配置复杂学习、验证对画质要求不高的识别OV2640最高2MP (1600x1200)JPEG/ YUV/ RGB565DCMI (8-bit)自带JPEG压缩节省带宽和内存压缩会损失细节增加CPU解码负担需要较高分辨率但传输/存储带宽有限的场景GC032830万像素YUV/ RGB565DCMI (8-bit)性价比高体积小市场型号杂驱动适配可能需功夫小型化设备如智能门锁MT9V034全局快门752x480灰度DCMI (8-bit)全局快门无果冻效应适合运动物体通常是灰度传感器无彩色信息工业检测高速运动物体拍摄注意事项新手常犯的错误是盲目追求高分辨率。在STM32上VGA640x480已经是非常高的分辨率了。更高的分辨率意味着更大的图像缓冲区更长的处理时间。原则是在满足识别精度的前提下使用尽可能低的分辨率。很多时候QQVGA160x120或QVGA320x240就足够了。可以先在PC上用不同分辨率的图像测试算法效果再决定硬件选型。3. 开发环境搭建与驱动编写工欲善其事必先利其器。一个高效的开发环境能事半功倍。3.1 软件工具链准备IDESTM32CubeIDE是ST官方的免费集成开发环境基于Eclipse集成了CubeMX配置工具和调试器一站式解决对新手友好。也可以使用 Keil MDK 或 IAR它们编译器优化效率可能更高但收费。STM32CubeMX必备神器。用于图形化配置芯片时钟、外设DCMI、DMA、GPIO、I2C等、中间件FATFS, USB等并生成初始化代码框架。它能帮你避免大量底层寄存器配置的繁琐工作。图像处理库传统CV可以移植轻量级的库如libfixmath定点数运算、CImg的简化版或者自己实现关键函数如灰度化、二值化、Sobel算子。微型神经网络TensorFlow Lite for Microcontrollers谷歌官方框架支持将训练好的TFLite模型部署到MCU。需要将其作为库文件集成到工程中。CMSIS-NNARM针对Cortex-M处理器优化的神经网络内核函数库。如果你是自己构建小网络或者使用其他框架生成的模型可以调用CMSIS-NN的API来加速卷积、全连接等操作。上位机软件用于调试和图像显示。如STM32CubeMonitor可自定义数据流显示、OpenCV编写简单的PC端程序接收串口发送的图像数据并显示、或串口调试助手的图像显示功能。3.2 摄像头驱动与DCMI配置这是项目第一个硬骨头核心是让STM32通过DCMI接口稳定地收到图像数据。CubeMX配置使能DCMI外设配置数据宽度如8位、像素时钟极性、数据使能极性等。这些参数必须与摄像头传感器数据手册严格匹配。配置一个DMA流将DCMI的数据流直接搬运到内存中指定的数组图像缓冲区。一定要用DMA否则每个像素都会产生中断CPU将完全被占用。配置一个I2C或SCCBOV系列常用接口用于连接摄像头的配置总线初始化传感器参数如分辨率、输出格式、曝光、增益等。驱动编写要点传感器初始化根据数据手册通过I2C依次写入寄存器设置所需的工作模式。OV系列通常有厂家提供的初始化寄存器序列数组可以直接使用但可能需要根据实际电路如主时钟频率微调。双缓冲区乒乓操作这是实现流畅连续采集的关键技巧。分配两个图像缓冲区BufferA和BufferB。当DMA正在将一帧数据填入BufferA时CPU可以处理上一帧已经填满的BufferB。当BufferA填满后DMA自动切换至BufferBCPU则处理BufferA如此循环。这能有效避免处理速度跟不上采集速度导致的图像撕裂问题。// 伪代码示例 uint8_t image_buffer_A[IMAGE_SIZE]; uint8_t image_buffer_B[IMAGE_SIZE]; volatile uint8_t *current_process_buf NULL; // 指向当前待处理的缓冲区 volatile uint8_t *current_capture_buf image_buffer_A; // 指向当前DMA填充的缓冲区 void DCMI_DMA_TransferCompleteCallback(DMA_HandleTypeDef *hdma) { // DMA传输完成中断 current_process_buf current_capture_buf; // 将填满的缓冲区交给处理线程 // 切换DMA目标到另一个缓冲区 if (current_capture_buf image_buffer_A) { current_capture_buf image_buffer_B; HAL_DMA_Start_IT(hdma_dcmi, (uint32_t)DCMI-DR, (uint32_t)image_buffer_B, IMAGE_SIZE); } else { current_capture_buf image_buffer_A; HAL_DMA_Start_IT(hdma_dcmi, (uint32_t)DCMI-DR, (uint32_t)image_buffer_A, IMAGE_SIZE); } // 可以设置一个信号量或标志位通知主循环有新的图像待处理 }同步信号处理DCMI的VSYNC帧同步和HSYNC行同步信号要正确配置。通常使用中断或事件来检测一帧的开始和结束用于控制DMA的启停和缓冲区切换逻辑。踩坑实录初期调试时最容易出现“花屏”或“全黑/全白”图像。排查顺序1.电源和时钟确保摄像头模组的供电通常是3.3V和1.8V稳定主时钟XCLK频率正确且波形干净。2.数据线物理连接检查D0-D7数据线、PCLK、HREF、VSYNC是否虚焊或接错。3.时序参数在CubeMX中反复核对DCMI的时钟极性和数据使能极性与传感器手册对比。4.缓冲区对齐确保DMA目标内存地址是4字节对齐的取决于总线宽度有时不对齐会导致数据错位。5.I2C配置用逻辑分析仪抓取I2C波形确认初始化寄存器的写入值和顺序完全正确。4. 图像预处理在MCU上为识别“减肥”从摄像头得到的原始图像数据RGB565或YUV通常不能直接用于识别尤其是对资源紧张的STM32。预处理的目标是降维、去噪、增强特征同时最大限度减少计算量和内存占用。4.1 分辨率缩放与ROI硬件缩放部分高级的摄像头传感器如OV2640支持通过寄存器设置输出子采样Subsampling或窗口Windowing模式直接输出较低分辨率的图像。这是最推荐的方式直接从源头减少数据量。软件缩放如果传感器不支持或者需要动态调整则需要在MCU端进行。采用最邻近插值或简单的行列隔点采样速度较快。例如将QVGA图像缩放到QQVGA可以直接每两个像素取一个。ROI如果你只关心图像中某个固定区域的物体比如摄像头对准传送带中央可以在内存中只定义该区域大小的缓冲区并通过配置DCMI的CROP功能如果支持或软件上只处理该区域的数据来大幅减少后续处理量。4.2 色彩空间转换与二值化灰度化将彩色图转为灰度图是减少数据量的标准操作。对于RGB565格式常用的灰度公式是Gray (R*38 G*75 B*15) 7近似于0.299R0.587G0.114B。这个计算可以在像素搬运过程中同步进行节省一个完整的缓冲区。二值化对于背景和前景对比明显的场景如黑底白字的识别二值化是终极的“减肥”手段将灰度图变成只有0和1的黑白图。关键在于阈值的选取。固定阈值最简单但受光照影响大。自适应阈值如局部平均阈值法效果更好但计算量稍大。可以在STM32上实现例如计算图像全局均值作为阈值。// 简单的全局阈值二值化示例 void binaryzation(uint8_t *gray_img, uint8_t *bin_img, int width, int height) { uint32_t sum 0; // 第一步计算全局平均灰度 for(int i0; iwidth*height; i) { sum gray_img[i]; } uint8_t threshold sum / (width * height); // 第二步根据阈值生成二值图像 for(int i0; iwidth*height; i) { bin_img[i] (gray_img[i] threshold) ? 255 : 0; } }4.3 滤波与降噪图像传感器难免有噪声预处理时需要平滑。均值滤波快速但会使边缘模糊。3x3的窗口需要9次加法、1次除法或移位。中值滤波对椒盐噪声效果好但计算量较大需要排序。在STM32上对于小窗口3x3可以使用优化过的排序网络算法。高斯滤波效果更平滑但涉及浮点运算或定点数乘法。在STM32上可以预先计算好整数化的高斯核用整数乘加来实现。实操心得预处理链的顺序和算法选择需要反复试验和权衡。一个黄金法则是在PC上用OpenCV先用高分辨率图像设计并验证整个预处理和识别流程确定最低可接受的分辨率和最简单的算法组合。然后再将其移植到STM32。在MCU上能用一个if-else解决的绝不用一个循环能用移位解决的绝不用乘除。5. 识别算法实现与优化这是项目的“大脑”部分。我们分别从传统CV和微型神经网络两条路径展开。5.1 传统计算机视觉方法实战假设我们的任务是识别一个红色圆形物体在图像中的位置比如一个红色的乒乓球。算法流程设计输入RGB565原始图像。步骤1颜色分割。将RGB图像转换到HSV颜色空间更适合颜色分割。在STM32上实现RGB到HSV的快速转换是个挑战因为涉及三角函数。通常的优化是预先计算好红色色调H分量的范围如0-10和170-180并制作成查找表LUT。或者更简单粗暴但有效的方法是直接在RGB空间判断 R G2 且 R B2经验公式将符合条件的像素标记为前景。步骤2形态学操作。对二值化的红色区域进行腐蚀和膨胀消除小的噪声点连接相邻区域。腐蚀和膨胀可以用3x3的结构元素进行遍历是计算密集型操作需要优化。步骤3轮廓查找与筛选。遍历二值图像找到所有连通域轮廓。这是一个经典的“种子填充”或“连通组件标记”算法。在STM32上实现时要注意栈溢出风险可以使用迭代而非递归。然后计算每个连通域的面积、外接圆度等特征。步骤4特征匹配与输出。根据面积大小和圆度(4*π*面积)/(周长^2)越接近1越圆筛选出最可能是红色圆形的物体计算其最小外接圆或质心坐标并输出。关键优化技巧查找表将复杂的计算如三角函数、颜色转换结果预先计算好存储在Flash中用查表代替实时计算。定点数运算STM32的Cortex-M4/M7虽然有FPU但整数运算尤其是乘加通常更快、更省电。将浮点运算转换为定点数运算如Q格式表示法能显著提升速度。CMSIS-DSP库ARM提供的DSP库中包含了大量优化的数学函数如向量乘法、加法、滤波等。善用这些库函数而不是自己写循环。降低遍历维度例如在找轮廓时可以不用遍历全图而是先对图像进行行投影和列投影快速定位目标可能存在的区域ROI再在ROI内进行精细处理。5.2 微型神经网络部署流程以使用TensorFlow Lite MicroTFLM部署一个手势识别模型为例。模型训练与导出在PC上使用TensorFlow/Keras搭建一个简单的CNN模型例如2-3个卷积层池化层1-2个全连接层。用收集到的手势图像数据集如手势0-5的图片训练模型。训练完成后将模型转换为TensorFlow Lite格式.tflite文件。模型量化这是将模型部署到MCU的关键步骤。量化将模型权重和激活值从32位浮点数转换为8位整数。这能将模型大小减少约75%并显著加速推理速度因为整数运算在MCU上更快。使用TFLite的量化训练后量化工具进行全整数量化。集成TFLM到STM32工程从TensorFlow GitHub仓库获取TFLM的源码。将其核心文件.c和.h添加到你的STM32 CubeIDE或Keil工程中。将量化后的.tflite模型文件通过一个工具如xxd命令转换为C语言数组嵌入到程序的Flash里。# 在Linux/Mac或WSL下 xxd -i converted_model.tflite model_data.cc在代码中初始化TFLM解释器将模型数组加载进去并分配一个足够大的“Tensor Arena”一块连续的RAM用于存储中间结果。推理执行将预处理好的图像数据例如缩放并归一化后的灰度图填充到输入张量。调用解释器的Invoke()函数执行推理。从输出张量中读取结果通常是每个类别的概率得分。// 伪代码示例 #include tensorflow/lite/micro/micro_interpreter.h // ... 其他头文件 // 1. 声明模型数组由xxd生成 extern const unsigned char g_model[]; extern const int g_model_len; // 2. 分配Tensor Arena (在全局区或堆上) const int tensor_arena_size 10 * 1024; // 根据模型调整通常需要几十KB uint8_t tensor_arena[tensor_arena_size]; // 3. 在初始化函数中 tflite::MicroErrorReporter error_reporter; const tflite::Model* model tflite::GetModel(g_model); static tflite::MicroInterpreter static_interpreter( model, tflite::ops::micro::AllOpsResolver(), tensor_arena, tensor_arena_size, error_reporter); static_interpreter.AllocateTensors(); // 分配张量内存 // 4. 在循环中执行推理 TfLiteTensor* input static_interpreter.input(0); // ... 将预处理后的图像数据拷贝到 input-data.int8 (或 .data.f 如果是浮点模型) memcpy(input-data.int8, preprocessed_image, input-bytes); TfLiteStatus invoke_status static_interpreter.Invoke(); if (invoke_status ! kTfLiteOk) { /* 处理错误 */ } TfLiteTensor* output static_interpreter.output(0); // output-data.int8 中存储了各个类别的得分 int8_t* scores output-data.int8; // 找出得分最高的类别 int predicted_class argmax(scores, output-dims-data[1]);性能优化使用CMSIS-NNTFLM的后端支持CMSIS-NN。在编译时启用CMSIS-NN内核TFLM会自动调用这些高度优化的函数推理速度可以提升数倍。调整Tensor Arena大小通过实验找到最小可用的Arena大小节省RAM。模型剪枝在训练时使用剪枝技术移除不重要的神经元连接进一步压缩模型。6. 系统集成、调试与性能评估当驱动、预处理和识别算法都准备好后需要将它们整合成一个稳定、高效的系统。6.1 任务调度与系统架构一个典型的图像识别任务流程是周期性的。建议采用前后台系统或简单的状态机而不是复杂的RTOS以降低系统复杂度。状态1等待帧捕获完成。DMA在后台搬运数据。状态2图像预处理。当current_process_buf就绪标志被设置进入此状态进行缩放、灰度化、滤波等操作。状态3识别推理。执行CV算法或神经网络推理。状态4结果输出与响应。通过串口打印结果、点亮LED、控制舵机等。返回状态1等待下一帧。要特别注意时序分析用定时器或系统滴答计时器测量每个阶段消耗的时间毫秒级。确保“一帧处理总时间”小于“一帧采集时间”否则会导致系统越来越慢最终卡死。6.2 调试技巧与性能评估图像输出调试将处理中间环节的图像数据如二值化后的图像通过串口发送到上位机显示是最有效的调试手段。可以先将图像下采样并转换为ASCII艺术图或者开发一个简单的上位机程序用OpenCV还原显示。性能 profilingCPU利用率在main循环中翻转一个GPIO引脚用示波器测量其高低电平时间可以粗略估算CPU空闲程度。内存使用通过IDE的map文件查看.data,.bssRAM和.textFlash段的大小确保没有溢出。帧率在流程开始和结束点打时间戳计算FPS。这是最直观的性能指标。功耗评估如果项目对功耗敏感需要测量不同工作模式下的电流。在等待帧捕获的间隙可以让CPU进入低功耗的SLEEP模式由DCMI和DMA的中断来唤醒它。6.3 常见问题排查速查表现象可能原因排查方向图像全黑/全白摄像头未正确初始化曝光参数错误数据线连接问题1. 检查I2C初始化序列。2. 用逻辑分析仪抓取DCMI数据线和同步信号。3. 检查传感器供电和时钟。图像有彩色条纹/错位DCMI时序配置错误DMA缓冲区地址非对齐PCLK时钟不稳定1. 核对CubeMX中DCMI的极性设置。2. 确保图像缓冲区地址4字节对齐。3. 检查PCB布线时钟线远离高频干扰源。处理速度极慢帧率很低算法复杂度太高未使用硬件加速编译器优化未开启1. 用定时器定位耗时最长的函数。2. 检查是否启用了FPU和DSP指令集编译器选项-mfpufpv4-sp-d16 -mfloat-abihard。3. 开启编译器优化-O2或-Os。神经网络推理结果完全错误输入数据预处理不一致模型未正确量化Tensor Arena不足1. 确保在MCU上的归一化、缩放方式与PC训练时完全一致。2. 检查模型是否成功加载输入/输出张量维度是否正确。3. 增大Tensor Arena并观察是否改善。系统运行一段时间后死机内存泄漏栈溢出中断冲突1. 检查动态内存分配尽量避免在MCU上用malloc。2. 增大任务栈大小。3. 检查中断优先级避免DMA中断被长时间阻塞。7. 进阶优化与扩展思路当基础功能跑通后可以考虑以下方向进行深化使用硬件加速器如果使用STM32H7系列可以利用其硬件JPEG编解码器直接处理OV2640输出的JPEG流节省CPU资源。对于STM32N6则可以利用NPU来运行更大的模型。集成实时操作系统当系统功能变复杂如需要同时处理图像、网络通信、用户界面时引入FreeRTOS等RTOS来管理多任务提高系统的可靠性和响应性。离线学习与在线更新探索在设备端进行少量数据学习在线学习的可能性或者通过SD卡、蓝牙等方式更新设备端的模型文件使识别能力可以迭代。多传感器融合结合其他传感器如TOF飞行时间测距传感器在识别出物体的同时获取其距离信息实现更复杂的交互。在STM32上实现图像识别是一个将理论、硬件、软件深度结合的挑战性项目。它没有唯一的正确答案充满了各种权衡和取舍。从点亮摄像头到看到第一帧清晰的图像再到算法成功识别出目标每一步都充满了成就感。这个过程不仅能让你深入理解嵌入式系统的底层原理更能让你掌握边缘AI应用的核心方法论。记住最关键的不是追求极致的精度或速度而是在有限的资源内找到最优雅、最稳定的解决方案。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…