基于FPGA的图像边缘检测

news/2024/5/1 8:19:44/文章来源:https://blog.csdn.net/xyf_fate/article/details/127190179

基于FPGA的图像边缘检测

      • 一、图像处理算法
        • 1.灰度转换
        • 2.高斯滤波
        • 3.二值化
        • 4.Sobel
      • 二、项目框架
        • 1.摄像头配置模块
        • 2.图像处理模块
        • 3.数据缓存模块
        • 4.其它模块
      • 三、部分代码
        • 1.数据采集模块
        • 2.读写控制模块
      • 四、参考
      • 五、源码

简介:基于FPGA,摄像头实时采集图像数据,经过图像处理、乒乓缓存,通过vga显示

工具:Quartus 18.1

开发板:AIGO_C4MB_V11(CycloneIV-EP4CE6F17C8)

摄像头:OV5640

一、图像处理算法

1.灰度转换

RGB颜色模型是由红(Red)、绿(Green)、蓝(Blue)三种基色以不同的比例叠加而成;而且每个像素分量(R、G、B)的值分布在0—255范围内,三种基色以不同的比例混合,能够显示出2563种颜色。 在这个项目中ov5640采集的数据是16位rgb565的数据,首先扩展为rgb888,然后进行加权求和
在这里插入图片描述
如图所示,灰度转换的公式
在灰度转换过程中,可能会因为取整操作引入噪声,所以接下来使用高斯滤波算法来去除灰度转化过程中引入的噪声

2.高斯滤波

高斯滤波本质上是一种线性平滑滤波,即对整幅图像进行加权平均的过程,每一个像素点的值都是由其本身和邻域内的其他像素点加权平均后得到
高斯滤波的具体操作是使用一个N*N卷积模板对整幅图像扫描,用模板确定的邻域内的像素加权平均值代替模板中心像素点的值
在这里插入图片描述

其中,I(x,y)表示原图像中坐标为(x,y)的像素值;G(x,y)表示高斯滤波之后的值

3.二值化

二值化的作用是把灰度图像的像素值设置为0或者255,即纯黑或者纯白。通过二值图像,能更好地分析物体的形状和轮廓,有利于后续使用Sobel算子检测图像的边缘
二值化有多种方法,其中最常用的就是采用阈值法进行二值化

4.Sobel

Sobel算子主要用于检测图像边缘,在物体的边缘通常都有像素的变化,反映了物体与背景之间的差异,或者两个物体之间的差异。它是一个离散差分算子,用来计算像素点上下、左右领域内像素点的加权差,根据在边缘处达到极值来检测边缘
Sobel算子在水平方向和垂直方向各采用一个模板,检测各方向上的边缘,其优点是计算简单,速度快;但是对于纹理较为复杂的图像,检测效果不理想。水平方向模板Sx和垂直方向模板Sy如下
在这里插入图片描述

将两个算子与图像做平面卷积,即可得到水平方向与垂直方向的梯度值;若以I表示图像矩阵,Gx表示水平方向图像梯度值,Gy表示垂直方向的梯度值,则Gx与Gy可以表示如下:
在这里插入图片描述

二、项目框架

整个项目主要分为:
摄像头配置模块、图像处理模块、数据缓存模块、vga显示模块以及时钟管理模块
在这里插入图片描述

1.摄像头配置模块

摄像头配置模块负责配置摄像头各个参数,在摄像头上电后需要等待20ms。然后再通过I2C发送设备ID、写地址和数据,其中地址先发送高8位再发送低8位。这里包含摄像头时钟、图像大小、帧率以及其他和图像相关的参数,按照配置表中的参数,将摄像头配置为分辨率为1280*720像素点、RGB565数据格式、VGA时序输出;然后通过I2C协议将参数配置给摄像头的每个寄存器

2.图像处理模块

该模块完成图像数据的采集与处理;图像采集模块(capture)对摄像头输出的像素数据进行串并转换,然后给到后续的图像处理模块,依次进行灰度转换(rgb565_gray)、高斯滤(gs_filter)、二值化处理(gray_bin)、Sobel边缘检测(sobel)

3.数据缓存模块

