有符号浮点运算的基本步骤:以双线性插值为例
参考:韩彬的图像处理书、无双软件学院方法。
步骤一:无损定点化
浮点数在硬件计算中首先需要做的便是定点化,一般是左移一定位宽,可以是2048或4096;
这个过程要注意保障无损;
步骤二:运算和位宽匹配;
要确定所有参与计算的数小数位位宽是匹配的,否则无法进行任何层次的计算;
需要特别注意很多小数在计算的时候也需要定点化,例如:
always@(posedge clk) if(rst) src_xf0 <= 'd0; else if(dst_de==1'b1) src_xf0 <= {dst_hcnt,2'd0} + 2; else src_xf0 <= 'd0;
这里做的计算是修改后的双线性插值中的中心对齐操作;
0.5左移两位变成了2;
步骤三:相乘后的截位处理
发生了相乘操作以后,整数和小数位宽都会发生变化,注意匹配;
此处小数位位宽为12,0.5左移12位后为2048;
//fix16_2 * fix16_12 = fix32_14 always@(posedge clk) if(rst) src_xf1 <= 'd0; else src_xf1 <= src_xf0*sx; //fix26_12 - fix12_12 = fix26_12 可能为负数 always@(posedge clk) if(rst) src_xf2 <= 'd0; else src_xf2 <= src_xf1[27:2] - 2048;
步骤四:加减处理后的正负判断;
目前为止的公式:src_x = (dst_x + 0.5) * scale_x - 0.5
always@(posedge clk) if(rst) src_xf3 <= 'd0; else src_xf3 <= src_xf2; always@(posedge clk) if(rst) src_x0 <= 'd0; else if(src_xf2[25]==1'b1) src_x0 <= 'd0; else src_x0 <= src_xf2[25:12];
在这里的运算中,相减可能出现负数,这是显而易见的,但是此处xf2指的是坐标;(当然,相加如果坐标大于图像尺寸也会做匹配处理)
坐标不能有负数,最小是0;
在sobel里我也做了类似的操作;
always@(posedge clk) if(rst) region_type <= 0; else if(src_x0>=SRC_IW-1&&src_y0>=SRC_IH-1&&src_xy_de==1'b1) region_type <= 1; else if(src_y0>=SRC_IH-1&&src_xy_de==1'b1) region_type <= 2; else if(src_x0>=SRC_IW-1&&src_xy_de==1'b1) region_type <= 3; else region_type <= 4;
步骤五:符号化:
这里计算的就不是坐标,而是实际的像素值了;
此外,正数的有符号化需要在最高位手动填0。
实际的像素值也没有负值,但是这里计算出的数据可以用来后续对像素的增减,重要性判断,所以有正有负;
//fix26_12 - fix26_12 = fix26_12 always@(posedge clk) if(rst) v <= 'd0; else v <= $signed(src_xf3) - $signed({src_x0,12'd0});
后面没有太多指的说的,只需要记住实际使用的时候取出整数位数据;
还有就是小数位第一位是1代表了0.5,如果希望做四舍五入的话需要在整数位+1处理;
//fix25_12 always@(posedge clk) if(rst) cast_data <= 'd0; else if(line_data[24]==1'b1) cast_data <= 0; else if(line_data[22:12]>=255) cast_data <= 255; else cast_data <= line_data[11] ? line_data[19:12] + 1'b1 : line_data[19:12];