From f4efa6177e81facec26ee115abbd5b3b58abe611 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Sun, 6 Oct 2024 20:31:32 +0800 Subject: [PATCH] add justfile and polish project structure --- .justfile | 64 +++++++++++ CMakeLists.txt | 30 ++--- FPGA.nix | 9 ++ flake.lock | 56 ++++++++-- flake.nix | 4 +- rtl/Demosaic/Demosaic_Pipeline.sv | 80 ++++++++----- src/sc_main_pipeline.cpp | 162 +-------------------------- src/tb_isp.hpp | 180 ++++++++++++++++++++++++++++++ 8 files changed, 375 insertions(+), 210 deletions(-) create mode 100644 .justfile create mode 100644 src/tb_isp.hpp diff --git a/.justfile b/.justfile new file mode 100644 index 0000000..9397c4d --- /dev/null +++ b/.justfile @@ -0,0 +1,64 @@ +alias c := clean-build +alias b := build +alias r := run + +# default target +default := "Visp_Pipeline" + +# clean all outpu files +clean-all: + rm -rf build logs + +# clean build output files +clean-build: + rm -rf ./build/* + +# build and run default target +all: build run + +# clean and build +rebuild: clean-build build + +# generate build files +generate: + cmake . -B ./build/ -G Ninja + +# build default target +build: generate + ninja -C ./build/ {{default}} -v + +# build all project +build-all: generate + cmake --build ./build/ -v + +# build ISP target +build-Visp: generate + cmake --bulid ./build/ -t Visp + +# build ISP Pipeline target +build-Visp_Pipeline: generate + cmake --bulid ./build/ -t Visp_Pipeline + +# run default target +run: + exec "./build/{{default}}" + +# run ISP +run-Visp: + ./build/Visp + +# run ISP Pipeline +run-Visp_Pipeline: + ./build/Visp_Pipeline + +# run default target with tracing wave +trace: + exec "./build/{{default}}" +trace + +# run ISP with tracing wave +trace-Visp: + ./build/Visp +trace + +# run ISP Pipeline with tracing wave +trace-Visp_Pipeline: + ./build/Visp_Pipeline +trace \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 19fe2a5..e3d715d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,19 +39,25 @@ find_package(SystemCLanguage QUIET) # file(GLOB_RECURSE IMG_SRC ${PROJECT_SOURCE_DIR}/src/img_process/*.cpp) # add_library(img_process STATIC ${IMG_SRC}) +# Set input and output location +set(INPUT_IMG ${PROJECT_SOURCE_DIR}/src/transform/test.bin) +set(OUTPUT_DIR ${PROJECT_SOURCE_DIR}/logs/) +add_compile_definitions( + INPUT_IMG="${INPUT_IMG}" + OUTPUT_DIR="${OUTPUT_DIR}" +) + +# Get RTL source code dir +SUBDIRLIST(RTL_SUBDIR ${PROJECT_SOURCE_DIR}/rtl) + + # ---------------------- EXE --------------------------- # VISP # ---------------------- EXE --------------------------- add_executable(Visp ${PROJECT_SOURCE_DIR}/src/sc_main.cpp) -target_compile_definitions(Visp - PRIVATE INPUT_IMG="${PROJECT_SOURCE_DIR}/src/transform/test.bin" - PRIVATE OUTPUT_DIR="${PROJECT_SOURCE_DIR}/logs/" -) target_include_directories(Visp PRIVATE ${PROJECT_SOURCE_DIR}/src/img_process) # target_link_libraries(Visp PRIVATE img_process) -# Get RTL source code dir -SUBDIRLIST(RTL_SUBDIR ${PROJECT_SOURCE_DIR}/rtl) # Add the Verilated circuit to the target verilate(Visp SYSTEMC COVERAGE TRACE INCLUDE_DIRS ${RTL_SUBDIR} @@ -67,15 +73,13 @@ verilator_link_systemc(Visp) # VISP_Pipeline # ---------------------- EXE --------------------------- add_executable(Visp_Pipeline ${PROJECT_SOURCE_DIR}/src/sc_main_pipeline.cpp) -target_compile_definitions(Visp_Pipeline - PRIVATE INPUT_IMG="${PROJECT_SOURCE_DIR}/src/transform/test.bin" - PRIVATE OUTPUT_DIR="${PROJECT_SOURCE_DIR}/logs/" +target_include_directories( + Visp_Pipeline + PRIVATE ${PROJECT_SOURCE_DIR}/src/img_process + PRIVATE ${PROJECT_SOURCE_DIR}/src ) -target_include_directories(Visp_Pipeline PRIVATE ${PROJECT_SOURCE_DIR}/src/img_process) # target_link_libraries(Visp_Pipeline PRIVATE img_process) -# Get RTL source code dir -SUBDIRLIST(RTL_SUBDIR ${PROJECT_SOURCE_DIR}/rtl) # Add the Verilated circuit to the target verilate(Visp_Pipeline SYSTEMC COVERAGE TRACE INCLUDE_DIRS ${RTL_SUBDIR} @@ -85,4 +89,4 @@ verilate(Visp_Pipeline SYSTEMC COVERAGE TRACE ) # SystemC Link -verilator_link_systemc(Visp_Pipeline) \ No newline at end of file +verilator_link_systemc(Visp_Pipeline) diff --git a/FPGA.nix b/FPGA.nix index 7f8d0a6..d36b8e4 100644 --- a/FPGA.nix +++ b/FPGA.nix @@ -19,6 +19,15 @@ # Enable languages support # languages.cplusplus.enable = true; + languages.python = { + enable = true; + version = "3.11"; + venv.enable = true; + venv.requirements = '' + teroshdl + cocotb + ''; + }; # When enter shell, exec ... enterShell = '' diff --git a/flake.lock b/flake.lock index b6aa65a..90b4141 100644 --- a/flake.lock +++ b/flake.lock @@ -191,6 +191,22 @@ "type": "github" } }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -429,6 +445,27 @@ "type": "github" } }, + "nixpkgs-python": { + "inputs": { + "flake-compat": "flake-compat_3", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1722978926, + "narHash": "sha256-sqOOEaKJJSUFBzag/cGeeXV491TrrVFY3DFBs1w20V8=", + "owner": "cachix", + "repo": "nixpkgs-python", + "rev": "7c550bca7e6cf95898e32eb2173efe7ebb447460", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "nixpkgs-python", + "type": "github" + } + }, "nixpkgs-regression": { "locked": { "lastModified": 1643052045, @@ -511,14 +548,18 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 315532800, - "narHash": "sha256-DXLcxy2Vmxj0vD/GACAsw/JCeyi3UJlVl/9iU+ZnPnU=", - "type": "tarball", - "url": "https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable/nixexprs.tar.xz" + "lastModified": 1728018373, + "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", + "type": "github" }, "original": { - "type": "tarball", - "url": "https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable/nixexprs.tar.xz" + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" } }, "poetry2nix": { @@ -614,7 +655,8 @@ "root": { "inputs": { "devenv": "devenv", - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs_3", + "nixpkgs-python": "nixpkgs-python" } }, "systems": { diff --git a/flake.nix b/flake.nix index f5fc646..5595e6d 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,8 @@ { inputs = { - nixpkgs.url = "https://mirrors.ustc.edu.cn/nix-channels/nixpkgs-unstable/nixexprs.tar.xz"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-python.url = "github:cachix/nixpkgs-python"; + nixpkgs-python.inputs.nixpkgs.follows = "nixpkgs"; devenv.url = "github:cachix/devenv"; devenv.inputs.nixpkgs.follows = "nixpkgs"; }; diff --git a/rtl/Demosaic/Demosaic_Pipeline.sv b/rtl/Demosaic/Demosaic_Pipeline.sv index b68c8e2..8585bdd 100644 --- a/rtl/Demosaic/Demosaic_Pipeline.sv +++ b/rtl/Demosaic/Demosaic_Pipeline.sv @@ -1,26 +1,26 @@ `timescale 1ns / 1ps module Demosaic_Pipeline #( -parameter WINDOW_LENGTH = 3, -parameter reg [15:0] TOTAL_WIDTH = 512+3, // 总图像宽度 -parameter reg [15:0] TOTAL_HEIGHT = 256+3, // 总图像高度 -parameter reg [ 1:0] RAW_TYPE = 3, // (0,0)位置算起RAW_TYPE的值 -parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 -)( + parameter WINDOW_LENGTH = 3, + parameter reg [15:0] TOTAL_WIDTH = 512+3, // 总图像宽度 + parameter reg [15:0] TOTAL_HEIGHT = 256+3, // 总图像高度 + parameter reg [ 1:0] RAW_TYPE = 3, // (0,0)位置算起RAW_TYPE的值 + parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 + )( input wire clk, input wire reset, - + input wire [DATA_WIDTH - 1:0] in_data [WINDOW_LENGTH*WINDOW_LENGTH], // 数据输入线.第一列数据在[0],[1],[2]中 output reg [DATA_WIDTH - 1:0] out_data [3], // 数据输出线,3、2、1分别表示r、g、b - + input wire in_valid, output wire out_valid, - + input wire in_ready, output wire out_ready, - + output reg out_hsync, // 行同步,一行第一个像素点输出的同时高电平 output reg out_fsync // 帧同步,一帧第一个像素点输出的同时高电平 -); + ); localparam DATA_NUM = WINDOW_LENGTH*WINDOW_LENGTH; localparam PIPILINE = 3; @@ -40,9 +40,12 @@ parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 reg [1:0] raw_type; integer i; - always @(posedge clk) begin - if(reset) begin - for(i=0;i= TOTAL_WIDTH - 1)?(0):(pos_x + 1); pos_y <= (pos_x >= TOTAL_WIDTH - 1)?((pos_y >= TOTAL_HEIGHT - 1)?(0):(pos_y + 1)):(pos_y); end - if(pipeline_valid[0]) begin + if(pipeline_valid[0]) + begin temp_pos_x <= pos_x; temp_pos_y <= pos_y; case (raw_type) - 0: begin // Missing B, R on G + 0: + begin // Missing B, R on G blue <= (data_cache[1] + data_cache[7]) >> 1; red <= (data_cache[3] + data_cache[5]) >> 1; green <= data_cache[4]; end - 1: begin // Missing G, R on B + 1: + begin // Missing G, R on B green <= (data_cache[1] + data_cache[3] + data_cache[5] + data_cache[7]) >> 2; red <= (data_cache[0] + data_cache[2] + data_cache[6] + data_cache[8]) >> 2; blue <= data_cache[4]; end - 2: begin // Missing G, B on R + 2: + begin // Missing G, B on R green <= (data_cache[1] + data_cache[3] + data_cache[5] + data_cache[7]) >> 2; blue <= (data_cache[0] + data_cache[2] + data_cache[6] + data_cache[8]) >> 2; red <= data_cache[4]; end - 3: begin // Missing B, R on G + 3: + begin // Missing B, R on G red <= (data_cache[1] + data_cache[7]) >> 1; blue <= (data_cache[3] + data_cache[5]) >> 1; green <= data_cache[4]; @@ -88,7 +100,8 @@ parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 endcase end - if(pipeline_valid[1]) begin + if(pipeline_valid[1]) + begin {out_data[2],out_data[1],out_data[0]} <= {red,blue,green}; out_hsync <= (temp_pos_x == 0); out_fsync <= ((temp_pos_x == 0) && (temp_pos_y == 0)); @@ -98,13 +111,20 @@ parameter reg [ 4:0] DATA_WIDTH = 16 // 输入/输出数据位宽 // 0:gr 1:rg 2:bg 3:gb 窗口右移,0<->1 2<->3; 窗口下移,0<->2,1<->3。 // bg gb gr rg - always @(*) begin - if(reset) raw_type = RAW_TYPE; - else case (RAW_TYPE) - 2'b00: raw_type = {pos_y[0], pos_x[0]}; - 2'b01: raw_type = {pos_y[0], ~pos_x[0]}; - 2'b10: raw_type = {~pos_y[0], pos_x[0]}; - 2'b11: raw_type = {~pos_y[0], ~pos_x[0]}; + always @(*) + begin + if(reset) + raw_type = RAW_TYPE; + else + case (RAW_TYPE) + 2'b00: + raw_type = {pos_y[0], pos_x[0]}; + 2'b01: + raw_type = {pos_y[0], ~pos_x[0]}; + 2'b10: + raw_type = {~pos_y[0], pos_x[0]}; + 2'b11: + raw_type = {~pos_y[0], ~pos_x[0]}; endcase end diff --git a/src/sc_main_pipeline.cpp b/src/sc_main_pipeline.cpp index a3f6ff2..faab916 100755 --- a/src/sc_main_pipeline.cpp +++ b/src/sc_main_pipeline.cpp @@ -12,7 +12,6 @@ #include // Include common routines -#include #include // mkdir #include #include @@ -22,8 +21,8 @@ // Include model header, generated from Verilating "isp.v" #include "Visp_Pipeline.h" -// Write Pictures -#include "bitmap_image.hpp" +// Include testbench written by systemc +#include "tb_isp.hpp" // Image Parameters static const uint16_t IN_WIDTH = 1936; @@ -56,161 +55,6 @@ static const double contrast = 1.2; using namespace sc_core; using namespace sc_dt; -SC_MODULE(TB_ISP) { - sc_in_clk clk; - sc_in rst; - - sc_in in_ready; // next module ready to receive data - sc_out out_valid; // next module data valid signal - sc_out out_data[3]; // next module receive data - - sc_in in_valid; // this module receive data valid signal - sc_out out_ready; // this module ready to receive data - sc_in in_data; // this module receive data - - bool is_done; // when receive all data - std::vector image; // the data of image - std::vector process_image = std::vector( - OUT_SIZE, 0); // after isp process, the data of image - - SC_CTOR(TB_ISP) { - SC_CTHREAD(sendData, clk.pos()); // when clk posedge, exec sendData - reset_signal_is(rst, true); // set rst signal - - SC_CTHREAD(readData, clk.pos()); - reset_signal_is(rst, true); // set rst signal - } - - void sendData(void) { - // init var - uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; - bool is_finish = false; // when send all data - // reset - out_valid = false; - for (auto &data : out_data) - data = 0; - - while (true) { - if (in_ready && !is_finish) { - // valid and send data - out_valid = true; - out_data[0] = image[(pos_y + 0) * IN_WIDTH + pos_x]; - out_data[1] = image[(pos_y + 1) * IN_WIDTH + pos_x]; - out_data[2] = image[(pos_y + 2) * IN_WIDTH + pos_x]; - - // print data - std::printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, - image[(pos_y + 0) * IN_WIDTH + pos_x]); - std::printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, - image[(pos_y + 1) * IN_WIDTH + pos_x]); - std::printf("x=%4d, y=%4d, data=0x%04x\n", pos_x, pos_y, - image[(pos_y + 2) * IN_WIDTH + pos_x]); - pos_x++; - - // calculate position and recognize when to finish - if (pos_x >= IN_WIDTH) { - pos_x = 0; - pos_y++; - } - if (pos_y >= IN_HEIGHT - 1) { - pos_y = 0; - cnt_flame++; - } - if (cnt_flame >= FLAMES) { - is_finish = true; - } - } else { - out_valid = false; - } - - // wait for next clk - wait(); - } - } - - void readData(void) { - // init local var - uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; - uint32_t last_data = 0, cnt = 0; - bool is_finish = false; - // reset - out_ready = false; - is_done = false; - - while (true) { - if (!is_finish) { - out_ready = true; - - // when data valid, write it down - if (in_valid) { - process_image[pos_y * OUT_WIDTH + pos_x] = in_data; - - // calculate position - pos_x++; - - if (pos_x >= OUT_WIDTH) { - pos_x = 0; - pos_y++; - } - if (pos_y >= OUT_HEIGHT) { - pos_y = 0; - saveData( - ("output_img_" + std::to_string(cnt_flame) + ".bmp").c_str()); - cnt_flame++; - } - if (cnt_flame >= FLAMES) { - is_finish = true; - } - } - } else { - out_ready = false; - } - - // when no data send, give finish signal - if (is_finish && (last_data == in_data)) { - cnt++; - if (cnt >= 100000L) { // when receive many times the same data - is_done = true; - std::printf("Finish Reading data; pos_x = %d, pos_y = %d\n", pos_x, - pos_y); - } - } else { - cnt = 0; - } - last_data = in_data; - - // wait for next clk - wait(); - } - } - - bool saveData(const char *name) { - bool ret = true; - - // Check Image Size - if (process_image.size() > OUT_SIZE) { - std::cout << "Process Image Over Size!!!\n" - << "Image Size:" << process_image.size() << "\n"; - return false; - } - - // Write BMP image - bitmap_image bmp(OUT_WIDTH, OUT_HEIGHT); - if (!bmp) { - std::cout << "Output Image Open Failed!!!\n"; - return false; - } - for (int y = 0; y < OUT_HEIGHT; y++) - for (int x = 0; x < OUT_WIDTH; x++) - bmp.set_pixel(x, y, - (process_image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16, - (process_image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8, - (process_image[y * OUT_WIDTH + x] & 0x000000ff) >> 0); - bmp.save_image(std::string(OUTPUT_DIR) + name); - return ret; - } -}; - int sc_main(int argc, char *argv[]) { std::printf("Enter into sc_main\n"); @@ -314,7 +158,7 @@ int sc_main(int argc, char *argv[]) { isp.gain_blue(gain_blue); // Construct testbench module - TB_ISP tb_isp("tb_isp"); + TB_ISP tb_isp("tb_isp", IN_WIDTH, IN_HEIGHT, OUT_WIDTH, OUT_HEIGHT, FLAMES, OUTPUT_DIR); tb_isp.image = std::move(in_image); tb_isp.clk(clk); tb_isp.rst(rst); diff --git a/src/tb_isp.hpp b/src/tb_isp.hpp new file mode 100644 index 0000000..e7448c5 --- /dev/null +++ b/src/tb_isp.hpp @@ -0,0 +1,180 @@ +#ifndef __TB_ISP_H__ +#define __TB_ISP_H__ + +#include +#include + +// Write Pictures +#include "bitmap_image.hpp" + +SC_MODULE(TB_ISP) { + sc_core::sc_in_clk clk; + sc_core::sc_in rst; + + sc_core::sc_in in_ready; // next module ready to receive data + sc_core::sc_out out_valid; // next module data valid signal + sc_core::sc_out out_data[3]; // next module receive data + + sc_core::sc_in in_valid; // this module receive data valid signal + sc_core::sc_out out_ready; // this module ready to receive data + sc_core::sc_in in_data; // this module receive data + + const uint16_t IN_WIDTH; + const uint16_t IN_HEIGHT; + const uint32_t IN_SIZE; + const uint16_t OUT_WIDTH; + const uint16_t OUT_HEIGHT; + const uint32_t OUT_SIZE; + const uint32_t FLAMES; + const std::string OUT_DIR; + + bool is_done; // when receive all data + std::vector image; // the data of image + std::vector process_image; // after isp process, the data of image + + SC_CTOR(TB_ISP, const uint16_t in_width, const uint16_t in_height, + const uint16_t out_width, const uint16_t out_height, + const uint32_t cnt_flame, const std::string& out_dir) + : IN_WIDTH(in_width), IN_HEIGHT(in_height), IN_SIZE(in_width * in_height), + OUT_WIDTH(out_width), OUT_HEIGHT(out_height), + OUT_SIZE(out_width * out_height), FLAMES(cnt_flame), + OUT_DIR(out_dir), + process_image(std::vector(out_width * out_height, 0)) { + SC_CTHREAD(sendData, clk.pos()); // when clk posedge, exec sendData + reset_signal_is(rst, true); // set rst signal + + SC_CTHREAD(readData, clk.pos()); + reset_signal_is(rst, true); // set rst signal + } + + void sendData(void) { + // init var + uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; + bool is_finish = false; // when send all data + // reset + out_valid = false; + for (auto &data : out_data) + data = 0; + + while (true) { + if (in_ready && !is_finish) { + // valid and send data + out_valid = true; + out_data[0] = image[(pos_y + 0) * IN_WIDTH + pos_x]; + out_data[1] = image[(pos_y + 1) * IN_WIDTH + pos_x]; + out_data[2] = image[(pos_y + 2) * IN_WIDTH + pos_x]; + + // print data + std::printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, + image[(pos_y + 0) * IN_WIDTH + pos_x]); + std::printf("x=%4d, y=%4d, data=0x%04x\t", pos_x, pos_y, + image[(pos_y + 1) * IN_WIDTH + pos_x]); + std::printf("x=%4d, y=%4d, data=0x%04x\n", pos_x, pos_y, + image[(pos_y + 2) * IN_WIDTH + pos_x]); + pos_x++; + + // calculate position and recognize when to finish + if (pos_x >= IN_WIDTH) { + pos_x = 0; + pos_y++; + } + if (pos_y >= IN_HEIGHT - 1) { + pos_y = 0; + cnt_flame++; + } + if (cnt_flame >= FLAMES) { + is_finish = true; + } + } else { + out_valid = false; + } + + // wait for next clk + wait(); + } + } + + void readData(void) { + // init local var + uint16_t pos_x = 0, pos_y = 0, cnt_flame = 0; + uint32_t last_data = 0, cnt = 0; + bool is_finish = false; + // reset + out_ready = false; + is_done = false; + + while (true) { + if (!is_finish) { + out_ready = true; + + // when data valid, write it down + if (in_valid) { + process_image[pos_y * OUT_WIDTH + pos_x] = in_data; + + // calculate position + pos_x++; + + if (pos_x >= OUT_WIDTH) { + pos_x = 0; + pos_y++; + } + if (pos_y >= OUT_HEIGHT) { + pos_y = 0; + saveData( + ("output_img_" + std::to_string(cnt_flame) + ".bmp").c_str()); + cnt_flame++; + } + if (cnt_flame >= FLAMES) { + is_finish = true; + } + } + } else { + out_ready = false; + } + + // when no data send, give finish signal + if (is_finish && (last_data == in_data)) { + cnt++; + if (cnt >= 100000L) { // when receive many times the same data + is_done = true; + std::printf("Finish Reading data; pos_x = %d, pos_y = %d\n", pos_x, + pos_y); + } + } else { + cnt = 0; + } + last_data = in_data; + + // wait for next clk + wait(); + } + } + + bool saveData(const char *name) { + bool ret = true; + + // Check Image Size + if (process_image.size() > OUT_SIZE) { + std::cout << "Process Image Over Size!!!\n" + << "Image Size:" << process_image.size() << "\n"; + return false; + } + + // Write BMP image + bitmap_image bmp(OUT_WIDTH, OUT_HEIGHT); + if (!bmp) { + std::cout << "Output Image Open Failed!!!\n"; + return false; + } + for (int y = 0; y < OUT_HEIGHT; y++) + for (int x = 0; x < OUT_WIDTH; x++) + bmp.set_pixel(x, y, + (process_image[y * OUT_WIDTH + x] & 0x00ff0000) >> 16, + (process_image[y * OUT_WIDTH + x] & 0x0000ff00) >> 8, + (process_image[y * OUT_WIDTH + x] & 0x000000ff) >> 0); + bmp.save_image(std::string(OUT_DIR) + name); + return ret; + } +}; + +#endif