通过乒乓缓存操作向SDRAM中读写图像数据,接口通过调用IP,主要是SDRAM读写控制逻辑(rw_control),使用两个异步FIFO跨时钟域数据处理,使用读写仲裁机制产生读写传输请求、地址等
为什么要用pp(乒乓)缓存?
如果不采用乒乓缓存,OV5640 帧率 30fps,VGA 帧率 60fps,如果摄像头输入的数据和VGA输出的数据都是连续不断的,那么刚好可以写一帧读两帧。但是一帧图像实际情况是一行行的生成和读取的,所以会出现 VGA 从SDRAM处读的上半帧是新帧,而由于SDRAM缓存的下半帧还没有被 OV5640写完,VGA 从SDRAM处读的下半帧还是旧帧,会出现错帧现象。采用乒乓缓存机制时,使用两个缓存区,写缓存区 1 时读缓存区 2,写缓存区 2 时读缓存区 1,每个缓存区存储完整的数据帧,读写隔离并且读写交替则不会出现错帧现象
为什么要读写仲裁?
仲裁:在FPGA中,当多个操作同时发出请求,容易导致操作冲突,因此我们需要根据相应的优先级来响应哪一个操作,这个过程就叫仲裁。在SDRAM中,初始化完成后,主要的功能就是突发写、突发读和自动刷新。如果同时发起写、读和刷新请求,就会出现操作冲突,从而导致SDRAM工作出错,因此这里就需要引入仲裁机制。为了简化设计,考虑将刷新与读写请求的仲裁分开考虑。由于刷新的优先级一定高于读写,因此,在底层接口中,只对读/写请求与刷新请求进行仲裁,即刷新请求的优先级一定高于读/写请求。在控制逻辑中,对读/写请求进行仲裁,保证底层接口不会同时收到读请求与写请求,从而避免底层接口中出现复杂控制

4.其它模块

vga模块就是通过vga协议将图像显示,这个非常简单,我之前的博客也写过关于vga的操作,这里就不在过多赘述
时钟管理模块则是通过pll生成时钟供SDRAM、vga、ov5640使用也没什么技术含量

三、部分代码

1.数据采集模块

