用户名  找回密码
 立即注册
查看: 399|回复: 22

2024嵌入式FPGA竞赛国特-最佳创意奖-红外瞳孔追踪系统(教学向)续

[复制链接]

2

主题

13

回帖

68

积分

少年

积分
68
发表于 2025-3-18 17:54:40 | 显示全部楼层 |阅读模式
本帖最后由 Even 于 2025-3-18 18:11 编辑

2.VIP_multi_target_detect(⭐)
        此代码是我从大磊视频中的代码修改而来,下面我将简单讲解,想了解代码细节推荐点击之前给的链接看看原视频,大磊老师讲的非常详细形象。
        该模块用于获取 二值化得出的亮斑 的边界:target_pos_out,注意:边界由43位组成:{Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}Flag位为标志位,代表该边界是否有效,后续为下、右、上、左四个边界,所有操作在一帧内完成,也就是一个vs周期内。众所周知,人有两个眼睛,所以在一般情况下,二值化输出的是两个相隔一段距离的亮斑区域——白像素之间间隔在MIN_DIST以内的白像素集,MIN_DIST自由设定。该模块我就直接设定为输出两个亮斑边界。此处祭出本人帅照以示说明,箭头所指即为暗瞳效应产生的亮斑区域:

首先,per_frame_clken 拉高后,每个时钟x_cnt自增,到达一行像素后,x_cnt清零,y_cnt自增,由此即对每个有效像素进行了坐标标记。

      再看130行处,通过投票机制判定二值化白像素是新的亮斑区域还是落在之前亮斑区域之内的像素。target_flag用于标记亮斑区域,当target_flag[0] == 0时,证明暂未出现亮斑区域;target_flag[1] == 0时,证明暂未出现第二个亮斑区域。[1:0]new_target_flag是两个投票箱,对应两个投票区域。打个比方,在一片1280*720平米的空地上,将要按照从左到右,从上到下的顺序一颗一颗栽种一种根系范围是方形的树,树占地1平米,根系占地4*MIN_DIST²米,树可能种活也可能死,且当一棵活树在另外一棵活树的根系范围之内时,二者根系结合形成一个种群,当栽种成功两个种群时即完成指标,剩下未在根系范围内的树不再考虑。活树——亮点,死树——暗点,种群——亮斑区域。
此刻,可能有人问了:“你二值化代码这么简单,怎么保证亮点就是暗瞳效应产生的呢?有没有改进方法?”

        有的,兄弟,有的。我们先考虑相对常见的问题:摄像头坏点——腐蚀处理;红外光强过弱导致无亮斑——见下文;红外光强过强导致一大片亮斑——见下文;鼻尖反光干扰——模块从左到右,从上到下,抓取到两个亮斑区域即止,一般人鼻子在两个眼睛下方,是抓不到的;眼睛上方背景光源干扰——见下文。

        那么就有人要问了:“我有三只眼睛怎么办,你这垃圾代码不废了吗?有没有改进方法?”

        没有,兄弟,抱歉。本眼动作品暂不支持多人运动以及外星人。若急需请赞助经费,标注外星人,我将在后续开展外星人专属业务。

