|
本帖最后由 正点原子 于 2021-1-23 15:31 编辑
1)实验平台:正点原子达芬奇FPGA开发板
2) 章节摘自【正点原子】达芬奇之FPGA开发指南
3)购买链接:https://detail.tmall.com/item.htm?id=624335496505
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_dafenqi.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)对正点原子FPGA感兴趣的同学可以加群讨论:905624739 点击加入:
第四十七章基于OV5640的Sobel边缘检测实验
边缘检测是一种常用的图像分割技术,常用的边缘检测算子有Roberts Cross算子、Prewitt算子、Sobel算子和 Kirsch算子等。Sobel算子是根据像素点上下左右邻点灰度加权差在边缘处达到极值这一现象来检测边缘。其对噪声具有平滑作用,提供较为精确的边缘方向信息,当对精度要求不是很高时,是一种较为常用的边缘检测方法。在本章实验中将进行基于SOBEL算子的边缘检测实验。
本章包括以下几个部分:
4747.1简介
47.2实验任务
47.3硬件设计
47.4程序设计
47.5下载验证
47.1简介
图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出有意义目标的技术和过程。它是由图像处理到图像分析的关键步骤。现有的图像分割方法主要分以下几类:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法以及基于特定理论的分割方法等。从数学角度来看,图像分割是将数字图像划分成互不相交的区域的过程。图像分割的过程也是一个标记过程,即把属于同一区域的像素赋予相同的编号。
图像分割的一种重要方法就是边缘检测,即检测图像灰度级或者结构发生突变的像素点,表明一个区域的终结,也是另一个区域开始的地方。这种一副图像中灰度级或结构突变的像素点的集合称为边缘。不同的图像灰度变化不同,在边界处一般有明显的灰度变化,检测图像的灰度变化是一种常用的边缘检测方法。
图像的灰度值具有不连续性,图像局部的灰度突变可以用微分来检测,因为这种突变时间十分短促,因此一阶微分和二阶微分十分适合这种突变的检测。但使用二阶微分对噪声的响应更加强烈,其对图像的质量要求较高。
为了对有意义的边缘点进行分类,与这个点相联系的灰度级的变化必须比在这一点的背景上的变化更有效(灰度变化更剧烈)。由于本次实验用局部计算处理,因此决定一个值是否有效的方法就是设定一个阈值。当一个点的二维一阶导数(图像是一个二维函数)比指定阈值大,就认为这个点是一个边缘点。
一幅图像可以看做是一个二维函数,图像的的一阶导数可以用梯度表示(梯度的本意是一个向量(矢量),表示某一函数在某一点处的方向导数沿着该方向取得最大值。我们用∇f表示梯度,如下图所示为像素点(x,y)的梯度表达式:
图 47.1.1 点(x,y)处的梯度向量
∇f它指出了f(图像)在点(x,y)处最大变化率的方向。
向量∇f的大小(长度)表示为M(x,y),M(x,y)的表达式如下:
图 47.1.2 M(x,y)的表达式
它是梯度向量方向变化率的值。值得注意的是这些求和、平方及开平方都是阵列操作。
梯度的方向可以用图 47.1.3的公式来表示,它是以x轴为度量基准表示的,它与图像的边缘垂直。
图 47.1.3 梯度向量的方向
本次实验要计算梯度的大小,首先要计算梯度关于x和y方向的分量gy和gx,比较常用的计算梯度的分量的方法是使用一些空间域的模板。大家通常把用于计算梯度偏导数的滤波器模板称为梯度算子(也称为差分算子、边缘算子和边缘检测子),例如用于边缘检测的Sobel算子、Roberts算子和Prewitt算子等。如下图就是几种常用的边缘检测模板:
图 47.1.4 几种边缘检测算子
罗伯特交叉梯度算子是最早尝试具有对角优势的模板之一,它是一个2x2模板。2x2的模板在概念上很简单,但它是一个偶数模板,偶数模板对于中心点的确认很不便,因此一般情况下大家使用奇数的模板,最小的奇数模板是3x3的模板。这些奇数模板考虑了中心点对端数据的性质,并携带有关于边缘方向的更多信息,能够更好的表达图像的边缘。Sobel算子和Prewitt算子都是实际应用中常见的算子,但相比用Prewitt算子,Sobel算子具有更好的抑制噪声性能。下面给出使用Sobel算子计算梯度分量的算术表达式:
图 47.1.5 Sobel算子求取梯度分量
在这些公式中,3x3区域的第三行与第一行的差近似为x方向的偏导数,第三列与第一列的差近似为y方向的偏导数。上式用Verilog实现可以用下图的计算方法表示:
图 47.1.6 用Verilog对梯度分量的表示
在上图的算式中,gy1和gy3分别表示第一行和第三列行的值。gx1和gx3分别表示第一行列第三列的值。
在进行边缘检测时首先需要求出每一个像素在x和y方向的偏导数gy 和gx,再求出像素点的梯度大小M(x,y),然后把M(x,y)与本次实验设置的阈值进行比较,大于阈值则表示该像素点为边缘,反之,则表示该像素点不是边缘。
47.2实验任务
本次实验任务是通过摄像头采集的RGB565数据转化为Ycbcr数据(也可直接配置摄像头采集yuv数据),然后再进行灰度的Sobel边缘检测,最后在HDMI显示器上显示。
47.3硬件设计
本章节中硬件设计与“OV5640摄像头HDMI显示实验”完全相同,在此就不在赘述。
47.4程序设计
根据实验任务,首先设计如图 47.4.1所示的系统框图,本章实验的系统框架延续了“OV5640摄像头HDMI灰度显示实验”的整体架构。本次实验包括以下模块:时钟模块、图像分辨率设置模块、DDR控制器模块、摄像头驱动模块、图像处理模块和HDMI顶层模块。其中时钟模块、DDR控制器模块、HDMI顶层模块、图像分辨率设置模块和摄像头驱动模块没有做任何修改,这些模块在“OV5640摄像头HDMI显示实验”中已经说明过,这里不再详述,本次实验只对图像处理模块做了修改。
ov5640的sobel边沿检测实验系统框图如下图所示:
图 47.4.1 顶层系统框图
由上图可知,时钟模块(clk_wiz_0)为HDMI顶层模块、DDR控制模块以及OV5640驱动模块提供驱动时钟。OV5640驱动模块控制着传感器初始化的开始与结束,传感器初始化完成后将采集到的数据写入图像处理模块。图像处理模块将摄像头数据进行处理后存入DDR控制模块。顶层模块从DDR控制模块中读出数据并驱动显示器显示,这时整个系统才完成了数据的采集、缓存与显示。需要注意的是图像数据采集模块是在DDR3和传感器都初始化完成之后才开始输出数据的,避免了在DDR3初始化过程中向里面写入数据。
顶层模块的原理图如下图所示:
图 47.4.2 顶层模块原理图
FPGA顶层模块(ov5640_hdmi_sobel)例化了以下五个模块:时钟模块(clk_wiz_0)、OV5640驱动模块(ov5640_dri)、图像处理模块(vip)、DDR控制模块(ddr3_top)和HDMI顶层模块(hdmi_top)。
时钟模块(clk_wiz_0):时钟模块通过调用MMCM IP核实现,共输出4个时钟,频率分别为200Mhz(DDR3参考时钟)、50Mhz时钟、65Mhz时钟和325M时钟(HDMI像素时钟的5倍频)。200Mhz时钟作为DDR控制模块的参考时钟,由MIG IP核产生的ui_clk(本次设计为100Mhz)作为DDR控制模块的驱动时钟,50Mhz时钟作为OV5640驱动模块驱动时钟,65Mhz时钟和325M时钟(HDMI像素时钟的5倍频)负责驱动HDMI顶层模块。
OV5640驱动模块(ov5640_dri):OV5640驱动模块负责驱动OV5640 SCCB接口总线,将像素时钟驱动下的传感器输出的场同步信号、行同步信号以及8位数据转换成DDR读写控制模块的写使能信号和16位写数据信号,完成对OV5640传感器图像的采集。
图像处理模块(vip):对采集后的图像数据进行处理,并将处理后的数据存入DDR控制模块。
DDR控制模块(ddr3_top):DDR读写控制器模块负责驱动DDR片外存储器,缓存图像传感器输出的图像数据。该模块将MIG IP核复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。
有关DDR控制模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
HDMI顶层模块(hdmi_top):HDMI顶层模块负责驱动HDMI显示器的驱动信号的输出,同时为其他模块提供显示器参数、场同步信号和数据请求信号。关HDMI顶层模块的详细介绍请大家参考“OV5640摄像头HDMI显示实验”章节。
VIP模块框图如下图所示:
图 47.4.3 vip模块框图
vip模块例化了RGB转YCbCr模块(rgb2ycbcr)和sobel边缘检测模块(vip_sobel_edge_detector)。RGB转YCbCr模块负责将摄像头采集的RGB565格式数据到转换为YUV格式的数据。sobel边缘检测模块负责将YUV格式的视频图像进行边缘检测后输出。有关RGB转YCbCr模块的详细介绍请大家参考“OV5640摄像头HDMI灰度显示实验”章节。
vip模块原理图如下图所示:
图 47.4.4 vip模块原理图
如上图所示,摄像头采集到16位rgb565输入vip模块,经过“rgb2ycbcr”模块转化为8位的yuv444数据,然后在将转化后的灰度数据(img_y)作为“vip_sobel_edge_detector”模块的输入,对灰度进行边缘检测处理,最后输出处理后的灰度数据“post_img_bit”。
图像处理模块负责图像数据的格式转换,代码如下:
- 1 module vip(
- 2 //module clock
- 3 input clk , // 时钟信号
- 4 input rst_n , // 复位信号(低有效)
- 5
- 6 //图像处理前的数据接口
- 7 input pre_frame_vsync,
- 8 input pre_frame_hsync,
- 9 input pre_frame_de ,
- 10 input [15:0] pre_rgb ,
- 11 input [10:0] xpos ,
- 12 input [10:0] ypos ,
- 13
- 14 //图像处理后的数据接口
- 15 output post_frame_vsync, // 场同步信号
- 16 output post_frame_hsync, // 行同步信号
- 17 output post_frame_de , // 数据输入使能
- 18 output [15:0] post_rgb // RGB565颜色数据
- 19 );
- 20
- 21 parameter SOBEL_THRESHOLD = 128; //sobel阈值
- 22
- 23 //wire define
- 24 wire [ 7:0] img_y;
- 25 wire [ 7:0] post_img_y;
- 26 wire [15:0] post_rgb;
- 27 wire post_frame_vsync;
- 28 wire post_frame_hsync;
- 29 wire post_frame_de;
- 30 wire pe_frame_vsync;
- 31 wire pe_frame_href;
- 32 wire pe_frame_clken;
- 33 wire ycbcr_vsync;
- 34 wire ycbcr_hsync;
- 35 wire ycbcr_de;
- 36 wire post_img_bit;
- 37 //*****************************************************
- 38 //** main code
- 39 //*****************************************************
- 40
- 41 assign post_rgb = {16{~post_img_bit}};
- 42
- 43 //RGB转YCbCr模块
- 44 rgb2ycbcr u_rgb2ycbcr(
- 45 //module clock
- 46 .clk (clk ), // 时钟信号
- 47 .rst_n (rst_n ), // 复位信号(低有效)
- 48 //图像处理前的数据接口
- 49 .pre_frame_vsync (pre_frame_vsync), // vsync信号
- 50 .pre_frame_hsync (pre_frame_hsync), // href信号
- 51 .pre_frame_de (pre_frame_de ), // data enable信号
- 52 .img_red (pre_rgb[15:11] ),
- 53 .img_green (pre_rgb[10:5 ] ),
- 54 .img_blue (pre_rgb[ 4:0 ] ),
- 55 //图像处理后的数据接口
- 56 .post_frame_vsync(pe_frame_vsync), // vsync信号
- 57 .post_frame_hsync(pe_frame_href), // href信号
- 58 .post_frame_de (pe_frame_clken), // data enable信号
- 59 .img_y (img_y), //灰度数据
- 60 .img_cb (),
- 61 .img_cr ()
- 62 );
- 63
- 64 vip_sobel_edge_detector
- 65 #(
- 66 .SOBEL_THRESHOLD (SOBEL_THRESHOLD) //sobel阈值
- 67 )
- 68 u_vip_sobel_edge_detector(
- 69 .clk (clk),
- 70 .rst_n (rst_n),
- 71
- 72 //处理前数据
- 73 .per_frame_vsync (pe_frame_vsync), //处理前帧有效信号
- 74 .per_frame_href (pe_frame_href), //处理前行有效信号
- 75 .per_frame_clken (pe_frame_clken), //处理前图像使能信号
- 76 .per_img_y (img_y), //处理前输入灰度数据
- 77
- 78 //处理后的数据
- 79 .post_frame_vsync (post_frame_vsync), //处理后帧有效信号
- 80 .post_frame_href (post_frame_hsync), //处理后行有效信号
- 81 .post_frame_clken (post_frame_de), //输出使能信号
- 82 .post_img_bit (post_img_bit) //输出像素
- 83
- 84 );
- 85 endmodule
复制代码
代码的第21行表示对边缘检测的阈值的设定,本次实验设定的值为256级灰度的中间值128。
代码的第41行表示对边缘检测后的1bit数据进行位拼接,形成16bit的RGB565格式的数据输出,这里将信号post_img_bit取反,是为了在显示器上将边缘显示为黑色,底色为白色。
代码的第44行至62行是对灰度转换模块的例化,在该模块以摄像头采集的16位RGB565红、绿、蓝三原色数据作为输入数据,通过算法实现RGB到YCbCr的转换,并输出8位灰度数据,并输出数据输出使能信号。有关RGB转YCbCr模块的详细介绍请大家参考“OV5640摄像头HDMI灰度显示实验”章节。
代码的第64行至84行是对sobel边缘检测模块的例化,前面已经介绍过Sobel算子是3x3的模板,因此在实现边缘检测时也需要生成3x3的阵列,有关3x3阵列的生成在“基于OV5640的中值滤波实验”有过介绍,在此就不再赘述。
sobel边缘检测模块如下:
- 1 module vip_sobel_edge_detector
- 2 #(
- 3 parameter SOBEL_THRESHOLD = 128 //Sobel 阈值
- 4 )
- 5 (
- 6 input clk, //cmos 像素时钟
- 7 input rst_n,
- 8 //处理前数据
- 9 input per_frame_vsync,
- 10 input per_frame_href,
- 11 input per_frame_clken,
- 12 input [7:0] per_img_y,
- 13 //处理后的数据
- 14 output post_frame_vsync,
- 15 output post_frame_href,
- 16 output post_frame_clken,
- 17 output post_img_bit
- 18 );
- 19 //reg define
- 20 reg [9:0] gx_temp2; //第三列值
- 21 reg [9:0] gx_temp1; //第一列值
- 22 reg [9:0] gx_data; //x方向的偏导数
- 23 reg [9:0] gy_temp1; //第一行值
- 24 reg [9:0] gy_temp2; //第三行值
- 25 reg [9:0] gy_data; //y方向的偏导数
- 26 reg [20:0] gxy_square;
- 27 reg [15:0] per_frame_vsync_r;
- 28 reg [15:0] per_frame_href_r;
- 29 reg [15:0] per_frame_clken_r;
- 30
- 31 //wire define
- 32 wire matrix_frame_vsync;
- 33 wire matrix_frame_href;
- 34 wire matrix_frame_clken;
- 35 wire [10:0] dim;
- 36 //输出3X3 矩阵
- 37 wire [7:0] matrix_p11;
- 38 wire [7:0] matrix_p12;
- 39 wire [7:0] matrix_p13;
- 40 wire [7:0] matrix_p21;
- 41 wire [7:0] matrix_p22;
- 42 wire [7:0] matrix_p23;
- 43 wire [7:0] matrix_p31;
- 44 wire [7:0] matrix_p32;
- 45 wire [7:0] matrix_p33;
- 46
- 47 //*****************************************************
- 48 //** main code
- 49 //*****************************************************
- 50
- 51 assign post_frame_vsync = per_frame_vsync_r[10];
- 52 assign post_frame_href = per_frame_href_r[10] ;
- 53 assign post_frame_clken = per_frame_clken_r[10];
- 54 assign post_img_bit = post_frame_href ? post_img_bit_r : 1'b0;
- 55
- 56 //3x3矩阵
- 57 vip_matrix_generate_3x3_8bit u_vip_matrix_generate_3x3_8bit(
- 58 .clk (clk),
- 59 .rst_n (rst_n),
- 60 //预处理数据
- 61 .per_frame_vsync (per_frame_vsync),
- 62 .per_frame_href (per_frame_href),
- 63 .per_frame_clken (per_frame_clken),
- 64 .per_img_y (per_img_y),
- 65
- 66 //处理后的数据
- 67 .matrix_frame_vsync (matrix_frame_vsync),
- 68 .matrix_frame_href (matrix_frame_href),
- 69 .matrix_frame_clken (matrix_frame_clken),
- 70 .matrix_p11 (matrix_p11),
- 71 .matrix_p12 (matrix_p12),
- 72 .matrix_p13 (matrix_p13), //输出 3X3 矩阵
- 73 .matrix_p21 (matrix_p21),
- 74 .matrix_p22 (matrix_p22),
- 75 .matrix_p23 (matrix_p23),
- 76 .matrix_p31 (matrix_p31),
- 77 .matrix_p32 (matrix_p32),
- 78 .matrix_p33 (matrix_p33)
- 79 );
- 80
- 81 //Sobel 算子
- 82 // gx gy 像素点
- 83 // [ -1 0 +1 ] [ +1 +2 +1 ] [ P11 P12 P13 ]
- 84 // [ -2 0 +2 ] [ 0 0 0 ] [ P21 P22 P23 ]
- 85 // [ -1 0 +1 ] [ -1 -2 -1 ] [ P31 P32 P33 ]
- 86
- 87 //Step 1 计算x方向的偏导数
- 88 always@(posedge clk or negedge rst_n)begin
- 89 if(!rst_n)begin
- 90 gy_temp1 <= 10'd0;
- 91 gy_temp2 <= 10'd0;
- 92 gy_data <= 10'd0;
- 93 end
- 94 else begin
- 95 gy_temp1 <= matrix_p13 + (matrix_p23 << 1) + matrix_p33;
- 96 gy_temp2 <= matrix_p11 + (matrix_p21 << 1) + matrix_p31;
- 97 gy_data <= (gy_temp1 >= gy_temp2) ? gy_temp1 - gy_temp2 :
- 98 (gy_temp2 - gy_temp1);
- 99 end
- 100 end
- 101
- 102 //Step 2 计算y方向的偏导数
- 103 always@(posedge clk or negedge rst_n)begin
- 104 if(!rst_n)begin
- 105 gx_temp1 <= 10'd0;
- 106 gx_temp2 <= 10'd0;
- 107 gx_data <= 10'd0;
- 108 end
- 109 else begin
- 110 gx_temp1 <= matrix_p11 + (matrix_p12 << 1) + matrix_p13;
- 111 gx_temp2 <= matrix_p31 + (matrix_p32 << 1) + matrix_p33;
- 112 gx_data <= (gx_temp1 >= gx_temp2) ? gx_temp1 - gx_temp2 :
- 113 (gx_temp2 - gx_temp1);
- 114 end
- 115 end
- 116
- 117 //Step 3 计算平方和
- 118 always@(posedge clk or negedge rst_n)begin
- 119 if(!rst_n)
- 120 gxy_square <= 21'd0;
- 121 else
- 122 gxy_square <= gx_data * gx_data + gy_data * gy_data;
- 123 end
- 124
- 125 //Step 4 开平方(梯度向量的大小)
- 126 cordic u_cordic(
- 127 .aclk (clk),
- 128 .s_axis_cartesian_tvalid (1'b1),
- 129 .s_axis_cartesian_tdata (gxy_square),
- 130 .m_axis_dout_tvalid (),
- 131 . m_axis_dout_tdata (dim)
- 132 );
- 133
- 134 //Step 5 将开平方后的数据与预设阈值比较
- 135 reg post_img_bit_r;
- 136 always@(posedge clk or negedge rst_n)begin
- 137 if(!rst_n)
- 138 post_img_bit_r <= 1'b0; //初始值
- 139 else if(dim >= SOBEL_THRESHOLD)
- 140 post_img_bit_r <= 1'b1; //检测到边缘1
- 141 else
- 142 post_img_bit_r <= 1'b0; //不是边缘 0
- 143 end
- 144
- 145 //延迟5个周期同步
- 146 always@(posedge clk or negedge rst_n)begin
- 147 if(!rst_n)begin
- 148 per_frame_vsync_r <= 0;
- 149 per_frame_href_r <= 0;
- 150 per_frame_clken_r <= 0;
- 151 end
- 152 else begin
- 153 per_frame_vsync_r <= {per_frame_vsync_r[14:0],matrix_frame_vsync};
- 154 per_frame_href_r <= {per_frame_href_r[14:0],matrix_frame_href};
- 155 per_frame_clken_r <= {per_frame_clken_r[14:0],matrix_frame_clken};
- 156 end
- 157 end
- 158
- 159 endmodule
复制代码
在上述代码中,首先求x、y方向的偏导数,如代码第88至115行;在代码第118至123行,计算了偏导数的平方和;代码第126行至132行,对上一步计算的平方和进行开平方,所得的值就是梯度向量的大小,在此处调用了开方函数,稍后会展示关于开方函数IP的配置界面;最后将开方所得的值与预设阈值进行比较,若大于阈值则post_img_bit_r赋为1,表示该像素点是边缘像素,否则赋为0,表示该像素点不是边缘像素,如代码第135行至143行;前面step1到5一共消耗了11个时钟周期,因此需要对post_frame_vsync、post_frame_href 和post_frame_clken延迟11个时钟周期进行同步,如代码第146行至157行。
有关阈值的设置,本实验中设为128,如顶层代码第3行所示。理论上讲阈值可以为0到255中的任意值(灰度值为0到255),但实际上,阈值过小或过大都会影响实验结果。阈值过大会导致边缘间断;阈值过小,会导致伪边缘。
关于开方函数IP的调用,先在搜索框输入“cordic”,选择“cordic”,如下图所示:
图 47.4.5 选择“CORDIC”
双击选项,进入配置界面,如下图:
图 47.4.6 配置界面1
Functional Selection(功能选择):可用的功能选择包括旋转(Rotate)、正弦函数(Sin)、余弦函数(Cos)、反正切函数(ArcTan)、平方根(Square Root)、平移(Translate)、双曲正弦函数(Sinh)、双曲余弦函数(Cosh)和双曲反正切函数(ArcTanh)。本次实验用到的是平方根,所以在“Functional Selection”选项中选择平方根(Square Root)。
Architectural Configuration(架构配置):这个选项在功能选择为平方根的时候是不可选的状态,这个选项不用管它。
Pipelining Mode(流水线模式):流水线模式有3种模式可供选择,分别为No Pipelining(无流水)、Optimal(最佳模式)、Maximum(最大限度)。本次实验选择Optimal(最佳模式)。
Data Format(数据格式):数据格式有两种,分别是Signed Fraction(有符号分数)和Unsigned Fraction(无符号分数)。本次实验不需要带符号运算,所以选Unsigned Fraction(无符号分数)。
Phase Format(相位格式):这个选项在功能选择为平方根的时候是不可选的状态,这个选项不用管它。
Input Width(输入位宽):本次实验的数据的输入位宽设为21bit。
Output Width(输出位宽):本次实验的数据的输出位宽设为11bit。
Round Mode(舍位模式):数据格式有四种,分别是Truncate(缩短模式)、Positive Infinity(正无穷大模式)、Pos Neg Infinity(负无穷大模式)和Nearest Even(近似值模式)。本次实验选择Nearest Even(近似值模式)。
Advanced Configuration Parameters(高级配置参数):这个选项在功能选择为平方根的时候是不可选的状态,这个选项不用管它。
图 47.4.7 配置界面2
上图所示的选项卡为AXI总线的配置,本次实验不需要用到AXI总线,所以不用配置。点击“OK”,这样就完成了开方函数的配置。
47.5下载验证
编译完工程之后就可以开始下载程序了。将OV5640摄像头模块插在达芬奇开发板的“OLED/CAMERA”插座上,并将HDMI电缆一端连接到开发板上的HDMI_B插座、另一端连接到显示器。将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,下载完成后观察HDMI显示器显示图案。如下图所示:
图 47.5.1 HDMI实时显示边缘检测图像
|
阿莫论坛20周年了!感谢大家的支持与爱护!!
月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
|