`include "param.v"
module capture(input           clk     ,//像素时钟 摄像头输出的pclkinput           rst_n   ,input           enable  ,//采集使能 配置完成input           vsync   ,//摄像头场同步信号input           href    ,//摄像头行参考信号input   [7:0]   din     ,//摄像头像素字节output  [15:0]  dout    ,//像素数据output          dout_sop,//包文头 一帧图像第一个像素点output          dout_eop,//包文尾 一帧图像最后一个像素点output          dout_vld //像素数据有效
);//信号定义reg     [11:0]      cnt_h       ;wire                add_cnt_h   ;wire                end_cnt_h   ;reg     [9:0]       cnt_v       ;wire                add_cnt_v   ;wire                end_cnt_v   ;reg     [1:0]       vsync_r     ;//同步打拍wire                vsync_nedge ;//下降沿reg                 flag        ;//串并转换标志reg     [15:0]      data        ;reg                 data_vld    ;reg                 data_sop    ;reg                 data_eop    ;//计数器always @(posedge clk or negedge rst_n) begin if (rst_n==0) begincnt_h <= 0; endelse if(add_cnt_h) beginif(end_cnt_h)cnt_h <= 0; elsecnt_h <= cnt_h+1 ;endendassign add_cnt_h = flag & href;assign end_cnt_h = add_cnt_h  && cnt_h == (`H_AP << 1)-1;always @(posedge clk or negedge rst_n) begin if (rst_n==0) begincnt_v <= 0; endelse if(add_cnt_v) beginif(end_cnt_v)cnt_v <= 0; elsecnt_v <= cnt_v+1 ;endendassign add_cnt_v = end_cnt_h;assign end_cnt_v = add_cnt_v  && cnt_v == `V_AP-1 ;//vsync同步打拍always  @(posedge clk or negedge rst_n)beginif(~rst_n)beginvsync_r <= 2'b00;endelse beginvsync_r <= {vsync_r[0],vsync};endendassign vsync_nedge = vsync_r[1] & ~vsync_r[0];always  @(posedge clk or negedge rst_n)beginif(~rst_n)beginflag <= 1'b0;endelse if(enable & vsync_nedge)begin  //摄像头配置完成且场同步信号拉低之后开始采集有效数据flag <= 1'b1;endelse if(end_cnt_v)begin     //一帧数据采集完拉低flag <= 1'b0;   endend//dataalways  @(posedge clk or negedge rst_n)beginif(~rst_n)begindata <= 0;endelse begindata <= {data[7:0],din};//左移//data <= 16'b1101_1010_1111_0111;//16'hdaf7endend//data_sopalways  @(posedge clk or negedge rst_n)beginif(~rst_n)begindata_sop <= 1'b0;data_eop <= 1'b0;data_vld <= 1'b0;endelse begindata_sop <= add_cnt_h && cnt_h == 2-1 && cnt_v == 0;data_eop <= end_cnt_v;data_vld <= add_cnt_h && cnt_h[0] == 1'b1;endendassign dout = data;assign dout_sop = data_sop;assign dout_eop = data_eop;assign dout_vld = data_vld;endmodule 

2.读写控制模块

`include"param.v"
module sdram_ctrl (input               clk             ,input               clk_in          ,input               clk_out         ,input               rst_n           ,//数据输入input   [15:0]      din             ,//摄像头输入像素数据input               din_sop         ,input               din_eop         ,    input               din_vld         ,//数据输出input               rdreq           ,//vga的读数据请求output  [15:0]      dout            ,//输出给vga的数据output              dout_vld        ,//输出给vga的数据有效标志//sdram_interfaceoutput              avm_write       ,//输出给sdram 接口 IP 的写请求output              avm_read        ,//输出给sdram 接口 IP 的读请求output  [23:0]      avm_addr        ,//输出给sdram 接口 IP 的读写地址output  [15:0]      avm_wrdata      ,//输出给sdram 接口 IP 的写数据input   [15:0]      avs_rddata      ,//sdram 接口 IP 输入的读数据input               avs_rddata_vld  ,input               avs_waitrequest    
);//参数定义localparam  IDLE  = 4'b0001,WRITE = 4'b0010,READ  = 4'b0100,DONE  = 4'b1000;//信号定义reg     [3:0]       state_c     ;reg     [3:0]       state_n     ;reg     [8:0]       cnt         ;//突发读写计数器wire                add_cnt     ;wire                end_cnt     ;reg     [1:0]       wr_bank     ;//写bankreg     [1:0]       rd_bank     ;//读bankreg     [21:0]      wr_addr     ;//写地址   行地址 + 列地址wire                add_wr_addr ;wire                end_wr_addr ;reg     [21:0]      rd_addr     ;//读地址   行地址 + 列地址wire                add_rd_addr ;wire                end_rd_addr ;reg                 change_bank ;//切换bank reg                 wr_finish   ;//一帧数据写完reg     [1:0]       wr_finish_r ;//同步到写侧reg                 wr_data_flag;//wrfifo写数据的标志reg                 wr_flag     ;reg                 rd_flag     ;reg                 flag_sel    ;reg                 prior_flag  ;wire                idle2write  ;  wire                idle2read   ;wire                write2done  ;wire                read2done   ;reg     [15:0]      rd_data     ;//rfifo读数据输出reg                 rd_data_vld ;wire    [17:0]      wfifo_data  ; wire                wfifo_rdreq ;wire                wfifo_wrreq ;wire    [17:0]      wfifo_q     ;wire                wfifo_empty ;wire    [10:0]      wfifo_usedw ;wire                wfifo_full  ;wire    [15:0]      rfifo_data  ;wire                rfifo_rdreq ;wire                rfifo_wrreq ;wire    [15:0]      rfifo_q     ;wire                rfifo_empty ;wire                rfifo_full  ;wire    [10:0]      rfifo_usedw ;//状态机always  @(posedge clk or negedge rst_n)beginif(~rst_n)beginstate_c <= IDLE;endelse beginstate_c <= state_n;endendalways  @(*)begincase(state_c)IDLE  :begin if(idle2write)state_n = WRITE;else if(idle2read)state_n = READ;else state_n = state_c;end WRITE :begin if(write2done)state_n = DONE;else state_n = state_c;end     READ  :begin if(read2done)state_n = DONE;else state_n = state_c;end DONE  :state_n = IDLE;default:state_n = IDLE;endcase  endassign idle2write = state_c == IDLE  && (~prior_flag && wfifo_usedw >= `USER_BL);assign idle2read  = state_c == IDLE  && prior_flag && rfifo_usedw <= `RD_UT;assign write2done = state_c == WRITE && end_cnt;assign read2done  = state_c == READ  && end_cnt;//计数器always @(posedge clk or negedge rst_n)beginif(!rst_n)begincnt <= 0;endelse if(add_cnt)beginif(end_cnt)cnt <= 0;elsecnt <= cnt + 1;endendassign add_cnt = (state_c == WRITE | state_c == READ) & ~avs_waitrequest; assign end_cnt = add_cnt && cnt== `USER_BL-1;  /************************读写优先级仲裁*****************************/
//rd_flag     ;//读请求标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd_flag <= 0;end else if(rfifo_usedw <= `RD_LT)begin   rd_flag <= 1'b1;end else if(rfifo_usedw > `RD_UT)begin rd_flag <= 1'b0;end end//wr_flag     ;//写请求标志always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr_flag <= 0;end else if(wfifo_usedw >= `USER_BL)begin wr_flag <= 1'b1;end else begin wr_flag <= 1'b0;end end//flag_sel    ;//标记上一次操作always @(posedge clk or negedge rst_n)begin if(!rst_n)beginflag_sel <= 0;end else if(read2done)begin flag_sel <= 1;end else if(write2done)begin flag_sel <= 0;end end//prior_flag  ;//优先级标志 0:写优先级高   1:读优先级高     仲裁读、写的优先级always @(posedge clk or negedge rst_n)begin if(!rst_n)beginprior_flag <= 0;end else if(wr_flag && (flag_sel || (~flag_sel && ~rd_flag)))begin   //突发写优先级高prior_flag <= 1'b0;end else if(rd_flag && (~flag_sel || (flag_sel && ~wr_flag)))begin   //突发读优先级高prior_flag <= 1'b1;end end/******************************************************************/    /********************      地址设计    ****************************/    //wr_bank  rd_bankalways  @(posedge clk or negedge rst_n)beginif(~rst_n)beginwr_bank <= 2'b00;rd_bank <= 2'b11;endelse if(change_bank)beginwr_bank <= ~wr_bank;rd_bank <= ~rd_bank;endend// wr_addr   rd_addralways @(posedge clk or negedge rst_n) begin if (rst_n==0) beginwr_addr <= 0; endelse if(add_wr_addr) beginif(end_wr_addr)wr_addr <= 0; elsewr_addr <= wr_addr+1 ;endendassign add_wr_addr = (state_c == WRITE) && ~avs_waitrequest;assign end_wr_addr = add_wr_addr  && wr_addr == `BURST_MAX-1 ;always @(posedge clk or negedge rst_n) begin if (rst_n==0) beginrd_addr <= 0; endelse if(add_rd_addr) beginif(end_rd_addr)rd_addr <= 0; elserd_addr <= rd_addr+1 ;endendassign add_rd_addr = (state_c == READ) && ~avs_waitrequest;assign end_rd_addr = add_rd_addr  && rd_addr == `BURST_MAX-1;//wr_finish     一帧数据全部写到SDRAMalways  @(posedge clk or negedge rst_n)beginif(~rst_n)beginwr_finish <= 1'b0;endelse if(~wr_finish & wfifo_q[17])begin  //写完  从wrfifo读出eopwr_finish <= 1'b1;endelse if(wr_finish && end_rd_addr)begin  //读完wr_finish <= 1'b0;endend//change_bank ;//切换bank always  @(posedge clk or negedge rst_n)beginif(~rst_n)beginchange_bank <= 1'b0;endelse beginchange_bank <= wr_finish && end_rd_addr;endend/****************************************************************//*********************** wrfifo 写数据   ************************/
//控制像素数据帧 写入 或 丢帧always  @(posedge clk_in or negedge rst_n)beginif(~rst_n)beginwr_data_flag <= 1'b0;end else if(~wr_data_flag & ~wr_finish_r[1] & din_sop)begin//可以向wrfifo写数据wr_data_flag <= 1'b1;endelse if(/*wr_finish_r[1] && din_sop*/wr_data_flag & din_eop)begin//不可以向wrfifo写入数据wr_data_flag <= 1'b0;endendalways  @(posedge clk_in or negedge rst_n)begin //把wr_finish从wrfifo的读侧同步到写侧if(~rst_n)beginwr_finish_r <= 0;endelse beginwr_finish_r <= {wr_finish_r[0],wr_finish};endend/****************************************************************/always  @(posedge clk_out or negedge rst_n)beginif(~rst_n)beginrd_data <= 0;rd_data_vld <= 1'b0;endelse beginrd_data <= rfifo_q;rd_data_vld <= rfifo_rdreq;endendwrfifo	wrfifo_inst (.aclr   (~rst_n     ),.data   (wfifo_data ),.rdclk  (clk        ),.rdreq  (wfifo_rdreq),.wrclk  (clk_in     ),.wrreq  (wfifo_wrreq),.q      (wfifo_q    ),.rdempty(wfifo_empty),.rdusedw(wfifo_usedw),.wrfull (wfifo_full ));assign wfifo_data = {din_eop,din_sop,din};assign wfifo_wrreq = ~wfifo_full & din_vld & ((~wr_finish_r[1] & din_sop) ||wr_data_flag);assign wfifo_rdreq = state_c == WRITE && ~avs_waitrequest;rdfifo u_rdfifo(.aclr       (~rst_n     ),.data       (rfifo_data ),.rdclk      (clk_out    ),.rdreq      (rfifo_rdreq),.wrclk      (clk        ),.wrreq      (rfifo_wrreq),.q          (rfifo_q    ), .rdempty    (rfifo_empty),.wrfull     (rfifo_full ),.wrusedw    (rfifo_usedw)
);assign rfifo_data = avs_rddata;assign rfifo_wrreq = ~rfifo_full & avs_rddata_vld;assign rfifo_rdreq = ~rfifo_empty & rdreq;//输出assign dout       = rd_data;assign dout_vld   = rd_data_vld;assign avm_wrdata = wfifo_q[15:0];assign avm_write  = ~(state_c == WRITE && ~avs_waitrequest);assign avm_read   = ~(state_c == READ && ~avs_waitrequest);assign avm_addr   = (state_c == WRITE)?{wr_bank[1],wr_addr[21:9],wr_bank[0],wr_addr[8:0]}:((state_c == READ)?{rd_bank[1],rd_addr[21:9],rd_bank[0],rd_addr[8:0]}:0);endmodule 