代码超字数见后续

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 17:55:36 | 显示全部楼层
  1. module VIP_multi_target_detect
  2. (       
  3.     input                                 clk,
  4.     input                                 rst_n,
  5.     input                                 per_frame_vsync,
  6.     input                                 per_frame_hs,
  7.     input                                 per_frame_clken,
  8.     input                                 per_img_Bit,     //white
  9.     output reg         [42:0]         target_pos_out1, // {Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}
  10.     output reg         [42:0]         target_pos_out2,
  11.        
  12.     input                   [ 9:0]         MIN_DIST         //min domain
  13. );

  14. //720p
  15. parameter        [10:0] IMG_HDISP = 11'd1280;
  16. parameter        [9:0]  IMG_VDISP = 10'd720 ;

  17. //lag 1 clocks signal sync
  18. reg         per_frame_vsync_r;
  19. reg         per_frame_hs_r   ;
  20. reg         per_frame_clken_r;
  21. reg         per_img_Bit_r    ;

  22. always@(posedge clk or negedge rst_n)begin
  23.     if(!rst_n)begin
  24.         per_frame_vsync_r         <= 0;
  25.         per_frame_hs_r                 <= 0;
  26.         per_frame_clken_r         <= 0;
  27.         per_img_Bit_r                 <= 0;
  28.     end
  29.         else begin
  30.                 per_frame_vsync_r          <= per_frame_vsync ;
  31.                 per_frame_hs_r          <= per_frame_hs    ;
  32.                 per_frame_clken_r          <= per_frame_clken ;
  33.                 per_img_Bit_r                  <= per_img_Bit     ;
  34.         end
  35. end

  36. wire vsync_pos_flag;//rising edge of vs
  37. wire vsync_neg_flag;//falling edge if vs

  38. assign vsync_pos_flag = per_frame_vsync & (!per_frame_vsync_r);
  39. assign vsync_neg_flag = !(per_frame_vsync) & per_frame_vsync_r;

  40. //
  41. //count the input pixel of v/h to get v/h coordinates

  42. reg [10:0] x_cnt;
  43. reg [9:0] y_cnt;

  44. always@(posedge clk or negedge rst_n) begin
  45.     if(!rst_n) begin
  46.         x_cnt <= 11'd0;
  47.         y_cnt <= 10'd0;
  48.     end
  49.     else if(!per_frame_vsync) begin
  50.         x_cnt <= 11'd0;
  51.         y_cnt <= 10'd0;
  52.     end
  53.     else if(per_frame_clken) begin
  54.                 if(x_cnt < IMG_HDISP - 1) begin
  55.             x_cnt <= x_cnt + 1'b1;
  56.             y_cnt <= y_cnt;
  57.                 end
  58.                 else begin
  59.                         x_cnt <= 11'd0;
  60.                         y_cnt <= y_cnt + 1'b1;
  61.                  end
  62.     end
  63.         else begin
  64.                 x_cnt <= 11'd0;
  65.                 y_cnt <= y_cnt;
  66.         end
  67. end


  68. // lag 1 clocks signal sync
  69. reg [10:0] x_cnt_r;
  70. reg [9:0] y_cnt_r;

  71. always @(posedge clk or negedge rst_n) begin
  72.     if (!rst_n)
  73.         x_cnt_r <= 11'd0;
  74.     else
  75.         x_cnt_r <= x_cnt;
  76. end

  77. always @(posedge clk or negedge rst_n) begin
  78.     if (!rst_n)
  79.         y_cnt_r <= 10'd0;
  80.     else
  81.         y_cnt_r <= y_cnt;
  82. end

  83. // reg the boundaries of each moving object
  84. reg [42:0] target_pos1;
  85. reg [42:0] target_pos2;

  86. // valid mark
  87. wire [1:0]target_flag;

  88. // left/right/up/down fields for each target
  89. wire [10:0] target_left1         ;
  90. wire [10:0] target_right1         ;
  91. wire [9:0] target_top1                 ;
  92. wire [9:0] target_bottom1         ;

  93. wire [10:0] target_left2         ;
  94. wire [10:0] target_right2         ;
  95. wire [9:0] target_top2                ;
  96. wire [9:0] target_bottom2         ;


  97. assign target_flag[0]         =         target_pos1[42];

  98. assign target_bottom1         =         (target_pos1[41:32] < IMG_VDISP-1         - MIN_DIST ) ? (target_pos1[41:32]        +MIN_DIST) : IMG_VDISP-1;
  99. assign target_right1         =         (target_pos1[31:21] < IMG_HDISP-1         - MIN_DIST ) ? (target_pos1[31:21]        +MIN_DIST) : IMG_HDISP-1;
  100. assign target_top1           =         (target_pos1[20:11] > 10'd0                 + MIN_DIST ) ? (target_pos1[20:11]        -MIN_DIST) : 10'd0;
  101. assign target_left1                =        (target_pos1[10: 0] > 11'd0                 + MIN_DIST ) ? (target_pos1[10: 0]        -MIN_DIST) : 11'd0;

  102. assign target_flag[1]         =         target_pos2[42];

  103. assign target_bottom2         =         (target_pos2[41:32] < IMG_VDISP-1         - MIN_DIST ) ? (target_pos2[41:32]        +MIN_DIST) : IMG_VDISP-1;
  104. assign target_right2         =         (target_pos2[31:21] < IMG_HDISP-1         - MIN_DIST ) ? (target_pos2[31:21]        +MIN_DIST) : IMG_HDISP-1;
  105. assign target_top2           =         (target_pos2[20:11] > 10'd0                 + MIN_DIST ) ? (target_pos2[20:11]        -MIN_DIST) : 10'd0;
  106. assign target_left2                =        (target_pos2[10: 0] > 11'd0                 + MIN_DIST ) ? (target_pos2[10: 0]        -MIN_DIST) : 11'd0;


  107. reg  target_cnt;           
  108. reg [1:0] new_target_flag; //ballot box

  109. always @(posedge clk or negedge rst_n) begin
  110.     if (!rst_n) begin
  111.         target_pos1 <= {1'b0, 10'd0, 11'd0, 10'd0, 11'd0};
  112.         target_pos2 <= {1'b0, 10'd0, 11'd0, 10'd0, 11'd0};
  113.         new_target_flag <= 2'd0;
  114.         target_cnt <= 1'd0;
  115.     end
  116.    
  117.     // initialize
  118.     else if(vsync_pos_flag) begin
  119.         target_pos1 <= {1'b0, 10'd0, 11'd0, 10'd0, 11'd0};
  120.         target_pos2 <= {1'b0, 10'd0, 11'd0, 10'd0, 11'd0};
  121.                 new_target_flag <= 2'd0;
  122.                 target_cnt <= 1'd0;
  123.     end
  124.     else begin
  125.         // first clk,judge new target/target in domain
  126.         if(per_frame_clken && per_img_Bit ) begin
  127.                         if(target_flag[0] == 1'b0)                        // if reg flag0 invalid,vote the bit as a new target
  128.                                 new_target_flag[0] <= 1'b1;
  129.                         else begin                                                        // if reg flag0 valid,judge whether the target is in domain
  130.                                 if((x_cnt < target_left1 || x_cnt > target_right1 || y_cnt < target_top1 || y_cnt > target_bottom1))        //if out of domain,vote the bit as a new target
  131.                                         new_target_flag[0] <= 1'b1;
  132.                                 else
  133.                                         new_target_flag[0] <= 1'b0;               
  134.                     end
  135.                        
  136.                         if(target_flag[1] == 1'b0)                    // same        as flag0
  137.                                 new_target_flag[1] <= 1'b1;
  138.                         else begin                                                       
  139.                                 if((x_cnt < target_left2 || x_cnt > target_right2 || y_cnt < target_top2 || y_cnt > target_bottom2))       
  140.                                         new_target_flag[1] <= 1'b1;
  141.                                 else
  142.                                         new_target_flag[1] <= 1'b0;               
  143.                     end
  144.         end
  145.         else begin
  146.                         new_target_flag <= 2'b0;
  147.         end

  148.                
  149.         // second clk,according to the vote,update target
  150.         if(per_frame_clken_r && per_img_Bit_r) begin
  151.                         if(new_target_flag == 2'b11) begin         // unanimous vote,new target appear
  152.                                 if(target_cnt == 1'b0)begin
  153.                                         target_cnt <=1'd1;
  154.                                         target_pos1 <= {1'b1, y_cnt_r, x_cnt_r, y_cnt_r, x_cnt_r};
  155.                                 end                               
  156.                                 else if(target_cnt == 1'b1 && target_pos2[42] != 1'b1 && (x_cnt_r < target_left1 || x_cnt_r > target_right1 || y_cnt_r < target_top1 || y_cnt_r > target_bottom1))begin
  157.                                         target_pos2 <= {1'b1, y_cnt_r, x_cnt_r, y_cnt_r, x_cnt_r};
  158.                                         target_cnt <=1'd1;
  159.                                 end
  160.                         end
  161.                        
  162.                         else if (new_target_flag > 2'd0 && new_target_flag != 2'b11) begin // target in domain
  163.                                 if(new_target_flag[0] == 1'b0) begin //  flag0 == 0, target in domain1
  164.                                
  165.                                         target_pos1[42] <= 1'b1;

  166.                                         if(x_cnt_r < target_pos1[10: 0])         // expand boundary
  167.                                                 target_pos1[10: 0] <= x_cnt_r;
  168.                                         if(x_cnt_r > target_pos1[31:21])        
  169.                                                 target_pos1[31:21] <= x_cnt_r;
  170.                                         if(y_cnt_r < target_pos1[20:11])        
  171.                                                 target_pos1[20:11] <= y_cnt_r;
  172.                                         if(y_cnt_r > target_pos1[41:32])        
  173.                                                 target_pos1[41:32] <= y_cnt_r;
  174.                                 end
  175.                                 else if(new_target_flag[1] == 1'b0) begin // flag1 == 0, target in domain2
  176.                                
  177.                                         target_pos2[42] <= 1'b1;

  178.                                         if(x_cnt_r < target_pos2[10: 0])        
  179.                                                 target_pos2[10: 0] <= x_cnt_r;
  180.                                         if(x_cnt_r > target_pos2[31:21])        
  181.                                                 target_pos2[31:21] <= x_cnt_r;
  182.                                         if(y_cnt_r < target_pos2[20:11])        
  183.                                                 target_pos2[20:11] <= y_cnt_r;
  184.                                         if(y_cnt_r > target_pos2[41:32])        
  185.                                                 target_pos2[41:32] <= y_cnt_r;
  186.                                 end
  187.                         end
  188.                 end
  189.         end
  190. end

  191. //reg output after a frame

  192. always @(posedge clk or negedge rst_n)
  193.         if(!rst_n) begin
  194.                 target_pos_out1 <= {1'd0,10'd0,11'd0,10'd0,11'd0};
  195.                 target_pos_out2 <= {1'd0,10'd0,11'd0,10'd0,11'd0};               
  196.     end
  197.     else if(vsync_neg_flag)         begin
  198.                 target_pos_out1 <= target_pos1;
  199.                 target_pos_out2 <= target_pos2;
  200.     end


  201. endmodule
复制代码

2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 17:59:10 | 显示全部楼层
突然发现好像可以回复直接发帖)(狗头),那就直接在这继续发了

2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:01:11 | 显示全部楼层
3.VIP_multi_target_detect_black

在已经标定亮斑区域之后,我们便可以进一步在亮斑附近标定瞳孔(红框部分):



       相对于上一个多目标追踪的代码,标定瞳孔的单目标追踪代码就简单很多了,只需要例化该模块两次,分别将左右眼亮斑接入target_pos_in即可。不同的是,该模块的per_img_Bit是通过二值化筛选出足够黑的部分(代码类似,自行修改),够黑则拉高。而vsync_neg_flag用于表示一帧的结束,也就代表着模块数据处理完毕,用于各模块协调。
       flag_black用于标定当前像素输入否已经在亮斑的某个区域范围之内(根据实际补光灯与人眼的相对位置调节参数),当per_frame_clken(像素时序),per_img_Bit(黑色瞳孔),flag_black(像素范围)同时满足时,当前像素即为组成黑色瞳孔的像素,即可根据当前像素坐标拓展框定范围,并在一帧结束后作为瞳孔坐标信息target_pos_out输出给后续画框模块处理。
       这样也就在一定程度上解决了眼睛上方背景光源干扰的问题,因为光干扰一般是一片较亮的区域,二值化后周围小范围内不会存在足够黑到per_img_Bit拉高的程度,干扰也就在该模块被阻断了。
  1. module VIP_multi_target_detect_black
  2. (
  3.         input clk,
  4.         input rst_n,
  5.         input per_frame_vsync,
  6.         input per_frame_clken,
  7.         input per_img_Bit,                //balck
  8.         input            [42:0]         target_pos_in,//{Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}
  9.         output reg         [42:0]         target_pos_out,//{Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}
  10.         output                                vsync_neg_flag //mark the ending of a frame
  11. );

  12. parameter        [10:0] IMG_HDISP = 11'd1280;
  13. parameter        [9:0]  IMG_VDISP = 10'd720;

  14. reg         per_frame_vsync_r;

  15. always@(posedge clk or negedge rst_n)
  16. begin
  17.     if(!rst_n)
  18.                 per_frame_vsync_r         <= 0;
  19.         else        
  20.                 per_frame_vsync_r          <= per_frame_vsync ;
  21. end

  22. wire vsync_neg_flag;//falling edge

  23. assign vsync_neg_flag = !(per_frame_vsync) & per_frame_vsync_r;

  24. reg [10:0] x_cnt;
  25. reg [9:0] y_cnt;

  26. reg [9:0] up_reg ;
  27. reg [9:0] down_reg ;
  28. reg [10:0] left_reg ;
  29. reg [10:0] right_reg;
  30. reg flag_reg;

  31. //count the input pixel of v/h to get v/h coordinates
  32. always@(posedge clk or negedge rst_n)
  33. begin
  34.     if(!rst_n) begin
  35.         x_cnt <= 11'd0;
  36.         y_cnt <= 10'd0;
  37.     end
  38.     else if(!per_frame_vsync) begin
  39.         x_cnt <= 11'd0;
  40.         y_cnt <= 10'd0;
  41.     end
  42.     else if(per_frame_clken) begin
  43.         if(x_cnt < IMG_HDISP - 1) begin
  44.             x_cnt <= x_cnt + 1'b1;
  45.             y_cnt <= y_cnt;
  46.         end
  47.         else begin
  48.             x_cnt <= 11'd0;
  49.             y_cnt <= y_cnt + 1'b1;
  50.         end
  51.     end
  52. end

  53. //mark the area from target_pos_in
  54. reg flag_black;

  55. always@(posedge clk or negedge rst_n)
  56.         if(!rst_n)
  57.                 flag_black <= 1'b0;
  58.         else if(!per_frame_vsync)
  59.                 flag_black <= 1'b0;
  60.         else if(target_pos_in[42] && per_frame_clken && y_cnt < target_pos_in[41:32] + 5'd20 && x_cnt < target_pos_in[31:21] + 5'd20 && y_cnt > target_pos_in[20:11] - 6'd32 && x_cnt > target_pos_in[10:0] - 5'd20)
  61.                 flag_black <= 1'b1;
  62.         else
  63.                 flag_black <= 1'b0;


  64. //mark pupil
  65. always@(posedge clk or negedge rst_n) begin
  66.     if(!rst_n) begin
  67.         up_reg <= target_pos_in[41:32] + 5'd20;
  68.         down_reg <= 10'd0;
  69.         left_reg <= target_pos_in[31:21] + 5'd20;
  70.         right_reg <= 10'd0;
  71.         flag_reg <= 1'b0;
  72.     end
  73.     else if(!per_frame_vsync)begin
  74.         up_reg <= target_pos_in[41:32] + 5'd20;
  75.         down_reg <= 10'd0;
  76.         left_reg <= target_pos_in[31:21] + 5'd20;
  77.         right_reg <= 11'd0;
  78.         flag_reg <= 1'b0;
  79.     end
  80.     else if (per_frame_clken && per_img_Bit && flag_black) begin
  81.                 flag_reg <= 1'b1;

  82.                 if (x_cnt < left_reg)
  83.                         left_reg <= x_cnt;
  84.                 else
  85.                         left_reg <= left_reg;

  86.                 if (x_cnt > right_reg)
  87.                         right_reg <= x_cnt;
  88.                 else
  89.                         right_reg <= right_reg;

  90.                 if (y_cnt < up_reg)
  91.                         up_reg <= y_cnt;
  92.                 else
  93.                         up_reg <= up_reg;

  94.                 if (y_cnt > down_reg)
  95.                         down_reg <= y_cnt;
  96.                 else
  97.                         down_reg <= down_reg;
  98.         end
  99. end

  100.        
  101. always @(posedge clk or negedge rst_n) begin
  102.     if (!rst_n) begin
  103.         target_pos_out <= {1'd0,10'd0,11'd0,10'd0,11'd0};
  104.     end
  105.         else if (vsync_neg_flag) begin
  106.         target_pos_out <= {flag_reg,down_reg,right_reg,up_reg,left_reg};
  107.     end
  108. end

  109. endmodule
复制代码




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:05:06 | 显示全部楼层
4.VIP_Video_add_rectangular
        该模块为实时画框模块,视频中呈现的瞳孔框,定位框(locater),视线追踪框(sight frame),人员标记(person number)都由该模块在原视频上叠加红框实现。此处代码基本逻辑在大磊的视频里同样解释了,再次推荐观看。各框效果如下图:

       模块per_img_red/green/blue为图片实时像素,由于红外窄带滤波灰度摄像头采集到信号为raw8格式,所以本项目中三者都为8位灰度值。此处target_pos_output为前模块输出的两个瞳孔坐标。rx_person为队友做的AI人脸识别,据此信号判断人员编号。flag_rst信号为定位框的重置信号,该信号产生模块见下文,信号用于重置与当前瞳孔位置比较的定位框位置。sit为模块判定人眼移动的方向,作为输出信号用于控制外设舵机、云台等。
       模块269行之前都为准备 框的坐标,实际画框部分从269行开始。我首先解释画框部分,以((x_cnt >   rectangular_left1) && (x_cnt <   rectangular_right1) && ((y_cnt ==   rectangular_up1) || (y_cnt ==   rectangular_down1)) && rectangular_flag1)这段用于画上下边框的或条件之一为例,当四个条件同时满足时,输出纯红像素作为上下框边界。rectangular_flag1——框坐标是否有效;x_cnt >   rectangular_left1——当前像素在左边界右;x_cnt >   rectangular_right1——当前像素在右边界左;(y_cnt ==   rectangular_up1) || (y_cnt ==   rectangular_down1)——当前像素坐标等于上/下边界。其余或条件同理。
       114行开始,解释了如何重置定位框——外界输入的flag_rst信号(可自由设定触发源,本项目用眨眼和外界按钮,会在后续功能模块说明),当其拉高时,将当前瞳孔坐标作为新的定位框坐标。之后,将定位框x/y方向坐标和rec_x/y_sum分别与瞳孔当前x/y方向坐标和x/y_sum相减取绝对值和正负号,即可进行眼动八角定位 :

如图黑实线为可判定的八个方向,灰虚线为方向区域范围边界,通过比较 x差值与二分之一 y(移位实现)差值,y 差值与二分之一 x 差值,以及差值正负关系,即可划分八个区域。同时使用sit将眼动方向传递至模块外以控制外设;并且根据方向的不同,控制视线追踪框rec_eye的边界定速增加或减少,以实现框随视线移动的直观效果。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×

2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:07:14 | 显示全部楼层
  1. module VIP_Video_add_rectangular (
  2.     input       clk,      
  3.     input       rst_n,   
  4.        
  5.         input       per_frame_vsync,
  6.         input       per_frame_hs,
  7.         input       per_frame_clken,
  8.         input [7:0]      per_img_red,
  9.         input [7:0]      per_img_green,
  10.         input [7:0]      per_img_blue,
  11.     input [42:0]         target_pos_out1,// {Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}
  12.     input [42:0]         target_pos_out2,
  13.         input [3:0]     rx_person,      //person
  14.     output reg post_frame_vsync,   
  15.     output reg post_frame_hs,     
  16.     output reg post_frame_clken,   
  17.     output reg [7:0] post_img_red,  
  18.     output reg [7:0] post_img_green,
  19.     output reg [7:0] post_img_blue,
  20.        
  21.         input                  flag_rst,           //rst the locater flag
  22.        
  23.         output  [3:0]     sit           //eye direction
  24. );

  25. //1280*720 resolution
  26. parameter [10:0] IMG_HDISP = 11'd1280;
  27. parameter [9:0] IMG_VDISP = 10'd720;
  28.        
  29. wire [9:0]         rectangular_up1;           
  30. wire [9:0]         rectangular_up2;
  31. wire [9:0]         rectangular_down1;           
  32. wire [9:0]         rectangular_down2;
  33. wire [10:0] rectangular_left1;           
  34. wire [10:0] rectangular_left2;
  35. wire [10:0] rectangular_right1;               
  36. wire [10:0] rectangular_right2;

  37. wire               rectangular_flag1;                //flag whether there is a moving target
  38. wire               rectangular_flag2;


  39. assign rectangular_flag1         =         target_pos_out1[42];
  40. assign rectangular_down1         =         target_pos_out1[41:32];
  41. assign rectangular_right1         =         target_pos_out1[31:21];
  42. assign rectangular_up1                 =         target_pos_out1[20:11];
  43. assign rectangular_left1        =         target_pos_out1[10:0];       

  44. assign rectangular_flag2         =         target_pos_out2[42];
  45. assign rectangular_down2         =         target_pos_out2[41:32];
  46. assign rectangular_right2         =         target_pos_out2[31:21];
  47. assign rectangular_up2                 =         target_pos_out2[20:11];
  48. assign rectangular_left2        =         target_pos_out2[10:0];               

  49.        
  50. reg [10:0] x_cnt;
  51. reg [9:0] y_cnt;


  52. always @(posedge clk or negedge rst_n) begin
  53.     if(!rst_n)begin
  54.                 x_cnt <= 11'd0;
  55.                 y_cnt <= 10'd0;
  56.         end
  57.         else begin
  58.                 if(!per_frame_vsync)begin
  59.                         x_cnt <= 11'd0;
  60.                         y_cnt <= 10'd0;
  61.                 end
  62.                 else if(per_frame_clken) begin
  63.                         if(x_cnt < IMG_HDISP - 1) begin
  64.                 x_cnt <= x_cnt + 1'b1;
  65.                 y_cnt <= y_cnt;
  66.                         end
  67.                         else begin
  68.                 x_cnt <= 11'd0;
  69.                 y_cnt <= y_cnt + 1'b1;
  70.             end
  71.                 end
  72.                 else begin
  73.                 x_cnt <= 11'd0;
  74.                 y_cnt <= y_cnt;
  75.                 end
  76.         end               
  77. end

  78. //sum of x/y
  79. wire [12:0]x_sum;
  80. wire [11:0]y_sum;
  81. assign         x_sum = (rectangular_flag1 && rectangular_flag2) ? (rectangular_right1 + rectangular_right2 + rectangular_left1 + rectangular_left2):1'b0;
  82. assign         y_sum = (rectangular_flag1 && rectangular_flag2) ? (rectangular_up1 + rectangular_up2 + rectangular_down1 + rectangular_down2):1'b0;



  83. //locater
  84. wire [9:0]         rectangular_up3;           
  85. wire [9:0]         rectangular_up4;
  86. wire [9:0]         rectangular_down3;           
  87. wire [9:0]         rectangular_down4;
  88. wire [10:0] rectangular_left3;           
  89. wire [10:0] rectangular_left4;
  90. wire [10:0] rectangular_right3;               
  91. wire [10:0] rectangular_right4;

  92. reg [41:0]rec_left  = 42'b0101000000_00111011011_0100110000_00111000110;// {Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}
  93. reg [41:0]rec_right = 42'b0101000000_01011011011_0100110000_01011000110;// {Flag,ymax[41:32],xmax[31:21],ymin[20:11],xmin[10:0]}

  94. //rst locater
  95. always @(posedge clk or negedge rst_n)
  96.         if(!rst_n)begin
  97.                 rec_left  = 42'b0101000000_00111011011_0100110000_00111000110;
  98.                 rec_right = 42'b0101000000_01011011011_0100110000_01011000110;
  99.         end
  100.         else if(flag_rst && rectangular_flag1 && rectangular_flag2)begin
  101.                 rec_left  = target_pos_out1[41:0];
  102.                 rec_right = target_pos_out2[41:0];
  103.         end


  104. wire [11:0]rec_y_sum;
  105. wire [12:0]rec_x_sum;

  106. assign rec_x_sum = (rectangular_flag1 && rectangular_flag2) ? (rectangular_right3 + rectangular_right4 + rectangular_left3 + rectangular_left4):1'b0;
  107. assign rec_y_sum = (rectangular_flag1 && rectangular_flag2) ? (rectangular_up3 + rectangular_up4 + rectangular_down3 + rectangular_down4):1'b0;

  108. assign rectangular_down3         =         rec_left[41:32];
  109. assign rectangular_right3         =         rec_left[31:21];
  110. assign rectangular_up3                 =         rec_left[20:11];
  111. assign rectangular_left3        =         rec_left[10:0];       

  112. assign rectangular_down4         =         rec_right[41:32];
  113. assign rectangular_right4         =         rec_right[31:21];
  114. assign rectangular_up4                 =         rec_right[20:11];
  115. assign rectangular_left4        =         rec_right[10:0];


  116. //output eye direction
  117. reg right;
  118. reg left;
  119. reg down;
  120. reg up;
  121. wire [3:0]        sit;

  122. //judge sight direction(now-locater)
  123. wire sign_x;
  124. wire sign_y;
  125. wire [10:0]sub_x;
  126. wire [9:0]sub_y;

  127. assign sub_x = (x_sum > rec_x_sum) ? (x_sum - rec_x_sum) : (rec_x_sum - x_sum);
  128. assign sub_y = (y_sum > rec_y_sum) ? (y_sum - rec_y_sum) : (rec_y_sum - y_sum);

  129. assign sign_x = (x_sum > rec_x_sum) ? 1'b1 : 1'b0;
  130. assign sign_y = (y_sum > rec_y_sum) ? 1'b1 : 1'b0;

  131. wire h;
  132. wire v;
  133. wire h_v;

  134. assign h   = ((sub_x >> 1) >= sub_y) ? 1'b1 : 1'b0;
  135. assign v   = ((sub_y >> 1) >= sub_x) ? 1'b1 : 1'b0;
  136. assign h_v = (((sub_y >> 1) < sub_x) && ((sub_x >> 1) < sub_y)) ? 1'b1 : 1'b0;

  137. //sight frame
  138. reg  [41:0]rec_eye = 41'b0101100000_01011011011_0100010000_00111000110;
  139. always @(posedge clk or negedge rst_n)
  140.         if(!rst_n)
  141.                 rec_eye = 41'b0101100000_01011011011_0100010000_00111000110;
  142.         else if((x_cnt == IMG_HDISP - 2'b10) && (y_cnt == IMG_VDISP - 2'b10) && rectangular_flag1 && rectangular_flag2)begin
  143.                 if(h && sign_x && rec_eye[31:21] < IMG_HDISP)begin                        //right
  144.                         rec_eye[31:21] <= rec_eye[31:21] + 2'b10;
  145.                         rec_eye[10:0]  <= rec_eye[10:0] + 2'b10;
  146.                         right <= 1'b1;
  147.                         left  <= 1'b0;
  148.                         down  <= 1'b0;
  149.                         up    <= 1'b0;                       
  150.                 end
  151.                 else if(h && !sign_x && rec_eye[10:0] >= 1'b1)begin                        //left
  152.                         rec_eye[31:21] <= rec_eye[31:21] - 2'b10;
  153.                         rec_eye[10:0]  <= rec_eye[10:0] - 2'b10;       
  154.                         right <= 1'b0;
  155.                         left  <= 1'b1;
  156.                         down  <= 1'b0;
  157.                         up    <= 1'b0;                       
  158.                 end
  159.                 else if(v && sign_y && rec_eye[41:32] < IMG_VDISP)begin                //down
  160.                         rec_eye[41:32] <= rec_eye[41:32] + 2'b10;
  161.                         rec_eye[20:11] <= rec_eye[20:11] + 2'b10;
  162.                         right <= 1'b0;
  163.                         left  <= 1'b0;
  164.                         down  <= 1'b1;
  165.                         up    <= 1'b0;
  166.                 end
  167.                 else if(v && !sign_y && rec_eye[20:11] >= 1'b1)begin            //up
  168.                         rec_eye[41:32] <= rec_eye[41:32] - 2'b10;
  169.                         rec_eye[20:11] <= rec_eye[20:11] - 2'b10;
  170.                         right <= 1'b0;
  171.                         left  <= 1'b0;
  172.                         down  <= 1'b0;
  173.                         up    <= 1'b1;
  174.                 end
  175.                 else if(h_v && sign_x && sign_y && rec_eye[31:21] < IMG_HDISP && rec_eye[41:32] < IMG_VDISP)begin        //right_down
  176.                         rec_eye[31:21] <= rec_eye[31:21] + 2'b10;
  177.                         rec_eye[10:0]  <= rec_eye[10:0] + 2'b10;
  178.                         rec_eye[41:32] <= rec_eye[41:32] + 2'b10;
  179.                         rec_eye[20:11] <= rec_eye[20:11] + 2'b10;
  180.                         right <= 1'b1;
  181.                         left  <= 1'b0;
  182.                         down  <= 1'b1;
  183.                         up    <= 1'b0;                       
  184.                 end
  185.                 else if(h_v && !sign_x && sign_y && rec_eye[10:0] >= 1'b1 && rec_eye[41:32] < IMG_VDISP)begin                //left_down
  186.                         rec_eye[31:21] <= rec_eye[31:21] - 2'b10;
  187.                         rec_eye[10:0]  <= rec_eye[10:0] - 2'b10;
  188.                         rec_eye[41:32] <= rec_eye[41:32] + 2'b10;
  189.                         rec_eye[20:11] <= rec_eye[20:11] + 2'b10;
  190.                         right <= 1'b0;
  191.                         left  <= 1'b1;
  192.                         down  <= 1'b1;
  193.                         up    <= 1'b0;                       
  194.                 end
  195.                 else if(h_v && !sign_y && sign_x && rec_eye[31:21] < IMG_HDISP && rec_eye[20:11] >= 1'b1)begin        //right_up
  196.                         rec_eye[31:21] <= rec_eye[31:21] + 2'b10;
  197.                         rec_eye[10:0]  <= rec_eye[10:0] + 2'b10;
  198.                         rec_eye[41:32] <= rec_eye[41:32] - 2'b10;
  199.                         rec_eye[20:11] <= rec_eye[20:11] - 2'b10;
  200.                         right <= 1'b1;
  201.                         left  <= 1'b0;
  202.                         down  <= 1'b0;
  203.                         up    <= 1'b1;
  204.                 end
  205.                 else if(h_v && !sign_y && !sign_x && rec_eye[10:0] >= 1'b1 && rec_eye[20:11] >= 1'b1)begin                //left_up
  206.                         rec_eye[31:21] <= rec_eye[31:21] - 2'b10;
  207.                         rec_eye[10:0]  <= rec_eye[10:0] - 2'b10;
  208.                         rec_eye[41:32] <= rec_eye[41:32] - 2'b10;
  209.                         rec_eye[20:11] <= rec_eye[20:11] - 2'b10;
  210.                         right <= 1'b0;
  211.                         left  <= 1'b1;
  212.                         down  <= 1'b0;
  213.                         up    <= 1'b1;
  214.                 end       
  215.         end


  216. assign sit = {up, down, left, right};

  217. wire [9:0]         rectangular_up5;
  218. wire [9:0]         rectangular_down5;
  219. wire [10:0] rectangular_left5;
  220. wire [10:0] rectangular_right5;
  221.                
  222. assign rectangular_down5         =         rec_eye[41:32];
  223. assign rectangular_right5         =         rec_eye[31:21];
  224. assign rectangular_up5                 =         rec_eye[20:11];
  225. assign rectangular_left5        =         rec_eye[10:0];
复制代码


2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:07:34 | 显示全部楼层



  1. //draw       

  2. always @(posedge clk or negedge rst_n) begin
  3.         if(!rst_n) begin
  4.                 post_frame_vsync <= 1'd0;
  5.                 post_frame_hs  <= 1'd0;
  6.                 post_frame_clken <= 1'd0;
  7.                 post_img_red     <= 8'd0;
  8.                 post_img_green   <= 8'd0;
  9.                 post_img_blue    <= 8'd0;
  10.         end
  11.         else begin
  12.                 post_frame_vsync <= per_frame_vsync;
  13.                 post_frame_hs <= per_frame_hs;
  14.                 post_frame_clken <= per_frame_clken;
  15.                 if(post_frame_clken) begin
  16.                         if(((x_cnt >   rectangular_left1) && (x_cnt <   rectangular_right1) && ((y_cnt ==   rectangular_up1) || (y_cnt ==   rectangular_down1)) && rectangular_flag1) ||
  17.                         ((x_cnt >   rectangular_left2) && (x_cnt <   rectangular_right2) && ((y_cnt ==   rectangular_up2) || (y_cnt ==   rectangular_down2)) && rectangular_flag2) ||
  18.                         ((x_cnt >   rectangular_left3) && (x_cnt <   rectangular_right3) && ((y_cnt ==   rectangular_up3) || (y_cnt ==   rectangular_down3))) ||
  19.                         ((x_cnt >   rectangular_left4) && (x_cnt <   rectangular_right4) && ((y_cnt ==   rectangular_up4) || (y_cnt ==   rectangular_down4))) ||
  20.                         ((x_cnt >   rectangular_left5) && (x_cnt <   rectangular_right5) && ((y_cnt ==   rectangular_up5) || (y_cnt ==   rectangular_down5))) ||
  21.                         ((x_cnt >   rectangular_left3) && (x_cnt <   rectangular_left3 + 4'd10) && ((y_cnt == rectangular_up3 - 4'd4) || (y_cnt ==   rectangular_up3 - 5'd8) || (y_cnt ==   rectangular_up3 - 5'd1))
  22.                         && rx_person == 4'b0010)||
  23.                         ((x_cnt >   rectangular_left3) && (x_cnt <   rectangular_left3 + 4'd10) && ((y_cnt == rectangular_up3 - 4'd4) || (y_cnt ==   rectangular_up3 - 5'd8))
  24.                         && rx_person == 4'b0100)||
  25.                         ((x_cnt >   rectangular_left3) && (x_cnt <   rectangular_left3 + 4'd10) && ((y_cnt == rectangular_up3 - 4'd4))
  26.                         && rx_person == 4'b1000))begin
  27.                         //draw up and down
  28.                                 post_img_red         <= 8'd255;
  29.                                 post_img_green         <= 8'd0;
  30.                                 post_img_blue         <= 8'd0;
  31.                         end
  32.                         else if(((y_cnt >  rectangular_up1) && (y_cnt <   rectangular_down1) && ((x_cnt ==   rectangular_left1) || (x_cnt ==   rectangular_right1)) && rectangular_flag1)||
  33.                                    ((y_cnt >   rectangular_up2) && (y_cnt <   rectangular_down2) && ((x_cnt ==   rectangular_left2) || (x_cnt ==   rectangular_right2)) && rectangular_flag2) ||
  34.                                    ((y_cnt >   rectangular_up3) && (y_cnt <   rectangular_down3) && ((x_cnt ==   rectangular_left3) || (x_cnt ==   rectangular_right3)))||
  35.                                    ((y_cnt >   rectangular_up4) && (y_cnt <   rectangular_down4) && ((x_cnt ==   rectangular_left4) || (x_cnt ==   rectangular_right4)))||
  36.                                    ((y_cnt >   rectangular_up5) && (y_cnt <   rectangular_down5) && ((x_cnt ==   rectangular_left5) || (x_cnt ==   rectangular_right5))))begin
  37.                                    //draw left and right
  38.                                 post_img_red         <= 8'd255;
  39.                                 post_img_green         <= 8'd0;
  40.                                 post_img_blue         <= 8'd0;
  41.                         end
  42.                         else begin
  43.                                 post_img_red         <= per_img_red ;
  44.                                 post_img_green         <= per_img_green;
  45.                                 post_img_blue         <= per_img_blue ;
  46.                         end
  47.         end
  48.                 else begin
  49.                         post_img_red         <= per_img_red ;
  50.                         post_img_green         <= per_img_green;
  51.                         post_img_blue         <= per_img_blue ;
  52.                 end
  53.     end               
  54. end

  55. endmodule
复制代码

2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:08:32 | 显示全部楼层
四、功能模块说明
1、rec_rst
        该模块利用双目信号的捕获情况,判定是否刻意眨眼,以控制flag_rst信号重置定位框,flag12为模块VIP_multi_target_detect_black输出的target_pos_out[42],若flag1&&flag2 == 1,代表两眼信号都稳定。此处我编写了状态机以判断人是否刻意眨眼。概括来说就是稳定睁眼——稳定闭眼——稳定睁眼的过程,具体时间修改参数可调。

        IDLE:初始态,用于flag_rst信号的置零。

        S1:    双目都捕获时每帧对cnt_neg_p计数。视频是60Hz,也就是说当双目都捕获持续大约两秒后,若双目都丢失,则跳转至S2,同时cnt_neg_p清零。这是一个从睁眼到闭眼的过程。

        S2:    注意,该状态使用cnt_neg_n在双目都丢失时计数。为避免信号波动或自然眨眼影响,设定为双目都丢失1秒左右后,若再次捕获到任意信号,判定为睁眼,跳转到S3。大于半秒,小于1秒的时间内捕获信号,则判定为干扰,返回S1态。

        S3:    当双目再次被持续捕捉一秒左右,跳转至S4转态。

        S4:    回归IDLE,同时拉高flag_rst代表刻意眨眼过程完成,重置定位框。
  1. module rec_rst
  2. (       
  3.     input                                 clk,
  4.     input                                 rst_n,
  5.     input                                 flag1,
  6.     input                                 flag2,
  7.     input                                 v_neg,    //falling edge
  8.     output reg                          flag_rst
  9. );

  10. parameter IDLE         = 5'b00001;
  11. parameter S1         = 5'b00010; //visibility
  12. parameter S2         = 5'b00100; //lost
  13. parameter S3         = 5'b01000; //appear
  14. parameter S4         = 5'b10000; //output rst


  15. reg  [4:0]   curr_st     ;     
  16. reg  [4:0]   next_st     ;     

  17. //Excitation signal generation
  18. reg [7:0]        cnt_neg_p;
  19. reg [7:0]        cnt_neg_n;

  20. always @(posedge clk or negedge rst_n)
  21.         if(!rst_n || curr_st == IDLE || curr_st == S2 || (curr_st == S3 && !flag1 && !flag2))
  22.                 cnt_neg_p <= 1'b0;
  23.         else if(cnt_neg_p >= 8'd128)
  24.                 cnt_neg_p <= cnt_neg_p;
  25.         else if(flag1 && flag2 && v_neg)
  26.                 cnt_neg_p <= cnt_neg_p + 1'b1;

  27. always @(posedge clk or negedge rst_n)
  28.         if(!rst_n || curr_st == IDLE || curr_st == S1 || flag1 || flag2)
  29.                 cnt_neg_n <= 1'b0;
  30.         else if(cnt_neg_n >= 8'd128)
  31.                 cnt_neg_n <= cnt_neg_n;               
  32.         else if(!flag1 && !flag2 && v_neg && curr_st == S2)
  33.                 cnt_neg_n <= cnt_neg_n + 1'b1;

  34. always @(posedge clk or negedge rst_n)
  35.         if(!rst_n)
  36.                 curr_st <= IDLE;
  37.         else
  38.                 curr_st <= next_st;


  39. always @(curr_st)begin
  40.         case(curr_st)
  41.                 IDLE: begin
  42.                                 next_st <= S1;
  43.                                 flag_rst <= 1'b0;
  44.                           end
  45.                 S1        : if(cnt_neg_p >= 8'd128 && !flag1 && !flag2)
  46.                                 next_st <= S2;
  47.                           else
  48.                                 next_st <= S1;
  49.                                
  50.                 S2        : if(cnt_neg_n >= 8'd64 && (flag1 || flag2))
  51.                                 next_st <= S3;
  52.                           else if((flag1 || flag2) && cnt_neg_n >= 8'd32)
  53.                                 next_st <= S1;
  54.                           else
  55.                                 next_st <= S2;
  56.                                
  57.                 S3        : if(cnt_neg_p >= 7'd64 && flag1 && flag2)
  58.                                 next_st <= S4;
  59.                           else
  60.                                 next_st <= S3;

  61.                 S4        : if(flag1 && flag2)begin
  62.                                 next_st <= IDLE;
  63.                                 flag_rst <= 1'b1;
  64.                           end
  65.                           else
  66.                                 next_st <= S4;
  67.                 default : next_st <= IDLE;
  68.         endcase
  69. end


  70. endmodule
复制代码


2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:09:18 | 显示全部楼层
2、cnt_all
        此模块通过对一帧内所有有效像素的灰度值求和,与设定阈值对比,判断需要调高还是调低亮度,通过FPGA调控输出PWM波至外部硬件电路控制红外灯的亮度。模块相当简单,但是效果很不错,解决了很多问题。
        luminance为八位灰度图像数据,cmp为比较结果,再输入PWM模块调节PWM占空比。请根据实际环境调节代码末尾阈值上下限。
  1. module cnt_all
  2. (   
  3.         input               clk             ,   
  4.     input               rst_n           ,   
  5.    
  6.     input               per_frame_vsync     ,   
  7.     input               ycbcr_de        ,   // en
  8.     input   [7:0]       luminance       ,
  9.     output reg [1:0]   cmp    // 00 IDLE;10 exceed;01 below;11 ok
  10. );

  11. reg    per_frame_vsync_r;
  12. wire   vsync_pos_flag;//rising edge
  13. wire   vsync_neg_flag;//falling edge

  14. assign vsync_pos_flag = per_frame_vsync & (!per_frame_vsync_r);
  15. assign vsync_neg_flag = !(per_frame_vsync) & per_frame_vsync_r;

  16. reg   [27:0] cnt_fin;
  17. reg   [27:0] cnt;


  18. always @(posedge clk or negedge rst_n) begin
  19.     if(!rst_n)
  20.         cnt <= 1'b0;
  21.     else if(ycbcr_de)begin  
  22.         cnt <= cnt + luminance;
  23.         end               
  24.     else if(vsync_pos_flag)
  25.         cnt <= 1'b0;
  26. end

  27. //delay
  28. always@(posedge clk or negedge rst_n) begin
  29.     if(!rst_n) begin
  30.         per_frame_vsync_r <= 1'd0;
  31.     end
  32.     else begin
  33.         per_frame_vsync_r <= per_frame_vsync;
  34.     end
  35. end



  36. always @(posedge clk or negedge rst_n)
  37.         if(!rst_n) begin
  38.                 cnt_fin <= 1'b0;
  39.     end
  40.     else if(vsync_neg_flag)         begin //reg cnt after a frame
  41.                 cnt_fin <= cnt;
  42.     end

  43. always @(posedge clk or negedge rst_n)
  44.         if(!rst_n) begin
  45.                 cmp <= 2'b0;
  46.     end
  47.     else if(cnt_fin > 28'h2f00000)         begin
  48.                 cmp <= 2'b10;
  49.     end
  50.     else if(cnt_fin < 28'h2800000)         begin
  51.                 cmp <= 2'b01;
  52.     end
  53.     else if(cnt_fin > 28'h2800000 && cnt_fin < 28'h2f00000)         begin
  54.                 cmp <= 2'b11;
  55.     end

  56. endmodule
复制代码


2

主题

13

回帖

68

积分

少年

积分
68
 楼主| 发表于 2025-3-18 18:10:47 | 显示全部楼层
总结
下文与本项目无关,是博主的个人感叹(碎碎念),可跳过。
       博客主体写完,心情还是比较不平静的,有很多话想说,但是又因为各种原因删了。
       大一刚入南邮时,班主任(一位非常负责的导师)在班级群问:“大家有什么问题”,
       我:“没有啥问题”,
       班主任:“没问题就是最大的问题”。
       现在想起来当时自己真是愣头青,哈哈。大学不同于高中,我认为大学首要需要学会的能力是信息获取的能力。回首过往三年,虽然不后悔,多少有些遗憾,遗憾在于大多数时间都忙于学习,追求各种指标,而没有时间停下来,用心体会学习的过程。
       对于我来说,成绩更多像是我的保护伞,保护我免受父母的唠叨,保护我作为南邮第一届创新班学委有底气跟学校交流争取自己班的利益,保护我能保留很大一部分的个人自由······现在面对保研选择,才略微有些窥探到自己的追求:心无旁骛的深入追求知识。但是这又牵扯到很多,也很难实现。嗯,不过我依然会追逐理想,我依然问心无愧。
       祝愿各位都有远大前程。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|CrazyFPGA ( 粤ICP备2023025753号 )

GMT+8, 2025-4-4 06:50 , Processed in 0.050325 second(s), 20 queries .

Powered by CrazyFPGA X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表