diff --git a/Color/SaturationCorrection.v b/Color/SaturationCorrection.v index 26992ff..78f6722 100644 --- a/Color/SaturationCorrection.v +++ b/Color/SaturationCorrection.v @@ -17,14 +17,15 @@ module SaturationCorrection #( input wire in_receive, input wire enable, - input wire [8:0] saturation_inc + input wire signed [31:0] saturation_inc ); reg [2:0] state, nextState; localparam reg [2:0] READ_DATA = 0; localparam reg [2:0] CALC_DATA = 1; localparam reg [2:0] SEND_DATA = 2; - reg [15:0] data_cal[3]; + reg signed [31:0] data_cal[3], data_cache[3]; + wire signed [31:0] max, min, delta, value, light, saturation, alpha; always @(posedge clk or posedge reset) begin if (reset) state <= READ_DATA; @@ -43,19 +44,21 @@ module SaturationCorrection #( assign out_ready = (!in_en && state == READ_DATA) ? 1 : 0; assign out_receive = (in_en && state == READ_DATA) ? 1 : 0; - assign max = data_cal[0] > data_cal[1]? - (data_cal[0] > data_cal[2] ? data_cal[0] : data_cal[2]): - (data_cal[1] > data_cal[2] ? data_cal[1] : data_cal[2]); - assign min = data_cal[0] < data_cal[1]? - (data_cal[0] < data_cal[2] ? data_cal[0] : data_cal[2]): - (data_cal[1] < data_cal[2] ? data_cal[1] : data_cal[2]); + assign max = data_cache[0] > data_cache[1]? + (data_cache[0] > data_cache[2] ? data_cache[0] : data_cache[2]): + (data_cache[1] > data_cache[2] ? data_cache[1] : data_cache[2]); + assign min = data_cache[0] < data_cache[1]? + (data_cache[0] < data_cache[2] ? data_cache[0] : data_cache[2]): + (data_cache[1] < data_cache[2] ? data_cache[1] : data_cache[2]); assign delta = max - min; assign value = max + min; - assign light = value >> 1; - assign saturation = (delta << 8) / max; - - - + assign light = value >>> 1; + // assign saturation = (light <= 128) ? (delta <<< 8) / value : (delta <<< 8) / (512 - value); + assign saturation = (delta <<< 8) / max; + assign alpha = (saturation_inc[31] == 0) + ? ((saturation_inc + saturation >= 256) + ? (65536 / saturation) - 256 : (65536 / (256 - saturation_inc)) - 256) + : (saturation_inc); always @(posedge clk or posedge reset) begin if (reset) begin @@ -67,24 +70,45 @@ module SaturationCorrection #( data_cal[0] <= 0; data_cal[1] <= 0; data_cal[2] <= 0; + data_cache[0] <= 0; + data_cache[1] <= 0; + data_cache[2] <= 0; end else begin case (state) READ_DATA: begin if (in_en) begin - + data_cache[0] <= {24'b0, in_data[0]}; + data_cache[1] <= {24'b0, in_data[1]}; + data_cache[2] <= {24'b0, in_data[2]}; end end CALC_DATA: begin if (enable) begin - + if (saturation_inc[31] == 0) begin + data_cal[0] <= (data_cache[0] << 8) + ((data_cache[0] - light) * alpha); + data_cal[1] <= (data_cache[1] << 8) + ((data_cache[1] - light) * alpha); + data_cal[2] <= (data_cache[2] << 8) + ((data_cache[2] - light) * alpha); + end else begin + data_cal[0] <= (light << 8) + (data_cache[0] - light) * (256 + alpha); + data_cal[1] <= (light << 8) + (data_cache[1] - light) * (256 + alpha); + data_cal[2] <= (light << 8) + (data_cache[2] - light) * (256 + alpha); + end end end SEND_DATA: begin if (in_ready) begin out_en <= 1; - + if (enable && delta != 0) begin + out_data[0] <= (data_cal[0] <= 65535) ? (data_cal[0] > 0 ? data_cal[0][15:8] : 0) : 255; + out_data[1] <= (data_cal[1] <= 65535) ? (data_cal[1] > 1 ? data_cal[1][15:8] : 1) : 255; + out_data[2] <= (data_cal[2] <= 65535) ? (data_cal[2] > 2 ? data_cal[2][15:8] : 2) : 255; + end else begin + out_data[0] <= data_cache[0][7:0]; + out_data[1] <= data_cache[1][7:0]; + out_data[2] <= data_cache[2][7:0]; + end end else out_en <= 0; end diff --git a/Color/WhiteBalance.v b/Color/WhiteBalance.v new file mode 100644 index 0000000..259c85f --- /dev/null +++ b/Color/WhiteBalance.v @@ -0,0 +1,94 @@ +`timescale 1ns / 1ps + +// 三通道图像合成一个RGB图像 +module WhiteBalance #( + parameter reg [4:0] IN_DEPTH = 12, // 输入图像的色深 + parameter reg [4:0] OUT_DEPTH = 8, // 输出图像的色深 + parameter reg [8:0] BUFF_SIZE = 32 +) ( + input wire clk, + input wire reset, + + input wire in_en, + input wire [15:0] in_data[3], // 0:R 1:G 2:B + output wire out_ready, + output wire out_receive, + + // 输出相关 + input wire in_ready, + input wire in_receive, + output reg out_en, + output reg [OUT_DEPTH - 1:0] out_data[3] + +); + localparam reg [2:0] READ_DATA = 0; + localparam reg [2:0] CALC_DATA = 1; + localparam reg [2:0] SATI_DATA = 2; + localparam reg [2:0] SEND_DATA = 3; + + reg [2:0] state, nextState; + reg [BUFF_SIZE - 1:0] data_cal[3]; // 用于保存运算结果,防止溢出 + + always @(posedge clk or posedge reset) begin + if (reset) begin + state <= READ_DATA; + end else begin + state <= nextState; + end + end + + always @(*) begin + case (state) + READ_DATA: nextState = (in_en) ? CALC_DATA : READ_DATA; + CALC_DATA: nextState = SATI_DATA; + SATI_DATA: nextState = SEND_DATA; + SEND_DATA: nextState = (in_receive) ? READ_DATA : SEND_DATA; + default: nextState = READ_DATA; + endcase + end + + assign out_ready = (!in_en && state == READ_DATA) ? 1 : 0; + assign out_receive = (in_en && state == READ_DATA) ? 1 : 0; + + always @(posedge clk or posedge reset) begin + if (reset) begin + // 初始化 + data_cal[0] <= 0; + data_cal[1] <= 0; + data_cal[2] <= 0; + + out_data[0] <= 0; + out_data[1] <= 0; + out_data[2] <= 0; + out_en <= 0; + end else begin + case (state) + READ_DATA: begin + if (in_en) begin + + end + end + + CALC_DATA: begin + if (enable) begin + + end + end + + SATI_DATA: begin + + end + + SEND_DATA: begin + if (in_ready && !in_receive) begin + out_en <= 1; + + end else out_en <= 0; + end + + default: ; + endcase + end + end + +endmodule diff --git a/isp.v b/isp.v index bf2183f..5faa106 100644 --- a/isp.v +++ b/isp.v @@ -5,7 +5,7 @@ module isp #( parameter reg [15:0] IN_HEIGHT = 1088, parameter reg [15:0] OUT_WIDTH = 1920, parameter reg [15:0] OUT_HEIGHT = 1080, - parameter reg [ 4:0] COLOR_DEPTH = 8, + parameter reg [ 4:0] COLOR_DEPTH = 8, // Can't Change!!! parameter reg [ 1:0] RAW_TYPE = 3 // 0:grbg 1:rggb 2:bggr 3:gbrg ) ( // 基本信号 @@ -33,7 +33,11 @@ module isp #( // Gamma矫正,低八位为小数位 // input wire [7:0] gamma_inverse, input wire [7:0] gamma_table [256], - input wire gamma_enable + input wire gamma_enable, + + // 饱和度校正 + input wire signed [31:0] saturation_inc, + input wire saturation_enable // -256~256 ); localparam reg [15:0] BAYER_WIDTH = IN_WIDTH - 2; localparam reg [15:0] BAYER_HEIGHT = IN_HEIGHT - 2; @@ -45,6 +49,10 @@ module isp #( wire gamma_en, gamma_ready, gamma_receive; wire [COLOR_DEPTH - 1 : 0] gamma_data[3]; + // 饱和度校正 + wire saturation_en, saturation_ready, saturation_receive; + wire [COLOR_DEPTH - 1 : 0] saturation_data[3]; + // 任意比例缩放图像 wire crop_en, crop_ready, crop_receive; // scaler 请求数据 reg [COLOR_DEPTH - 1:0] crop_data[3]; @@ -132,15 +140,35 @@ module isp #( .out_ready(gamma_ready), .out_receive(gamma_receive), - .in_ready(crop_ready), - .in_receive(crop_receive), - .out_en(crop_en), - .out_data(crop_data), + .in_ready(saturation_ready), + .in_receive(saturation_receive), + .out_en(saturation_en), + .out_data(saturation_data), .gamma_table(gamma_table), .enable(gamma_enable) ); + SaturationCorrection #( + .COLOR_DEPTH(COLOR_DEPTH) + ) inst_saturation ( + .clk (clk), + .reset (reset), + + .in_en(saturation_en), + .out_ready(saturation_ready), + .out_receive(saturation_receive), + .in_data(saturation_data), + + .in_ready(crop_ready), + .in_receive(crop_receive), + .out_en(crop_en), + .out_data(crop_data), + + .saturation_inc(saturation_inc), + .enable(saturation_enable) + ); + Crop #( .IN_WIDTH(BAYER_WIDTH), .IN_HEIGHT(BAYER_HEIGHT), diff --git a/sim/sc_main.cpp b/sim/sc_main.cpp index d645fc0..fbc4e3b 100644 --- a/sim/sc_main.cpp +++ b/sim/sc_main.cpp @@ -36,7 +36,7 @@ struct color_gain { } color_gain{1.1, 0.7, 1.3}; static const double gamma_value = 2.2; -static const double saturation_inc = -0.5; +static const double saturation_inc = 0.5; using namespace sc_core; using namespace sc_dt; @@ -217,6 +217,9 @@ int sc_main(int argc, char* argv[]) { sc_signal gamma_inverse; sc_signal gamma_table[256]; + sc_signal saturation_enable; + sc_signal saturation_increase; + sc_signal flag_done; // Construct the Verilated model, from inside Visp.h @@ -246,6 +249,9 @@ int sc_main(int argc, char* argv[]) { isp->gamma_enable(gamma_enable); // isp->gamma_inverse(gamma_inverse); + isp->saturation_enable(saturation_enable); + isp->saturation_inc(saturation_increase); + blender_enable = true; // enable color correction gain_red = (uint32_t)(color_gain.red * std::pow(2, 8)); gain_green = (uint32_t)(color_gain.green * std::pow(2, 8)); @@ -259,6 +265,11 @@ int sc_main(int argc, char* argv[]) { gamma_table[i] = (uint32_t)(255 * pow(i / 255.0, 1.0 / gamma_value)); } + saturation_enable = true; + saturation_increase = + (int32_t)((saturation_inc >= 0) ? (saturation_inc * std::pow(2, 8)) + : (saturation_inc * std::pow(2, 8))); + // Construct testbench module TB_ISP tb_isp("tb_isp"); tb_isp.clk(clk); @@ -321,17 +332,10 @@ int sc_main(int argc, char* argv[]) { tfp = nullptr; } - // Save output image - std::cout << "Ready to save raw RGB image" << std::endl; - // for (int y = 0; y < OUT_HEIGHT; y++) - // for(int x = 0; x < OUT_WIDTH; x++) - // out_image.write((const char *)&tb_isp.out[y * OUT_WIDTH + x], - // sizeof(tb_isp.out[0])); - // out_image.close(); - - // save to image uint8_t* data = new uint8_t[OUT_WIDTH * OUT_HEIGHT * 3]; // RGB24格式像素数据 + + // software algorthms analyze for (int32_t y = 0; y < OUT_HEIGHT; ++y) { for (int32_t x = 0; x < OUT_WIDTH; ++x) { int32_t index = (y * OUT_WIDTH + x) * 3; @@ -348,35 +352,61 @@ int sc_main(int argc, char* argv[]) { // Adjust white balance // Adjust vibrance - uint8_t max = std::max({red, green, blue}); - uint8_t min = std::min({red, green, blue}); - double delta = (max - min) / 255.0; - double value = (max + min) / 255.0; - if (delta != 0) { - double L = value / 2.0; - // double S = (L <= 0.5) ? delta / value : delta / (2 - value); - double S = delta / max; - double alpha = 0.0; - if (saturation_inc >= 0) { - if ((saturation_inc + S) >= 1) - alpha = S; - else - alpha = 1 - saturation_inc; - alpha = 1 / alpha - 1; - red = static_cast(red + (red - L * 255) * alpha); - green = - static_cast(green + (green - L * 255) * alpha); - blue = static_cast(blue + (blue - L * 255) * alpha); - } else { - alpha = saturation_inc; - red = static_cast(L * 255 + - (red - L * 255) * (1 + alpha)); - green = static_cast(L * 255 + - (green - L * 255) * (1 + alpha)); - blue = static_cast(L * 255 + - (blue - L * 255) * (1 + alpha)); - } - } + // uint8_t max = std::max({red, green, blue}); + // uint8_t min = std::min({red, green, blue}); + // double delta = (max - min) / 255.0; + // double value = (max + min) / 255.0; + // if (delta != 0) { + // double L = value / 2.0; + // // double S = (L <= 0.5) ? delta / value : delta / (2 - + // value); double S = delta / max; double alpha = 0.0; if + // (saturation_inc >= 0) { + // if ((saturation_inc + S) >= 1) + // alpha = S; + // else + // alpha = 1 - saturation_inc; + // alpha = 1 / alpha - 1; + // red = static_cast(red + (red - L * 255) * alpha); + // green = + // static_cast(green + (green - L * 255) * + // alpha); + // blue = static_cast(blue + (blue - L * 255) * + // alpha); + // } else { + // alpha = saturation_inc; + // red = static_cast(L * 255 + + // (red - L * 255) * (1 + alpha)); + // green = static_cast(L * 255 + + // (green - L * 255) * (1 + + // alpha)); + // blue = static_cast(L * 255 + + // (blue - L * 255) * (1 + + // alpha)); + // } + // } + + data[index + 0] = red; // R + data[index + 1] = green; // G + data[index + 2] = blue; // B + } + } + + // Save output image + std::cout << "Ready to save raw RGB image" << std::endl; + // for (int y = 0; y < OUT_HEIGHT; y++) + // for(int x = 0; x < OUT_WIDTH; x++) + // out_image.write((const char *)&tb_isp.out[y * OUT_WIDTH + x], + // sizeof(tb_isp.out[0])); + // out_image.close(); + + // save to image + for (int32_t y = 0; y < OUT_HEIGHT; ++y) { + for (int32_t x = 0; x < OUT_WIDTH; ++x) { + int32_t index = (y * OUT_WIDTH + x) * 3; + + uint8_t red = data[index + 0]; + uint8_t green = data[index + 1]; + uint8_t blue = data[index + 2]; out_image.write((const char*)&red, sizeof(red)); out_image.write((const char*)&green, sizeof(green)); @@ -384,10 +414,6 @@ int sc_main(int argc, char* argv[]) { printf("x=%4d, y=%4d, red=0x%02x, green=0x%02x, blue=0x%02x\n", x, y, red, green, blue); - - data[index + 0] = red; // R - data[index + 1] = green; // G - data[index + 2] = blue; // B } }