四、参考

基于FPGA的图像实时采集

五、源码

https://github.com/IvanXiang/FPGA_COMS_SDRAM_VGA

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

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

相关文章

【Algorithm】Karatsuba Multiplications 乘法算法

Karatsuba Multiplications Q1&#xff1a; 请计算&#xff1a;x1234x1234x1234, y5678y5678y5678, x∗y?x*y?x∗y? 这个问题其实我们在三年级的时候就学过&#xff0c;用乘法竖式进行运算。但是有没有其他的方法&#xff0c;或者说&#xff0c;如果 x,yx,yx,y 非常大的时候…

drf 视图类 GenericAPIView 及扩展

drf 视图类 GenericAPIView 及扩展 文章目录drf 视图类 GenericAPIView 及扩展1、2个视图基类1.1、GenericAPIView&#xff1a;属性和方法1.2、基于APIView 写5个接口1.3、基于GenericAPIView写5个接口2、5个视图扩展类2.1 基于GenericAPIView5个视图扩展类写接口3、九个视图子…

【UCB操作系统CS162项目】Pintos Lab2:用户程序 User Programs(下)

在上节中&#xff0c;我们已经完成了 Lab 2 要求的参数传递和系统调用中的 halt, exit 以及向 stdout 输出的 write&#xff0c;最终停在了 wait 的实现之前。本节就先从 wait 和 exec 继续。 Syscall wait exec&#xff1a;实现父子进程 讲义中 wait 的要求是这样的&#x…

这几个文字翻译工具确定不试试看?

想问问大家平常会接触到TXT文件吗&#xff1f;这是微软在操作系统上附带的一种文本格式&#xff0c;主要是保存纯文字信息&#xff0c;像我们电脑上自带的记事本工具&#xff0c;就是使用这种文件格式。有时候我们需要将文本内容翻译成中文。那你知道如何实现TXT翻译成中文吗&a…

LRU缓存——哈希表+双向链表

一、题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; 1&#xff09;LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 2&#xff09;int get(int key) 如果关键字 key 存在于缓存中&#xff0c;…

STA系列 - 特殊时序分析multicycle/half-cycle/false path

文章目录什么是require time/arrive timeMulticycle PathHalf PathFalth Path本篇文章介绍的是特殊的时序path, 全文为视频笔记&#xff0c;以及自己的理解https://www.bilibili.com/video/BV1if4y1p7Dq?p10&vd_source84d1070e8334ce7e2bb0bd110abcf1a7什么是require time…

使用服务器跑模型——案例2

案例2 在本案例中我们使用vscode来上传/下载文件&#xff0c;服务器端编程和debug。 下载 vscode 在官网下载vscode正式版&#xff0c;别使用家庭版。下载地址https://code.visualstudio.com/Download。 使用 vscode 连接服务器 在vscode扩展中搜索ssh并下载安装。 安装成功…

【机器学习】熵权算法确定权重 原理+完整MATLAB代码+详细注释+操作实列

【机器学习】熵权算法确定权重 原理完整MATLAB代码详细注释操作实列 文章目录 1. 熵权法确定指标权重 &#xff08;1&#xff09;构造评价矩阵 Ymn &#xff08;2&#xff09;评价矩阵标准化处理 &#xff08;3&#xff09;计算指标信息熵值 Mj &#xff08;4&#xff09…

原生JS项目练习——验证码的生成及教验

一、主要功能介绍&#xff1a; 1、通过for循环生成生成六位随机验证码 2、通过for循环随机生成验证码颜色 3、窗口加载事件&#xff0c;窗口一加载就调用函数&#xff0c;重置验证码 4、按钮点击事件&#xff0c;一点击就调用函数&#xff0c;重置验证码 5、input输入框已失去焦…

Yarn概述

Hadoop系列 注&#xff1a;大家觉得博客好的话&#xff0c;别忘了点赞收藏呀&#xff0c;本人每周都会更新关于人工智能和大数据相关的内容&#xff0c;内容多为原创&#xff0c;Python Java Scala SQL 代码&#xff0c;CV NLP 推荐系统等&#xff0c;Spark Flink Kafka Hbase…

公众号网课搜题接口系统

公众号网课搜题接口系统 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;…

快速开发微信小程序之二-微信支付

一、背景 在面试程序员的时候&#xff0c;有两项经历会带来比较大的加分&#xff0c;第一你是否做过支付金融相关的业务&#xff0c;第二你是否写过底层框架中间件代码&#xff0c;今天我们聊一下微信支付是如何对接的。 二、相关概念 1、微信商户平台 要使用微信支付&#…

一、mini2440_bsp_led

一、芯片手册 1、板子原理图 2、GPIO使用 &#xff08;1&#xff09;GPxCON &#xff08;2&#xff09;GPxDAT 二、实现分析 1、初始化led 设置GPBCON&#xff08;0x56000010&#xff09;为 0x00015400 2、设置led输出&#xff0c;根据原理图引脚输出低电平时灯被点亮 LED1…

K8s-临时容器 Ephemeral Containers

临时容器 Ephemeral Containers 当由于容器崩溃或容器镜像不包含调试工具而导致 kubectl exec 无用时&#xff0c; 临时容器对于交互式故障排查很有用。尤其是&#xff0c;Distroless 镜像 允许用户部署最小的容器镜像&#xff0c;从而减少攻击面并减少故障和漏洞的暴露。 由于…

C | 枚举?看一遍就够了

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 啊我摔倒了..有没有人扶我起来学习.... 目录前言枚举1. 枚举的定义2. 枚举的内存大小3. 枚举的优势4. 枚举需要注意的地方前言 结构体、枚举、联合体都是自定义类型&#xff0c;结构体主要知识点结构体内存对齐可参考《C | …

九月SLAM相关论文速递

九月SLAM相关论文速递 论文列表DirectTracker: 3D Multi-Object Tracking Using Direct Image Alignment and Photometric Bundle Adjustment3D VSG: Long-term Semantic Scene Change Prediction through 3D Variable Scene GraphsLeveraging Large Language Models for Robo…

使用服务器跑模型——案例1

案例1 该方法mac&#xff0c;linux&#xff0c;windows都通用。我们使用terminal or cmd进行操作。 假设我们本地具有一个需要跑的模型Unet&#xff0c;我们需要将该模型上传到服务器上跑&#xff0c;步骤如下&#xff1a; 使用tar压缩文件 我们定位到我们需要压缩的模型&a…

云原生之容器编排实践-以k8s的Service方式暴露SpringBoot服务

背景 上一篇文章云原生之容器编排实践-SpringBoot应用以Deployment方式部署到minikube以及弹性伸缩中&#xff0c;我们通过 Deployment 完成了将 SpringBoot 应用部署到 minikube 并测试了其弹性伸缩的丝滑体验。但是 Deployment 部署后我们还面临以下问题&#xff1a; 访问时…

Day761.Redis集群方案:Codis -Redis 核心技术与实战

Redis集群方案&#xff1a;Codis Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于Redis集群方案&#xff1a;Codis Redis 的切片集群使用多个实例保存数据&#xff0c;能够很好地应对大数据量的场景。哨兵集群&#xff0c; Redis 官方提供的切片集群方案 Redis Clus…

SPI总线通信——基于STM32MP157A

SPI总线概念 SPI总线是Motorola首先提出的全双工三线/四线同步串行总线&#xff0c;采用主从模式&#xff08;Master Slave&#xff09;架构&#xff1b;支持多从机&#xff08;slave&#xff09;模式应用&#xff0c;一般仅支持单主机&#xff0c;多从机。 时钟由主机控制&…