├── test.RAW ├── prebuilt ├── test.RAW ├── test.png └── isp_pipeline.exe ├── image ├── deaft.drawio.png ├── isp_pipeline.png ├── readme │ └── isp_pipeline.png └── deaft.drawio ├── inc ├── nlohmann │ ├── detail │ │ ├── meta │ │ │ ├── call_std │ │ │ │ ├── begin.hpp │ │ │ │ └── end.hpp │ │ │ ├── identity_tag.hpp │ │ │ ├── void_t.hpp │ │ │ ├── detected.hpp │ │ │ ├── cpp_future.hpp │ │ │ └── is_sax.hpp │ │ ├── input │ │ │ ├── position_t.hpp │ │ │ ├── input_adapters.hpp │ │ │ └── parser.hpp │ │ ├── iterators │ │ │ ├── internal_iterator.hpp │ │ │ ├── iterator_traits.hpp │ │ │ ├── primitive_iterator.hpp │ │ │ ├── json_reverse_iterator.hpp │ │ │ └── iteration_proxy.hpp │ │ ├── macro_unscope.hpp │ │ ├── json_ref.hpp │ │ ├── string_escape.hpp │ │ ├── hash.hpp │ │ ├── output │ │ │ └── output_adapters.hpp │ │ ├── value_t.hpp │ │ ├── string_concat.hpp │ │ ├── exceptions.hpp │ │ └── conversions │ │ │ └── to_json.hpp │ ├── adl_serializer.hpp │ ├── json_fwd.hpp │ ├── byte_container_with_subtype.hpp │ ├── thirdparty │ │ └── hedley │ │ │ └── hedley_undef.hpp │ └── ordered_map.hpp └── isp.h ├── CMakeLists.txt ├── src ├── isp_aaf.cpp ├── isp_bcc.cpp ├── isp_ccm.cpp ├── isp_blc.cpp ├── isp_csc.cpp ├── isp_awb.cpp ├── isp_hsc.cpp ├── isp_fcs.cpp ├── isp_bnf.cpp ├── isp_gac.cpp ├── isp_eeh.cpp ├── isp_nlm.cpp ├── isp_dpc.cpp ├── isp_cfa.cpp └── isp_core.cpp ├── LICENSE.md ├── main.cpp ├── config.json └── readme.md /test.RAW: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/test.RAW -------------------------------------------------------------------------------- /prebuilt/test.RAW: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/prebuilt/test.RAW -------------------------------------------------------------------------------- /prebuilt/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/prebuilt/test.png -------------------------------------------------------------------------------- /image/deaft.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/image/deaft.drawio.png -------------------------------------------------------------------------------- /image/isp_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/image/isp_pipeline.png -------------------------------------------------------------------------------- /prebuilt/isp_pipeline.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/prebuilt/isp_pipeline.exe -------------------------------------------------------------------------------- /image/readme/isp_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lesialin/ImageSignalProcessing_C/HEAD/image/readme/isp_pipeline.png -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/call_std/begin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); 8 | } // namespace nlohmann 9 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/call_std/end.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); 8 | } // namespace nlohmann 9 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/identity_tag.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nlohmann 4 | { 5 | namespace detail 6 | { 7 | // dispatching helper struct 8 | template struct identity_tag {}; 9 | } // namespace detail 10 | } // namespace nlohmann 11 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/void_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace nlohmann 4 | { 5 | namespace detail 6 | { 7 | template struct make_void 8 | { 9 | using type = void; 10 | }; 11 | template using void_t = typename make_void::type; 12 | } // namespace detail 13 | } // namespace nlohmann 14 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/input/position_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | 5 | namespace nlohmann 6 | { 7 | namespace detail 8 | { 9 | /// struct to capture the start position of the current token 10 | struct position_t 11 | { 12 | /// the total number of characters read 13 | std::size_t chars_read_total = 0; 14 | /// the number of characters read in the current line 15 | std::size_t chars_read_current_line = 0; 16 | /// the number of lines read 17 | std::size_t lines_read = 0; 18 | 19 | /// conversion to size_t to preserve SAX interface 20 | constexpr operator size_t() const 21 | { 22 | return chars_read_total; 23 | } 24 | }; 25 | 26 | } // namespace detail 27 | } // namespace nlohmann 28 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/internal_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | namespace detail 8 | { 9 | /*! 10 | @brief an iterator value 11 | 12 | @note This structure could easily be a union, but MSVC currently does not allow 13 | unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. 14 | */ 15 | template struct internal_iterator 16 | { 17 | /// iterator for JSON objects 18 | typename BasicJsonType::object_t::iterator object_iterator {}; 19 | /// iterator for JSON arrays 20 | typename BasicJsonType::array_t::iterator array_iterator {}; 21 | /// generic iterator for all other types 22 | primitive_iterator_t primitive_iterator {}; 23 | }; 24 | } // namespace detail 25 | } // namespace nlohmann 26 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(isp_pipeline) 3 | find_package( OpenCV REQUIRED ) 4 | if(MSVC) 5 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 6 | endif() 7 | 8 | include_directories( ${OpenCV_INCLUDE_DIRS} ) 9 | include_directories(${PROJECT_SOURCE_DIR}/inc) 10 | include_directories(${PROJECT_SOURCE_DIR}/src) 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_SOURCE_DIR}/prebuilt>) 13 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $<1:${CMAKE_SOURCE_DIR}/prebuilt>) 14 | add_executable(isp_pipeline 15 | src/isp_core.cpp 16 | src/isp_aaf.cpp 17 | src/isp_cfa.cpp 18 | src/isp_gac.cpp 19 | src/isp_blc.cpp 20 | src/isp_dpc.cpp 21 | src/isp_ccm.cpp 22 | src/isp_awb.cpp 23 | src/isp_csc.cpp 24 | src/isp_nlm.cpp 25 | src/isp_bnf.cpp 26 | src/isp_eeh.cpp 27 | src/isp_fcs.cpp 28 | src/isp_hsc.cpp 29 | src/isp_bcc.cpp 30 | main.cpp) 31 | target_link_libraries(isp_pipeline ${OpenCV_LIBS}) 32 | -------------------------------------------------------------------------------- /src/isp_aaf.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | extern isp_config_t g_isp_config; 3 | 4 | //anti-aliasing filter 5 | void isp_aaf(uint16_t *raw_buf) 6 | { 7 | uint16_t image_height = g_isp_config.image_height; 8 | uint16_t image_width = g_isp_config.image_width; 9 | uint32_t idx; 10 | uint16_t arr[9] = {0}; 11 | 12 | for (int i = 2; i < image_height - 2; i++) 13 | { 14 | for (int j = 2; j < image_width - 2; j++) 15 | { 16 | 17 | idx = i * image_width + j; 18 | 19 | raw_buf[idx] = ((raw_buf[idx] << 3) + raw_buf[idx - 2 * image_width - 2] + raw_buf[idx - 2 * image_width + 2] + raw_buf[idx + 2 * image_width - 2] + 20 | raw_buf[idx + 2 * image_width + 2] + raw_buf[idx - 2] + raw_buf[idx + 2] + raw_buf[idx + 2 * image_width] + raw_buf[idx - 2 * image_width]) >> 21 | 4; 22 | 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/macro_unscope.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // restore clang diagnostic settings 4 | #if defined(__clang__) 5 | #pragma clang diagnostic pop 6 | #endif 7 | 8 | // clean up 9 | #undef JSON_ASSERT 10 | #undef JSON_INTERNAL_CATCH 11 | #undef JSON_THROW 12 | #undef JSON_PRIVATE_UNLESS_TESTED 13 | #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION 14 | #undef NLOHMANN_BASIC_JSON_TPL 15 | #undef JSON_EXPLICIT 16 | #undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL 17 | #undef JSON_INLINE_VARIABLE 18 | #undef JSON_NO_UNIQUE_ADDRESS 19 | #undef JSON_DISABLE_ENUM_SERIALIZATION 20 | 21 | #ifndef JSON_TEST_KEEP_MACROS 22 | #undef JSON_CATCH 23 | #undef JSON_TRY 24 | #undef JSON_HAS_CPP_11 25 | #undef JSON_HAS_CPP_14 26 | #undef JSON_HAS_CPP_17 27 | #undef JSON_HAS_CPP_20 28 | #undef JSON_HAS_FILESYSTEM 29 | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM 30 | #undef JSON_HAS_THREE_WAY_COMPARISON 31 | #undef JSON_HAS_RANGES 32 | #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 33 | #endif 34 | 35 | #include 36 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 lesialin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/isp_bcc.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | #define BBC_CONTRAST_FRACTION_BIT 6 3 | 4 | extern isp_config_t g_isp_config; 5 | 6 | void isp_bcc(uint8_t *y_image) 7 | { 8 | 9 | uint8_t fixed_contrast_gain = g_isp_config.bcc_config.contrast * (1 << BBC_CONTRAST_FRACTION_BIT); 10 | uint8_t brightness = g_isp_config.bcc_config.brightness; 11 | uint8_t y_mean = 127; 12 | uint16_t value; 13 | uint16_t image_width, image_height; 14 | image_width = g_isp_config.image_width; 15 | image_height = g_isp_config.image_height; 16 | 17 | for (int i = 0; i < image_height; i++) 18 | { 19 | for (int j = 0; j < image_width; j++) 20 | { 21 | value = y_image[i*image_width + j] + brightness; 22 | value = clip_max(value,255); 23 | value = clip_min(value,0); 24 | 25 | 26 | if(value > y_mean){ 27 | value = y_mean + (uint8_t)((fixed_contrast_gain*(value-(uint8_t)y_mean))>>BBC_CONTRAST_FRACTION_BIT); 28 | 29 | }else{ 30 | 31 | value = y_mean - (uint8_t)((fixed_contrast_gain*((uint8_t)y_mean-value))>>BBC_CONTRAST_FRACTION_BIT); 32 | } 33 | 34 | 35 | value = clip_max(value,255); 36 | value = clip_min(value,0); 37 | y_image[i*image_width + j] = value; 38 | 39 | 40 | 41 | } 42 | 43 | } 44 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/iterator_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // random_access_iterator_tag 4 | 5 | #include 6 | #include 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | template 13 | struct iterator_types {}; 14 | 15 | template 16 | struct iterator_types < 17 | It, 18 | void_t> 20 | { 21 | using difference_type = typename It::difference_type; 22 | using value_type = typename It::value_type; 23 | using pointer = typename It::pointer; 24 | using reference = typename It::reference; 25 | using iterator_category = typename It::iterator_category; 26 | }; 27 | 28 | // This is required as some compilers implement std::iterator_traits in a way that 29 | // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. 30 | template 31 | struct iterator_traits 32 | { 33 | }; 34 | 35 | template 36 | struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> 37 | : iterator_types 38 | { 39 | }; 40 | 41 | template 42 | struct iterator_traits::value>> 43 | { 44 | using iterator_category = std::random_access_iterator_tag; 45 | using value_type = T; 46 | using difference_type = ptrdiff_t; 47 | using pointer = T*; 48 | using reference = T&; 49 | }; 50 | } // namespace detail 51 | } // namespace nlohmann 52 | -------------------------------------------------------------------------------- /src/isp_ccm.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | extern isp_config_t g_isp_config; 3 | 4 | 5 | void isp_ccm(uint16_t *rgb_buf) 6 | { 7 | uint16_t image_width; 8 | uint16_t image_height; 9 | float *ccm_matrix; 10 | int16_t fixed_ccm_matrix[12]; 11 | uint16_t max_value; 12 | uint32_t idx; 13 | int32_t r, g, b; 14 | 15 | ccm_matrix = g_isp_config.ccm_matrix; 16 | image_width = g_isp_config.image_width; 17 | image_height = g_isp_config.image_height; 18 | max_value = (1 << g_isp_config.image_bits) - 1; 19 | 20 | for (int i = 0; i < 12; i++) 21 | { 22 | fixed_ccm_matrix[i] = (int16_t)(ccm_matrix[i] * (1 << CCM_FRACTION)); 23 | } 24 | 25 | for (int i = 0; i < image_height; i++) 26 | { 27 | for (int j = 0; j < image_width; j++) 28 | { 29 | idx = 3 * (i * image_width + j); 30 | r = (int16_t)rgb_buf[idx] * fixed_ccm_matrix[0] + (int16_t)rgb_buf[idx + 1] * fixed_ccm_matrix[1] + (int16_t)rgb_buf[idx + 2] * fixed_ccm_matrix[2] + fixed_ccm_matrix[3]; 31 | g = (int16_t)rgb_buf[idx] * fixed_ccm_matrix[4] + (int16_t)rgb_buf[idx + 1] * fixed_ccm_matrix[5] + (int16_t)rgb_buf[idx + 2] * fixed_ccm_matrix[6] + fixed_ccm_matrix[7]; 32 | b = (int16_t)rgb_buf[idx] * fixed_ccm_matrix[8] + (int16_t)rgb_buf[idx + 1] * fixed_ccm_matrix[9] + (int16_t)rgb_buf[idx + 2] * fixed_ccm_matrix[10] + fixed_ccm_matrix[11]; 33 | 34 | r = clip_min(r, 0); 35 | g = clip_min(g, 0); 36 | b = clip_min(b, 0); 37 | 38 | rgb_buf[idx] = r >> CCM_FRACTION; 39 | rgb_buf[idx + 1] = g >> CCM_FRACTION; 40 | rgb_buf[idx + 2] = b >> CCM_FRACTION; 41 | } 42 | } 43 | 44 | 45 | } -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "isp.h" 3 | #include "opencv2/opencv.hpp" 4 | 5 | 6 | using namespace cv; 7 | isp_config_t g_isp_config; 8 | 9 | int main(int argc, char **argv) 10 | { 11 | 12 | uint16_t* raw_buf; 13 | uint8_t* rgb_buf; 14 | uint8_t* yuv_buf; 15 | uint32_t image_size; 16 | FILE* f; 17 | FILE* fyuv_out; 18 | 19 | if (argc != 2) 20 | { 21 | printf("usage: ISP_pipeline.out raw_image_path\n"); 22 | return -1; 23 | } 24 | 25 | //load isp config 26 | isp_load_config("../config.json", &g_isp_config); 27 | 28 | image_size = g_isp_config.image_height*g_isp_config.image_width; 29 | //allocate raw memory 30 | raw_buf = (uint16_t*)malloc(sizeof(uint16_t)*image_size); 31 | //allocate rgb image memory 32 | rgb_buf = (uint8_t*)malloc(sizeof(uint8_t)*image_size*3); 33 | 34 | //allocate yuv image memory 35 | yuv_buf = (uint8_t*)malloc(sizeof(uint8_t)*image_size*3); 36 | 37 | // read data 38 | f = fopen(argv[1], "rb"); 39 | fread(raw_buf, sizeof(uint16_t), image_size, f); 40 | 41 | //init isp parameters 42 | isp_init(); 43 | 44 | //run isp raw domain pipe 45 | isp_raw_run(raw_buf, rgb_buf); 46 | 47 | // run isp yuv domain pipe 48 | isp_yuv_run(rgb_buf,yuv_buf); 49 | 50 | Mat img(g_isp_config.image_height, g_isp_config.image_width, CV_8UC3, rgb_buf); 51 | cv::cvtColor(img, img, cv::COLOR_BGR2RGB); 52 | imwrite("test.png",img); 53 | 54 | fyuv_out = fopen("test.yuv", "wb"); 55 | fwrite(yuv_buf, sizeof(uint8_t)*image_size*3, 1, fyuv_out); 56 | 57 | fclose(fyuv_out); 58 | fclose(f); 59 | free(raw_buf); 60 | free(rgb_buf); 61 | free(yuv_buf); 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/json_ref.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | template 13 | class json_ref 14 | { 15 | public: 16 | using value_type = BasicJsonType; 17 | 18 | json_ref(value_type&& value) 19 | : owned_value(std::move(value)) 20 | {} 21 | 22 | json_ref(const value_type& value) 23 | : value_ref(&value) 24 | {} 25 | 26 | json_ref(std::initializer_list init) 27 | : owned_value(init) 28 | {} 29 | 30 | template < 31 | class... Args, 32 | enable_if_t::value, int> = 0 > 33 | json_ref(Args && ... args) 34 | : owned_value(std::forward(args)...) 35 | {} 36 | 37 | // class should be movable only 38 | json_ref(json_ref&&) noexcept = default; 39 | json_ref(const json_ref&) = delete; 40 | json_ref& operator=(const json_ref&) = delete; 41 | json_ref& operator=(json_ref&&) = delete; 42 | ~json_ref() = default; 43 | 44 | value_type moved_or_copied() const 45 | { 46 | if (value_ref == nullptr) 47 | { 48 | return std::move(owned_value); 49 | } 50 | return *value_ref; 51 | } 52 | 53 | value_type const& operator*() const 54 | { 55 | return value_ref ? *value_ref : owned_value; 56 | } 57 | 58 | value_type const* operator->() const 59 | { 60 | return &** this; 61 | } 62 | 63 | private: 64 | mutable value_type owned_value = nullptr; 65 | value_type const* value_ref = nullptr; 66 | }; 67 | } // namespace detail 68 | } // namespace nlohmann 69 | -------------------------------------------------------------------------------- /src/isp_blc.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | 3 | extern isp_config_t g_isp_config; 4 | void isp_blc(uint16_t *raw_buf) 5 | { 6 | uint16_t image_width; 7 | uint16_t image_height; 8 | uint16_t max_value; 9 | uint16_t bl_r, bl_gr, bl_gb, bl_b; 10 | uint16_t r, gr, gb, b; 11 | uint16_t alpha, beta; 12 | uint32_t idx; 13 | uint16_t delta_gr, delta_gb; 14 | 15 | image_width = g_isp_config.image_width; 16 | image_height = g_isp_config.image_height; 17 | max_value = (1 << g_isp_config.image_bits) - 1; 18 | bl_r = g_isp_config.blc_config.bl_r; 19 | bl_gr = g_isp_config.blc_config.bl_gr; 20 | bl_gb = g_isp_config.blc_config.bl_gb; 21 | bl_b = g_isp_config.blc_config.bl_b; 22 | 23 | alpha = g_isp_config.blc_config.alpha * (1 << BLC_FRACTION); 24 | beta = g_isp_config.blc_config.beta * (1 << BLC_FRACTION); 25 | 26 | for (int i = 2; i < image_height - 2; i += 2) 27 | { 28 | for (int j = 2; j < image_width - 2; j += 2) 29 | { 30 | idx = i * image_width + j; 31 | r = raw_buf[idx]; 32 | gr = raw_buf[idx + 1]; 33 | gb = raw_buf[idx + image_width]; 34 | b = raw_buf[idx + image_width + 1]; 35 | r = (r > bl_r) ? (r - bl_r) : 0; 36 | gr = (gr > bl_gr) ? (gr - bl_gr) : 0; 37 | gb = (gb > bl_gb) ? (gb - bl_gb) : 0; 38 | b = (b > bl_b) ? (b - bl_b) : 0; 39 | 40 | delta_gr = (r * alpha) >> BLC_FRACTION; 41 | delta_gb = (b * beta) >> BLC_FRACTION; 42 | 43 | raw_buf[idx] = r; 44 | raw_buf[idx + 1] = clip_max((gr + delta_gr), max_value); 45 | raw_buf[idx + image_width] = clip_max((gb + delta_gb), max_value); 46 | raw_buf[idx + image_width + 1] = b; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/isp_csc.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | #define CSC_FIXED_FRACTION_BITS 8 3 | extern isp_config_t g_isp_config; 4 | int16_t g_csc_mat_fixed[9]; 5 | 6 | void isp_csc_init() 7 | { 8 | 9 | for (int i = 0; i < 3; i++) 10 | { 11 | for (int j = 0; j < 3; j++) 12 | { 13 | g_csc_mat_fixed[i * 3 + j] = g_isp_config.csc_matrix[i * 4 + j] * (1 << CSC_FIXED_FRACTION_BITS) + 0.5; 14 | // printf("fixed csc[%d, %d] = %d, float csc[%d, %d] = %.2f\n", i,j,g_csc_mat_fixed[i*3+j],i,j,g_isp_config.csc_matrix[i*4+j]); 15 | } 16 | } 17 | } 18 | 19 | void isp_csc(uint8_t *rgb_buf, uint8_t *yuv_buf) 20 | { 21 | 22 | uint32_t idx; 23 | uint32_t image_size; 24 | float *csc_mat_f; 25 | csc_mat_f = g_isp_config.csc_matrix; 26 | image_size = g_isp_config.image_height * g_isp_config.image_width; 27 | isp_csc_init(); 28 | 29 | for (int i = 0; i < g_isp_config.image_height; i++) 30 | { 31 | for (int j = 0; j < g_isp_config.image_width; j++) 32 | { 33 | idx = i * g_isp_config.image_width + j; 34 | 35 | // y 36 | yuv_buf[idx] = ((g_csc_mat_fixed[0] * (int16_t)rgb_buf[3 * idx] + g_csc_mat_fixed[1] * (int16_t)rgb_buf[3 * idx + 1] + g_csc_mat_fixed[2] * (int16_t)rgb_buf[3 * idx + 2] + (1<<(CSC_FIXED_FRACTION_BITS-1))) >> CSC_FIXED_FRACTION_BITS) + 16; 37 | // u 38 | yuv_buf[idx + image_size] = ((g_csc_mat_fixed[3] * (int16_t)rgb_buf[3 * idx] + g_csc_mat_fixed[4] * (int16_t)rgb_buf[3 * idx + 1] + g_csc_mat_fixed[5] * (int16_t)rgb_buf[3 * idx + 2] + (1<<(CSC_FIXED_FRACTION_BITS-1))) >> CSC_FIXED_FRACTION_BITS) + 128; 39 | // v 40 | yuv_buf[idx + 2 * image_size] = ((g_csc_mat_fixed[6] * (int16_t)rgb_buf[3 * idx] + g_csc_mat_fixed[7] * (int16_t)rgb_buf[3 * idx + 1] + g_csc_mat_fixed[8] * (int16_t)rgb_buf[3 * idx + 2]+ (1<<(CSC_FIXED_FRACTION_BITS-1))) >> CSC_FIXED_FRACTION_BITS) + 128; 41 | 42 | 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/detected.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | // https://en.cppreference.com/w/cpp/experimental/is_detected 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | struct nonesuch 13 | { 14 | nonesuch() = delete; 15 | ~nonesuch() = delete; 16 | nonesuch(nonesuch const&) = delete; 17 | nonesuch(nonesuch const&&) = delete; 18 | void operator=(nonesuch const&) = delete; 19 | void operator=(nonesuch&&) = delete; 20 | }; 21 | 22 | template class Op, 25 | class... Args> 26 | struct detector 27 | { 28 | using value_t = std::false_type; 29 | using type = Default; 30 | }; 31 | 32 | template class Op, class... Args> 33 | struct detector>, Op, Args...> 34 | { 35 | using value_t = std::true_type; 36 | using type = Op; 37 | }; 38 | 39 | template class Op, class... Args> 40 | using is_detected = typename detector::value_t; 41 | 42 | template class Op, class... Args> 43 | struct is_detected_lazy : is_detected { }; 44 | 45 | template class Op, class... Args> 46 | using detected_t = typename detector::type; 47 | 48 | template class Op, class... Args> 49 | using detected_or = detector; 50 | 51 | template class Op, class... Args> 52 | using detected_or_t = typename detected_or::type; 53 | 54 | template class Op, class... Args> 55 | using is_detected_exact = std::is_same>; 56 | 57 | template class Op, class... Args> 58 | using is_detected_convertible = 59 | std::is_convertible, To>; 60 | } // namespace detail 61 | } // namespace nlohmann 62 | -------------------------------------------------------------------------------- /src/isp_awb.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | extern isp_config_t g_isp_config; 3 | 4 | void isp_awb_gain(uint16_t *raw_buf) 5 | { 6 | 7 | uint16_t image_height, image_width; 8 | uint16_t max_value; 9 | uint32_t idx; 10 | uint32_t tmp; 11 | uint8_t r_gain, gr_gain, gb_gain, b_gain; 12 | string bayer_pattern; 13 | 14 | image_width = g_isp_config.image_width; 15 | image_height = g_isp_config.image_height; 16 | max_value = (1 << g_isp_config.image_bits) - 1; 17 | bayer_pattern = g_isp_config.bayer_pattern; 18 | 19 | r_gain = (uint8_t)(g_isp_config.awb_gain.r_gain * (1 << GAIN_FRACTION_BITS)); 20 | gr_gain = (uint8_t)(g_isp_config.awb_gain.gr_gain * (1 << GAIN_FRACTION_BITS)); 21 | gb_gain = (uint8_t)(g_isp_config.awb_gain.gb_gain * (1 << GAIN_FRACTION_BITS)); 22 | b_gain = (uint8_t)(g_isp_config.awb_gain.b_gain * (1 << GAIN_FRACTION_BITS)); 23 | 24 | if (bayer_pattern.compare("rggb") == 0) 25 | { 26 | for (uint16_t i = 0; i < image_height; i += 2) 27 | { 28 | for (uint16_t j = 0; j < image_width; j += 2) 29 | { 30 | idx = i * image_width + j; 31 | tmp = (r_gain * raw_buf[idx]) >> GAIN_FRACTION_BITS; 32 | raw_buf[idx] = clip_max(tmp, max_value); 33 | idx += 1; 34 | tmp = (gr_gain * raw_buf[idx]) >> GAIN_FRACTION_BITS; 35 | raw_buf[idx] = clip_max(tmp, max_value); 36 | idx += image_width; 37 | tmp = (b_gain * raw_buf[idx]) >> GAIN_FRACTION_BITS; 38 | raw_buf[idx] = clip_max(tmp, max_value); 39 | idx -= 1; 40 | tmp = (gb_gain * raw_buf[idx]) >> GAIN_FRACTION_BITS; 41 | raw_buf[idx] = clip_max(tmp, max_value); 42 | } 43 | } 44 | } 45 | else 46 | { 47 | cout << "-----------awb gain control--------------" << endl; 48 | cout << "Oppos! Bayer pattern " << g_isp_config.bayer_pattern << " not implemented yet..." << endl; 49 | cout << "bye bye QQ~" << endl; 50 | } 51 | } -------------------------------------------------------------------------------- /src/isp_hsc.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | #include 3 | 4 | #define PI 3.14159265 5 | #define HSC_SAT_FRACTION_BIT 6 6 | #define COS_SIN_FRATION_BIT 6 7 | 8 | extern isp_config_t g_isp_config; 9 | 10 | void isp_hsc(uint8_t *cbcr_image) 11 | { 12 | uint32_t image_size; 13 | uint16_t image_width, image_height; 14 | int16_t fixed_saturation = g_isp_config.hsc_config.saturation_gain * (1 << HSC_SAT_FRACTION_BIT); 15 | int16_t cb, cr; 16 | double hue_offset = g_isp_config.hsc_config.hue_offset; 17 | double cos_theta, sin_theta; 18 | int8_t fixed_cos_theta, fixed_sin_theta; 19 | 20 | image_width = g_isp_config.image_width; 21 | image_height = g_isp_config.image_height; 22 | image_size = image_width * image_height; 23 | 24 | cos_theta = cos(hue_offset / 180 * PI); 25 | sin_theta = sin(hue_offset / 180 * PI); 26 | 27 | fixed_cos_theta = cos_theta * (1 << COS_SIN_FRATION_BIT); 28 | fixed_sin_theta = sin_theta * (1 << COS_SIN_FRATION_BIT); 29 | 30 | for (int i = 0; i < image_height; i++) 31 | { 32 | for (int j = 0; j < image_width; j++) 33 | { 34 | cb = cbcr_image[i * image_width + j]; 35 | cr = cbcr_image[image_size + i * image_width + j]; 36 | cb = (((cb - 128) * fixed_cos_theta + (cr - 128) * fixed_sin_theta) >> COS_SIN_FRATION_BIT) + 128; 37 | cr = (((cr - 128) * fixed_cos_theta + (cb - 128) * fixed_sin_theta) >> COS_SIN_FRATION_BIT) + 128; 38 | 39 | cb = clip_max(cb,255); 40 | cb = clip_min(cb,0); 41 | cr = clip_max(cr,255); 42 | cr = clip_min(cr,0); 43 | 44 | cb = ((fixed_saturation*(cb -128)) >> HSC_SAT_FRACTION_BIT) +128; 45 | cr = ((fixed_saturation*(cr -128)) >> HSC_SAT_FRACTION_BIT) +128; 46 | 47 | cb = clip_max(cb,255); 48 | cb = clip_min(cb,0); 49 | cr = clip_max(cr,255); 50 | cr = clip_min(cr,0); 51 | 52 | cbcr_image[i * image_width + j] = cb; 53 | cbcr_image[image_size + i * image_width + j] = cr; 54 | 55 | 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/string_escape.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace nlohmann 6 | { 7 | namespace detail 8 | { 9 | 10 | /*! 11 | @brief replace all occurrences of a substring by another string 12 | 13 | @param[in,out] s the string to manipulate; changed so that all 14 | occurrences of @a f are replaced with @a t 15 | @param[in] f the substring to replace with @a t 16 | @param[in] t the string to replace @a f 17 | 18 | @pre The search string @a f must not be empty. **This precondition is 19 | enforced with an assertion.** 20 | 21 | @since version 2.0.0 22 | */ 23 | template 24 | inline void replace_substring(StringType& s, const StringType& f, 25 | const StringType& t) 26 | { 27 | JSON_ASSERT(!f.empty()); 28 | for (auto pos = s.find(f); // find first occurrence of f 29 | pos != StringType::npos; // make sure f was found 30 | s.replace(pos, f.size(), t), // replace with t, and 31 | pos = s.find(f, pos + t.size())) // find next occurrence of f 32 | {} 33 | } 34 | 35 | /*! 36 | * @brief string escaping as described in RFC 6901 (Sect. 4) 37 | * @param[in] s string to escape 38 | * @return escaped string 39 | * 40 | * Note the order of escaping "~" to "~0" and "/" to "~1" is important. 41 | */ 42 | template 43 | inline StringType escape(StringType s) 44 | { 45 | replace_substring(s, StringType{"~"}, StringType{"~0"}); 46 | replace_substring(s, StringType{"/"}, StringType{"~1"}); 47 | return s; 48 | } 49 | 50 | /*! 51 | * @brief string unescaping as described in RFC 6901 (Sect. 4) 52 | * @param[in] s string to unescape 53 | * @return unescaped string 54 | * 55 | * Note the order of escaping "~1" to "/" and "~0" to "~" is important. 56 | */ 57 | template 58 | static void unescape(StringType& s) 59 | { 60 | replace_substring(s, StringType{"~1"}, StringType{"/"}); 61 | replace_substring(s, StringType{"~0"}, StringType{"~"}); 62 | } 63 | 64 | } // namespace detail 65 | } // namespace nlohmann 66 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "width": 1920, 3 | "height": 1080, 4 | "image_bits": 10, 5 | "blc": { 6 | "bl_r": 0, 7 | "bl_gr": 0, 8 | "bl_gb": 0, 9 | "bl_b": 0, 10 | "alpha": 0.0, 11 | "beta": 0.0 12 | }, 13 | "dpc": { 14 | "dead_thres": 30, 15 | "mode": "gradient" 16 | }, 17 | "bayer_pattern": "rggb", 18 | "cfa_mode": "malvar", 19 | "awb_gain": { 20 | "r_gain": 1.5, 21 | "gr_gain": 1.0, 22 | "gb_gain": 1.0, 23 | "b_gain": 1.1 24 | }, 25 | "ccm": [ 26 | [ 27 | 1.0, 28 | 0.0, 29 | 0.0, 30 | 0.0 31 | ], 32 | [ 33 | 0.0, 34 | 1.0, 35 | 0.0, 36 | 0.0 37 | ], 38 | [ 39 | 0.0, 40 | 0.0, 41 | 1.0, 42 | 0.0 43 | ] 44 | ], 45 | "gamma": 0.8, 46 | "csc": [ 47 | [0.2568,0.5041,0.0979,16], 48 | [-0.1482,-0.291,0.4392,128], 49 | [0.4392,-0.3678,-0.0714,128] 50 | ], 51 | "nlm":{ 52 | "Ds":4, 53 | "ds":1, 54 | "h":5 55 | }, 56 | "bnf":{ 57 | "dw":[ 58 | [8,12,32,12,8], 59 | [12,64,128,64,12], 60 | [32,128,1024,128,32], 61 | [12,64,128,64,12], 62 | [8,12,32,12,8] 63 | ], 64 | "rw":[0,8,16,32], 65 | "rthres":[128,32,8] 66 | }, 67 | "edge_filter":[ 68 | [-1,0,-1,0,-1], 69 | [-1,0,8,0,-1], 70 | [-1,0,-1,0,-1] 71 | ], 72 | "eeh":{ 73 | "gain_min":32, 74 | "gain_max":128, 75 | "thres_min":4, 76 | "thres_max":16, 77 | "em_clip_min":-64, 78 | "em_clip_max":64 79 | }, 80 | "fcs":{ 81 | "edge_min":32, 82 | "edge_max":64 83 | }, 84 | "hsc":{ 85 | "hue_offset":0, 86 | "saturation_gain":1.3 87 | }, 88 | "bcc":{ 89 | "brightness":0, 90 | "contrast":1.1 91 | } 92 | 93 | 94 | 95 | 96 | } -------------------------------------------------------------------------------- /inc/nlohmann/adl_serializer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace nlohmann 12 | { 13 | 14 | /// @sa https://json.nlohmann.me/api/adl_serializer/ 15 | template 16 | struct adl_serializer 17 | { 18 | /// @brief convert a JSON value to any value type 19 | /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ 20 | template 21 | static auto from_json(BasicJsonType && j, TargetType& val) noexcept( 22 | noexcept(::nlohmann::from_json(std::forward(j), val))) 23 | -> decltype(::nlohmann::from_json(std::forward(j), val), void()) 24 | { 25 | ::nlohmann::from_json(std::forward(j), val); 26 | } 27 | 28 | /// @brief convert a JSON value to any value type 29 | /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ 30 | template 31 | static auto from_json(BasicJsonType && j) noexcept( 32 | noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) 33 | -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) 34 | { 35 | return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); 36 | } 37 | 38 | /// @brief convert any value type to a JSON value 39 | /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ 40 | template 41 | static auto to_json(BasicJsonType& j, TargetType && val) noexcept( 42 | noexcept(::nlohmann::to_json(j, std::forward(val)))) 43 | -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) 44 | { 45 | ::nlohmann::to_json(j, std::forward(val)); 46 | } 47 | }; 48 | } // namespace nlohmann 49 | -------------------------------------------------------------------------------- /inc/nlohmann/json_fwd.hpp: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ 2 | #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ 3 | 4 | #include // int64_t, uint64_t 5 | #include // map 6 | #include // allocator 7 | #include // string 8 | #include // vector 9 | 10 | /*! 11 | @brief namespace for Niels Lohmann 12 | @see https://github.com/nlohmann 13 | @since version 1.0.0 14 | */ 15 | namespace nlohmann 16 | { 17 | /*! 18 | @brief default JSONSerializer template argument 19 | 20 | This serializer ignores the template arguments and uses ADL 21 | ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) 22 | for serialization. 23 | */ 24 | template 25 | struct adl_serializer; 26 | 27 | /// a class to store JSON values 28 | /// @sa https://json.nlohmann.me/api/basic_json/ 29 | template class ObjectType = 30 | std::map, 31 | template class ArrayType = std::vector, 32 | class StringType = std::string, class BooleanType = bool, 33 | class NumberIntegerType = std::int64_t, 34 | class NumberUnsignedType = std::uint64_t, 35 | class NumberFloatType = double, 36 | template class AllocatorType = std::allocator, 37 | template class JSONSerializer = 38 | adl_serializer, 39 | class BinaryType = std::vector> 40 | class basic_json; 41 | 42 | /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document 43 | /// @sa https://json.nlohmann.me/api/json_pointer/ 44 | template 45 | class json_pointer; 46 | 47 | /*! 48 | @brief default specialization 49 | @sa https://json.nlohmann.me/api/json/ 50 | */ 51 | using json = basic_json<>; 52 | 53 | /// @brief a minimal map-like container that preserves insertion order 54 | /// @sa https://json.nlohmann.me/api/ordered_map/ 55 | template 56 | struct ordered_map; 57 | 58 | /// @brief specialization that maintains the insertion order of object keys 59 | /// @sa https://json.nlohmann.me/api/ordered_json/ 60 | using ordered_json = basic_json; 61 | 62 | } // namespace nlohmann 63 | 64 | #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ 65 | -------------------------------------------------------------------------------- /src/isp_fcs.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | extern isp_config_t g_isp_config; 3 | 4 | 5 | void isp_fcs(uint8_t *cbcr_image,int8_t *edge_map){ 6 | 7 | uint8_t edge; 8 | int32_t slop; 9 | int32_t gain; 10 | int16_t cb; 11 | int16_t cr; 12 | uint32_t image_size = g_isp_config.image_width*g_isp_config.image_height; 13 | 14 | slop = -(1.0/(g_isp_config.fcs_config.edge_max-g_isp_config.fcs_config.edge_min))*(1<<16); 15 | 16 | 17 | for(int i = 0; i < g_isp_config.image_height; i++){ 18 | for(int j = 0; j < g_isp_config.image_width;j++){ 19 | 20 | edge = abs(edge_map[i*g_isp_config.image_width+j]); 21 | 22 | cb = cbcr_image[i*g_isp_config.image_width+j]; 23 | cr = cbcr_image[image_size + i*g_isp_config.image_width+j]; 24 | 25 | if (edge < g_isp_config.fcs_config.edge_min){ 26 | //not edge, Cb Cr maintain 27 | cbcr_image[i*g_isp_config.image_width+j] = cb; 28 | cbcr_image[image_size + i*g_isp_config.image_width+j] = cr; 29 | 30 | }else if(edge >= g_isp_config.fcs_config.edge_min && edge <= g_isp_config.fcs_config.edge_max){ 31 | // with gain 32 | gain = slop * (int32_t)(g_isp_config.fcs_config.edge_max - edge); 33 | cb = ((gain * (cb-128)) >> 16) + 128; 34 | cr = ((gain * (cr-128)) >> 16) + 128; 35 | cb = clip_max(cb,255); 36 | cr = clip_max(cr,255); 37 | cb = clip_min(cb,0); 38 | cr = clip_min(cr,0); 39 | cbcr_image[i*g_isp_config.image_width+j] = cb; 40 | cbcr_image[image_size + i*g_isp_config.image_width+j] = cr; 41 | 42 | 43 | 44 | }else if(edge > g_isp_config.fcs_config.edge_max){ 45 | // this is weird...why color is black in edge pixel.? 46 | //is edge, Cb, Cr ==0 47 | // dst_image[i*g_isp_config.image_width+j] = 128; 48 | // dst_image[image_size + i*g_isp_config.image_width+j] = 128; 49 | 50 | //is edge, Cb, Cr maitain 51 | cbcr_image[i*g_isp_config.image_width+j] = cb; 52 | cbcr_image[image_size + i*g_isp_config.image_width+j] = cr; 53 | 54 | 55 | } 56 | 57 | } 58 | } 59 | 60 | 61 | 62 | } -------------------------------------------------------------------------------- /image/deaft.drawio: -------------------------------------------------------------------------------- 1 | 7Vxbl6I4EP41PnYfSADxUe3LzDk9M73buzvT+7InQlSmkTghduv8+km4KCSotCKgO/ZDkyJE+aq+qlSF0IHD2fKeovn0E3Gx3wGau+zAmw4AQLMA/yckq1iiA2DGkgn13ES2ETx5P3Ei1BLpwnNxmOvICPGZN88LHRIE2GE5GaKUvOW7jYmf/9Y5mmBF8OQgX5V+9Vw2jaU26G7kH7A3mabfrFu9+MwMpZ2TOwmnyCVvGRG87cAhJYTFR7PlEPsCvRSX+Lq7LWfXP4zigJW54O2hN0STf1afl/37P/4cdedL7+4qGeUV+Yvkhh9wECY/mK1SFPhIHHDeGLxNPYaf5sgRZ9640rlsymY+b+n8UP1R6TdgyvAyI0p+5D0mM8zoindJz3YTwFZS+22Dv5mIplnoUyFKVD5ZD71BhR8kwLwDpPQesoC43EqSJqFsSiYkQP7tRjqgZBG4WAyr8damzwMh8wSs75ixVWLyaMFIHkq89Ni3zPGzGOraTFo3y2TkqLFKGwG/32/ZRuYq0dxcFrXS67aqLSQL6uBd2CScRHSC2Y5+MO4ncNtpBBT7iHmvefZVr1HF7D/OhCMA2hM3f0IVfee1eXoSAJgnwdptZkig6wUssMxTQQbOhQSHGzMsacxGq4wZKsZ8g5HLJY/eMgrHQ0Ipj40eCY6z67Hn+0Pic3qIa+F4PAaOw+Uho+QFZ8641sgyrWqYAO3WMQGeCxPqDwdGSQaZrWKQoTBo4CPnhYse8GtCodmcRwZ0piQyQetIZDRBosMN2yxp2FarDNtUDLsDLJ8JMyQcAZE2pfZm/ViITIRDBJ3okxVZE/E/Tg20J57IeMGES9FMGHcwCudxr2jkEU37Z+NOfI7fRPzFcYfjmKQwZhh9qmGM1W0dY8wmw84m1DxnzuwLO5tI85wLNFWHHaskO7tVszO6tE8pWmU6zIkXsDAz8qMQbGzL7po524KalLlL/Q24sz8/iH/BxrbWt3K4uVkHuY74o7qOfsC8K+R7KIw8h/aZeKFIt+48n2Faj3tYB9RtIbgCt2G3L9B2G3Ebtc88uyVdgN2qAN1VWNb/OtgfWe+RF0SzUg4e8c9wQipnddBSi3w188RuMry2O6uzS3IrVVhLyGUr5Bre9TvCQ8t8+hjwKDQn/qXkd83TCTZaLmz3bLVXlk6gVXTqKXS6R7MZKiTUiUqOLsL2uJBNlmPj0fg0k7jm2QR6/49JXArqXmr0WsWM9GdnI01kmvuoIc/zzo4qcpmkearAZqrzKVX02qgCykaRltXatUb0cxYTg/I6rbyQdZz/A1v9X+yvolSVe5Ww8um1Kf4KvVz0ScpVGXlSoTrJRMHoNe399EbXJt/DrsNZUnaNsWWr9OoiYxOqOsI5lV0C09u1Bqari2By9VkbR75qOKVE5DNVzsJMbLtGkX+ywQhaFaX/8iyseT8Em1msqj9il115Au0qjenq8s6HRfT8G2ILmpTBTlJfrocRckGsBYxoJoVPI/Mh9eX6cpmyizd6u1ZvdHX5ZktoeVicZWCRJ7im3TiNGl2maTmNSq/TtKx8pi7UCO0VVs9ugykKHDwT4Jwfn+SJWgv4ZDU6UauPG2UXXdo2UVNXXaJZGQqZSg65oDygwoICHIZFZehLmdvVSiJn9eHu21ff+vTvo/NMXawbtnOlN7JB6N2Frf2beSq3/eIH2qCR16Clg2tJNzFPk+sk9VTwdBtQV2xuEEP7n7y5I3SGWDS1OzviwCajTyFx1JqYJ/ZhXY/QqgDhcIrm4nBOiSN82l6UR8h5mUR6+bJgvhfgPcxR0K+yWAwlt1W0r9EuAD/lSuXgFz3hKXuxwO2LTbS8FRAB38BF4TQycj0Pdd76twGcKdBY+cjfs9fnt8T+qPWIqcfvHtN9E4JsnN9lentd3Z5dp6nsWI9o5o0DWJLWY9+t+ENlILMncVyTBqrOsRbCqmbEMaPpZHRhfLakLZpQb5jPahZVJ58NkCu56tcarJnRZddE62G0JTEa9s6U0WoCEjN6tXi9MEZ3rTzShtEwowueK6qT0nlCH5qa7+Vt2WJUPby1dYluoCLewpp5W/BQxqUSF0i+1uyt88mmqAvUXfkK6AK/efnbX7/kBo3SEbSdsOiaJttywW6kbgEsumz01eGiWqWCy/sy6QoMbrcG95thc3DqJZ4qqX3X3LFwrt8elTNeoAZjUID16aAu2kxdKdTrB3O3PcpbF9Rm01CXKE0cB/W6rLatEFcX1AUluHqhVhP2pPimuWQWbTOUgOf3yXahm8xCs8AmIuR7k4A3HRxE+d5AoOY5yO8nJ2ae60a18SJ1lpu+nkxvUslaL4ikWoHi4MkUp6b7UY3lt9ryVdf81nmjcbWp6XQ0H/+ttl1q69aoth///fjr+/OT8XD188uNP5j3Xh7/LnhhnD3ymPqixHaoawvaBWnG9id/5FpIQepg1akBNZ/StctWAZTfAViwt6pWFai5xqWroCtvb+udjAW8uXkXbFwD2rxSF97+Ag== -------------------------------------------------------------------------------- /src/isp_bnf.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | /* Bilateral Noise Filter*/ 3 | 4 | extern isp_config_t g_isp_config; 5 | 6 | void isp_bnf(uint8_t *src_image, uint8_t *dst_image) 7 | { 8 | 9 | uint8_t kernel_size = 5; 10 | uint8_t half_kernel_size = kernel_size >> 1; 11 | uint16_t *cw = (uint16_t *)malloc(sizeof(uint16_t) * (kernel_size * kernel_size)); //color weight 12 | uint16_t *weights = (uint16_t *)malloc(sizeof(uint16_t) * (kernel_size * kernel_size)); // bnf weight 13 | uint8_t center_value, value, diff_value; 14 | uint32_t weight_sum; 15 | uint32_t value_sum; 16 | for (int i = 0; i < g_isp_config.image_height - kernel_size; i++) 17 | { 18 | for (int j = 0; j < g_isp_config.image_width - kernel_size; j++) 19 | { 20 | 21 | center_value = src_image[(i + half_kernel_size) * g_isp_config.image_width + (j + half_kernel_size)]; 22 | for (int m = 0; m < kernel_size; m++) 23 | { 24 | for (int n = 0; n < kernel_size; n++) 25 | { 26 | value = src_image[(i + m) * g_isp_config.image_width + (j + n)]; 27 | diff_value = center_value > value ? (center_value - value) : (value - center_value); 28 | if (diff_value >= g_isp_config.bnf_config.rthres[0]) 29 | { 30 | 31 | cw[n * kernel_size + n] = g_isp_config.bnf_config.rw[0]; 32 | } 33 | else if ((diff_value < g_isp_config.bnf_config.rthres[0]) && (diff_value >= g_isp_config.bnf_config.rthres[1])) 34 | { 35 | cw[n * kernel_size + n] = g_isp_config.bnf_config.rw[1]; 36 | } 37 | else if ((diff_value < g_isp_config.bnf_config.rthres[1]) && (diff_value >= g_isp_config.bnf_config.rthres[2])) 38 | { 39 | cw[n * kernel_size + n] = g_isp_config.bnf_config.rw[2]; 40 | } 41 | else if (diff_value < g_isp_config.bnf_config.rthres[2]) 42 | { 43 | cw[n * kernel_size + n] = g_isp_config.bnf_config.rw[3]; 44 | } 45 | } 46 | } 47 | //mutiply color weight and space wieght 48 | weight_sum = 0; 49 | value_sum = 0; 50 | for (int m = 0; m < kernel_size; m++) 51 | { 52 | for (int n = 0; n < kernel_size; n++) 53 | { 54 | weights[m * kernel_size + n] = g_isp_config.bnf_config.dw[m * kernel_size + n] * cw[m * kernel_size + n]; 55 | value_sum += weights[m * kernel_size + n] * src_image[(i + m) * g_isp_config.image_width + (j + n)]; 56 | weight_sum += weights[m * kernel_size + n]; 57 | } 58 | } 59 | 60 | dst_image[(i + half_kernel_size) * g_isp_config.image_width + (j + half_kernel_size)] = value_sum/weight_sum; 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/isp_gac.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | #include 3 | extern isp_config_t g_isp_config; 4 | extern uint16_t g_table_size; 5 | 6 | void isp_gac(uint16_t *rgb_buf, uint8_t *gamma_table, uint16_t table_size, uint8_t *ga_rgb_buf) 7 | { 8 | uint16_t image_width; 9 | uint16_t image_height; 10 | uint32_t idx; 11 | uint16_t in_max_value, out_max_value; 12 | uint16_t value; 13 | uint8_t l_value, r_value; 14 | uint16_t l_idx, r_idx; 15 | uint8_t diff_r, diff_l; 16 | image_width = g_isp_config.image_width; 17 | image_height = g_isp_config.image_height; 18 | in_max_value = (1 << g_isp_config.image_bits) - 1; 19 | out_max_value = (1 << 8) - 1; 20 | 21 | 22 | for (int i = 0; i < image_height; i++) 23 | { 24 | for (int j = 0; j < image_width; j++) 25 | { 26 | idx = 3 * (i * image_width + j); 27 | 28 | // calculate r 29 | value = rgb_buf[idx]; 30 | l_idx = value >> GAMMA_STEP; 31 | r_idx = l_idx + 1; 32 | 33 | if(r_idx < g_table_size){ 34 | l_value = gamma_table[l_idx]; 35 | r_value = gamma_table[r_idx]; 36 | diff_l = value - (l_idx << GAMMA_STEP); 37 | diff_r = (r_idx << GAMMA_STEP) - value; 38 | value = (l_value * diff_r + r_value * diff_l) >> GAMMA_STEP; 39 | 40 | }else{ 41 | value = in_max_value; 42 | 43 | } 44 | 45 | ga_rgb_buf[idx] = clip_max(value, 255); 46 | 47 | // calculate g 48 | value = rgb_buf[idx + 1]; 49 | l_idx = value >> GAMMA_STEP; 50 | r_idx = l_idx + 1; 51 | 52 | if(r_idx < g_table_size){ 53 | l_value = gamma_table[l_idx]; 54 | r_value = gamma_table[r_idx]; 55 | diff_l = value - (l_idx << GAMMA_STEP); 56 | diff_r = (r_idx << GAMMA_STEP) - value; 57 | value = (l_value * diff_r + r_value * diff_l) >> GAMMA_STEP; 58 | 59 | }else{ 60 | value = in_max_value; 61 | 62 | } 63 | 64 | 65 | ga_rgb_buf[idx + 1] = clip_max(value, 255); 66 | 67 | // calculate b 68 | value = rgb_buf[idx + 2]; 69 | l_idx = value >> GAMMA_STEP; 70 | r_idx = l_idx + 1; 71 | 72 | if(r_idx < g_table_size){ 73 | l_value = gamma_table[l_idx]; 74 | r_value = gamma_table[r_idx]; 75 | diff_l = value - (l_idx << GAMMA_STEP); 76 | diff_r = (r_idx << GAMMA_STEP) - value; 77 | value = (l_value * diff_r + r_value * diff_l) >> GAMMA_STEP; 78 | 79 | }else{ 80 | value = in_max_value; 81 | 82 | } 83 | 84 | 85 | ga_rgb_buf[idx + 2] = clip_max(value, 255); 86 | 87 | 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /inc/nlohmann/byte_container_with_subtype.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uint8_t, uint64_t 4 | #include // tie 5 | #include // move 6 | 7 | namespace nlohmann 8 | { 9 | 10 | /// @brief an internal type for a backed binary type 11 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/ 12 | template 13 | class byte_container_with_subtype : public BinaryType 14 | { 15 | public: 16 | using container_type = BinaryType; 17 | using subtype_type = std::uint64_t; 18 | 19 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 20 | byte_container_with_subtype() noexcept(noexcept(container_type())) 21 | : container_type() 22 | {} 23 | 24 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 25 | byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) 26 | : container_type(b) 27 | {} 28 | 29 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 30 | byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) 31 | : container_type(std::move(b)) 32 | {} 33 | 34 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 35 | byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) 36 | : container_type(b) 37 | , m_subtype(subtype_) 38 | , m_has_subtype(true) 39 | {} 40 | 41 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ 42 | byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) 43 | : container_type(std::move(b)) 44 | , m_subtype(subtype_) 45 | , m_has_subtype(true) 46 | {} 47 | 48 | bool operator==(const byte_container_with_subtype& rhs) const 49 | { 50 | return std::tie(static_cast(*this), m_subtype, m_has_subtype) == 51 | std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); 52 | } 53 | 54 | bool operator!=(const byte_container_with_subtype& rhs) const 55 | { 56 | return !(rhs == *this); 57 | } 58 | 59 | /// @brief sets the binary subtype 60 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/ 61 | void set_subtype(subtype_type subtype_) noexcept 62 | { 63 | m_subtype = subtype_; 64 | m_has_subtype = true; 65 | } 66 | 67 | /// @brief return the binary subtype 68 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/ 69 | constexpr subtype_type subtype() const noexcept 70 | { 71 | return m_has_subtype ? m_subtype : static_cast(-1); 72 | } 73 | 74 | /// @brief return whether the value has a subtype 75 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/ 76 | constexpr bool has_subtype() const noexcept 77 | { 78 | return m_has_subtype; 79 | } 80 | 81 | /// @brief clears the binary subtype 82 | /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/ 83 | void clear_subtype() noexcept 84 | { 85 | m_subtype = 0; 86 | m_has_subtype = false; 87 | } 88 | 89 | private: 90 | subtype_type m_subtype = 0; 91 | bool m_has_subtype = false; 92 | }; 93 | 94 | } // namespace nlohmann 95 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/primitive_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // ptrdiff_t 4 | #include // numeric_limits 5 | 6 | #include 7 | 8 | namespace nlohmann 9 | { 10 | namespace detail 11 | { 12 | /* 13 | @brief an iterator for primitive JSON types 14 | 15 | This class models an iterator for primitive JSON types (boolean, number, 16 | string). It's only purpose is to allow the iterator/const_iterator classes 17 | to "iterate" over primitive values. Internally, the iterator is modeled by 18 | a `difference_type` variable. Value begin_value (`0`) models the begin, 19 | end_value (`1`) models past the end. 20 | */ 21 | class primitive_iterator_t 22 | { 23 | private: 24 | using difference_type = std::ptrdiff_t; 25 | static constexpr difference_type begin_value = 0; 26 | static constexpr difference_type end_value = begin_value + 1; 27 | 28 | JSON_PRIVATE_UNLESS_TESTED: 29 | /// iterator as signed integer type 30 | difference_type m_it = (std::numeric_limits::min)(); 31 | 32 | public: 33 | constexpr difference_type get_value() const noexcept 34 | { 35 | return m_it; 36 | } 37 | 38 | /// set iterator to a defined beginning 39 | void set_begin() noexcept 40 | { 41 | m_it = begin_value; 42 | } 43 | 44 | /// set iterator to a defined past the end 45 | void set_end() noexcept 46 | { 47 | m_it = end_value; 48 | } 49 | 50 | /// return whether the iterator can be dereferenced 51 | constexpr bool is_begin() const noexcept 52 | { 53 | return m_it == begin_value; 54 | } 55 | 56 | /// return whether the iterator is at end 57 | constexpr bool is_end() const noexcept 58 | { 59 | return m_it == end_value; 60 | } 61 | 62 | friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 63 | { 64 | return lhs.m_it == rhs.m_it; 65 | } 66 | 67 | friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 68 | { 69 | return lhs.m_it < rhs.m_it; 70 | } 71 | 72 | primitive_iterator_t operator+(difference_type n) noexcept 73 | { 74 | auto result = *this; 75 | result += n; 76 | return result; 77 | } 78 | 79 | friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept 80 | { 81 | return lhs.m_it - rhs.m_it; 82 | } 83 | 84 | primitive_iterator_t& operator++() noexcept 85 | { 86 | ++m_it; 87 | return *this; 88 | } 89 | 90 | primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) 91 | { 92 | auto result = *this; 93 | ++m_it; 94 | return result; 95 | } 96 | 97 | primitive_iterator_t& operator--() noexcept 98 | { 99 | --m_it; 100 | return *this; 101 | } 102 | 103 | primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) 104 | { 105 | auto result = *this; 106 | --m_it; 107 | return result; 108 | } 109 | 110 | primitive_iterator_t& operator+=(difference_type n) noexcept 111 | { 112 | m_it += n; 113 | return *this; 114 | } 115 | 116 | primitive_iterator_t& operator-=(difference_type n) noexcept 117 | { 118 | m_it -= n; 119 | return *this; 120 | } 121 | }; 122 | } // namespace detail 123 | } // namespace nlohmann 124 | -------------------------------------------------------------------------------- /src/isp_eeh.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | extern isp_config_t g_isp_config; 3 | 4 | int8_t emlut(int16_t value) 5 | { 6 | int32_t lut = 0; 7 | int8_t out_lut = 0; 8 | if (value < -g_isp_config.eeh_config.thres_max) 9 | { 10 | // value < -x2 11 | lut = g_isp_config.eeh_config.gain_max * value; 12 | } 13 | else if (value >= -g_isp_config.eeh_config.thres_max && value < -g_isp_config.eeh_config.thres_min) 14 | { 15 | // -x2 = -g_isp_config.eeh_config.thres_min && value < g_isp_config.eeh_config.thres_min) 19 | { 20 | //-x1 < value < x1, is noise 21 | lut = -g_isp_config.eeh_config.gain_min * value; 22 | } 23 | else if (value >= g_isp_config.eeh_config.thres_min && value < g_isp_config.eeh_config.thres_max) 24 | { 25 | // x1 = g_isp_config.eeh_config.thres_max) 29 | { 30 | // value > x2 31 | lut = g_isp_config.eeh_config.gain_max * value; 32 | } 33 | lut = lut >> 8; 34 | out_lut = lut > g_isp_config.eeh_config.em_clip_max ? g_isp_config.eeh_config.em_clip_max : lut; 35 | out_lut = lut < g_isp_config.eeh_config.em_clip_min ? g_isp_config.eeh_config.em_clip_min : lut; 36 | 37 | return out_lut; 38 | } 39 | 40 | void create_edge_map(uint8_t* src_image, int8_t* edge_map){ 41 | 42 | int edge_filter_h = 3; 43 | int edge_filter_w = 5; 44 | int half_edge_filter_h = edge_filter_h >> 1; 45 | int half_edge_filter_w = edge_filter_w >> 1; 46 | 47 | int16_t edge_value, value_sum; 48 | int8_t value; 49 | 50 | for (int i = 0; i < g_isp_config.image_height - edge_filter_h; i++) 51 | { 52 | for (int j = 0; j < g_isp_config.image_width - edge_filter_w; j++) 53 | { 54 | value_sum = 0; 55 | for (int m = 0; m < edge_filter_h; m++) 56 | { 57 | for (int n = 0; n < edge_filter_w; n++) 58 | { 59 | value_sum += g_isp_config.edge_filter[m * edge_filter_w + n] * (int16_t)src_image[(i + m) * g_isp_config.image_width + (j + n)]; 60 | } 61 | } 62 | 63 | value = value_sum >> 3; 64 | 65 | edge_map[(i + half_edge_filter_h) * g_isp_config.image_width + (j + half_edge_filter_w)] = value; 66 | 67 | 68 | } 69 | } 70 | 71 | 72 | 73 | } 74 | 75 | void isp_eeh(uint8_t *y_image, int8_t *edge_map) 76 | { 77 | 78 | int edge_filter_h = 3; 79 | int edge_filter_w = 5; 80 | int half_edge_filter_h = edge_filter_h >> 1; 81 | int half_edge_filter_w = edge_filter_w >> 1; 82 | 83 | int8_t value; 84 | int8_t lut; 85 | int16_t new_value; 86 | 87 | create_edge_map(y_image, edge_map); 88 | 89 | for (int i = 0; i < g_isp_config.image_height - edge_filter_h; i++) 90 | { 91 | for (int j = 0; j < g_isp_config.image_width - edge_filter_w; j++) 92 | { 93 | 94 | value = edge_map[(i + half_edge_filter_h) * g_isp_config.image_width + (j + half_edge_filter_w)]; 95 | 96 | lut = emlut(value); 97 | 98 | new_value = y_image[(i + half_edge_filter_h) * g_isp_config.image_width + (j + half_edge_filter_w)] + lut; 99 | new_value = clip_max(new_value,255); 100 | new_value = clip_min(new_value,0); 101 | 102 | y_image[(i + half_edge_filter_h) * g_isp_config.image_width + (j + half_edge_filter_w)] = new_value; 103 | 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/json_reverse_iterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // ptrdiff_t 4 | #include // reverse_iterator 5 | #include // declval 6 | 7 | namespace nlohmann 8 | { 9 | namespace detail 10 | { 11 | ////////////////////// 12 | // reverse_iterator // 13 | ////////////////////// 14 | 15 | /*! 16 | @brief a template for a reverse iterator class 17 | 18 | @tparam Base the base iterator type to reverse. Valid types are @ref 19 | iterator (to create @ref reverse_iterator) and @ref const_iterator (to 20 | create @ref const_reverse_iterator). 21 | 22 | @requirement The class satisfies the following concept requirements: 23 | - 24 | [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): 25 | The iterator that can be moved can be moved in both directions (i.e. 26 | incremented and decremented). 27 | - [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): 28 | It is possible to write to the pointed-to element (only if @a Base is 29 | @ref iterator). 30 | 31 | @since version 1.0.0 32 | */ 33 | template 34 | class json_reverse_iterator : public std::reverse_iterator 35 | { 36 | public: 37 | using difference_type = std::ptrdiff_t; 38 | /// shortcut to the reverse iterator adapter 39 | using base_iterator = std::reverse_iterator; 40 | /// the reference type for the pointed-to element 41 | using reference = typename Base::reference; 42 | 43 | /// create reverse iterator from iterator 44 | explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept 45 | : base_iterator(it) {} 46 | 47 | /// create reverse iterator from base class 48 | explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} 49 | 50 | /// post-increment (it++) 51 | json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) 52 | { 53 | return static_cast(base_iterator::operator++(1)); 54 | } 55 | 56 | /// pre-increment (++it) 57 | json_reverse_iterator& operator++() 58 | { 59 | return static_cast(base_iterator::operator++()); 60 | } 61 | 62 | /// post-decrement (it--) 63 | json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) 64 | { 65 | return static_cast(base_iterator::operator--(1)); 66 | } 67 | 68 | /// pre-decrement (--it) 69 | json_reverse_iterator& operator--() 70 | { 71 | return static_cast(base_iterator::operator--()); 72 | } 73 | 74 | /// add to iterator 75 | json_reverse_iterator& operator+=(difference_type i) 76 | { 77 | return static_cast(base_iterator::operator+=(i)); 78 | } 79 | 80 | /// add to iterator 81 | json_reverse_iterator operator+(difference_type i) const 82 | { 83 | return static_cast(base_iterator::operator+(i)); 84 | } 85 | 86 | /// subtract from iterator 87 | json_reverse_iterator operator-(difference_type i) const 88 | { 89 | return static_cast(base_iterator::operator-(i)); 90 | } 91 | 92 | /// return difference 93 | difference_type operator-(const json_reverse_iterator& other) const 94 | { 95 | return base_iterator(*this) - base_iterator(other); 96 | } 97 | 98 | /// access to successor 99 | reference operator[](difference_type n) const 100 | { 101 | return *(this->operator+(n)); 102 | } 103 | 104 | /// return the key of an object iterator 105 | auto key() const -> decltype(std::declval().key()) 106 | { 107 | auto it = --this->base(); 108 | return it.key(); 109 | } 110 | 111 | /// return the value of an iterator 112 | reference value() const 113 | { 114 | auto it = --this->base(); 115 | return it.operator * (); 116 | } 117 | }; 118 | } // namespace detail 119 | } // namespace nlohmann 120 | -------------------------------------------------------------------------------- /inc/isp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_MSC_VER) 4 | #define EXPORT __declspec(dllexport) 5 | #else 6 | #define EXPORT 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "nlohmann/json.hpp" 14 | 15 | #define GAIN_FRACTION_BITS 6 //awb gain control 16 | #define BLC_FRACTION 14 //black level compenstation 17 | #define CCM_FRACTION 10 // color conversion matrix 18 | #define GAMMA_STEP 2 // gamma table 19 | 20 | #define clip_max(x, value) x > value ? value : x 21 | #define clip_min(x, value) x < value ? value : x 22 | 23 | using namespace std; 24 | 25 | typedef struct 26 | { 27 | float r_gain; 28 | float gr_gain; 29 | float gb_gain; 30 | float b_gain; 31 | 32 | } awb_gain_t; 33 | 34 | typedef struct 35 | { 36 | uint16_t bl_r; 37 | uint16_t bl_gr; 38 | uint16_t bl_gb; 39 | uint16_t bl_b; 40 | float alpha; 41 | float beta; 42 | 43 | } blc_cfg_t; 44 | 45 | typedef struct 46 | { 47 | uint8_t Ds; 48 | uint8_t ds; 49 | uint8_t h; 50 | 51 | } nlm_cfg_t; 52 | 53 | typedef struct 54 | { 55 | uint16_t dw[25]; 56 | uint16_t rw[4]; 57 | uint16_t rthres[3]; 58 | 59 | } bnf_cfg_t; 60 | 61 | typedef struct 62 | { 63 | 64 | uint16_t gain_min; 65 | uint16_t gain_max; 66 | uint16_t thres_min; 67 | uint16_t thres_max ; 68 | int16_t em_clip_min; 69 | int16_t em_clip_max; 70 | 71 | } eeh_cfg_t; 72 | 73 | typedef struct{ 74 | uint8_t edge_min; 75 | uint8_t edge_max; 76 | 77 | } fcs_cfg_t; 78 | 79 | typedef struct{ 80 | 81 | uint8_t hue_offset; 82 | float saturation_gain; 83 | 84 | } hsc_cfg_t; 85 | 86 | 87 | typedef struct{ 88 | 89 | uint8_t brightness; 90 | float contrast; 91 | 92 | } bcc_cfg_t; 93 | 94 | typedef struct 95 | { 96 | // image resolution 97 | uint32_t image_width; 98 | uint32_t image_height; 99 | uint16_t image_bits; 100 | // bayer pattern, ex rggb 101 | string bayer_pattern; 102 | // black level correction 103 | blc_cfg_t blc_config; 104 | // dead pixel correction 105 | uint16_t dpc_dead_thres; 106 | string dpc_mode; 107 | // awb gain 108 | awb_gain_t awb_gain; 109 | // color correction matrix 110 | float ccm_matrix[12]; 111 | //cfa mode 112 | string cfa_mode; 113 | // gamma correction parameter 114 | float gamma; 115 | // color space coversion 116 | float csc_matrix[12]; 117 | //non local mean denoise 118 | nlm_cfg_t nlm_config; 119 | //bilateral noise filter 120 | bnf_cfg_t bnf_config; 121 | //edge filter 122 | int16_t edge_filter[15]; 123 | //edge enhancement 124 | eeh_cfg_t eeh_config; 125 | //false color suppression 126 | fcs_cfg_t fcs_config; 127 | //hue staturation control 128 | hsc_cfg_t hsc_config; 129 | //brightness contrast control 130 | bcc_cfg_t bcc_config; 131 | 132 | } isp_config_t; 133 | 134 | 135 | 136 | EXPORT void isp_init(); 137 | EXPORT void isp_raw_run(uint16_t *raw_buf, uint8_t *rgb_buf); 138 | EXPORT void isp_yuv_run(uint8_t *rgb_buf, uint8_t *yuv_buf); 139 | EXPORT void isp_load_config(string filename, isp_config_t *isp_config); 140 | //raw domain 141 | void isp_blc(uint16_t *raw_buf); 142 | void isp_dpc(uint16_t *raw_buf); 143 | void isp_aaf(uint16_t *raw_buf); 144 | void isp_awb_gain(uint16_t *raw_buf); 145 | void isp_ccm(uint16_t *rgb_buf); 146 | void isp_cfa(uint16_t *raw_buf, uint16_t *rgb_buf); 147 | void isp_gac(uint16_t *rgb_buf, uint8_t *gamma_table, uint16_t table_size, uint8_t *ga_rgb_buf); 148 | 149 | //color space conversion 150 | void isp_csc(uint8_t *rgb_buf, uint8_t *yuv_buf); 151 | 152 | //yuv domain 153 | void isp_nlm(uint8_t *src_y_image,uint8_t *dst_y_image); 154 | void isp_bnf(uint8_t *src_y_image, uint8_t *dst_y_image); 155 | void isp_eeh(uint8_t *y_image, int8_t *edge_map); 156 | void isp_bcc(uint8_t* y_image); 157 | void isp_fcs(uint8_t *cbcr_image,int8_t *edge_map); 158 | void isp_hsc(uint8_t *cbcr_image); 159 | 160 | 161 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/hash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uint8_t 4 | #include // size_t 5 | #include // hash 6 | 7 | #include 8 | #include 9 | 10 | namespace nlohmann 11 | { 12 | namespace detail 13 | { 14 | 15 | // boost::hash_combine 16 | inline std::size_t combine(std::size_t seed, std::size_t h) noexcept 17 | { 18 | seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); 19 | return seed; 20 | } 21 | 22 | /*! 23 | @brief hash a JSON value 24 | 25 | The hash function tries to rely on std::hash where possible. Furthermore, the 26 | type of the JSON value is taken into account to have different hash values for 27 | null, 0, 0U, and false, etc. 28 | 29 | @tparam BasicJsonType basic_json specialization 30 | @param j JSON value to hash 31 | @return hash value of j 32 | */ 33 | template 34 | std::size_t hash(const BasicJsonType& j) 35 | { 36 | using string_t = typename BasicJsonType::string_t; 37 | using number_integer_t = typename BasicJsonType::number_integer_t; 38 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 39 | using number_float_t = typename BasicJsonType::number_float_t; 40 | 41 | const auto type = static_cast(j.type()); 42 | switch (j.type()) 43 | { 44 | case BasicJsonType::value_t::null: 45 | case BasicJsonType::value_t::discarded: 46 | { 47 | return combine(type, 0); 48 | } 49 | 50 | case BasicJsonType::value_t::object: 51 | { 52 | auto seed = combine(type, j.size()); 53 | for (const auto& element : j.items()) 54 | { 55 | const auto h = std::hash {}(element.key()); 56 | seed = combine(seed, h); 57 | seed = combine(seed, hash(element.value())); 58 | } 59 | return seed; 60 | } 61 | 62 | case BasicJsonType::value_t::array: 63 | { 64 | auto seed = combine(type, j.size()); 65 | for (const auto& element : j) 66 | { 67 | seed = combine(seed, hash(element)); 68 | } 69 | return seed; 70 | } 71 | 72 | case BasicJsonType::value_t::string: 73 | { 74 | const auto h = std::hash {}(j.template get_ref()); 75 | return combine(type, h); 76 | } 77 | 78 | case BasicJsonType::value_t::boolean: 79 | { 80 | const auto h = std::hash {}(j.template get()); 81 | return combine(type, h); 82 | } 83 | 84 | case BasicJsonType::value_t::number_integer: 85 | { 86 | const auto h = std::hash {}(j.template get()); 87 | return combine(type, h); 88 | } 89 | 90 | case BasicJsonType::value_t::number_unsigned: 91 | { 92 | const auto h = std::hash {}(j.template get()); 93 | return combine(type, h); 94 | } 95 | 96 | case BasicJsonType::value_t::number_float: 97 | { 98 | const auto h = std::hash {}(j.template get()); 99 | return combine(type, h); 100 | } 101 | 102 | case BasicJsonType::value_t::binary: 103 | { 104 | auto seed = combine(type, j.get_binary().size()); 105 | const auto h = std::hash {}(j.get_binary().has_subtype()); 106 | seed = combine(seed, h); 107 | seed = combine(seed, static_cast(j.get_binary().subtype())); 108 | for (const auto byte : j.get_binary()) 109 | { 110 | seed = combine(seed, std::hash {}(byte)); 111 | } 112 | return seed; 113 | } 114 | 115 | default: // LCOV_EXCL_LINE 116 | JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE 117 | return 0; // LCOV_EXCL_LINE 118 | } 119 | } 120 | 121 | } // namespace detail 122 | } // namespace nlohmann 123 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/output/output_adapters.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // copy 4 | #include // size_t 5 | #include // back_inserter 6 | #include // shared_ptr, make_shared 7 | #include // basic_string 8 | #include // vector 9 | 10 | #ifndef JSON_NO_IO 11 | #include // streamsize 12 | #include // basic_ostream 13 | #endif // JSON_NO_IO 14 | 15 | #include 16 | 17 | namespace nlohmann 18 | { 19 | namespace detail 20 | { 21 | /// abstract output adapter interface 22 | template struct output_adapter_protocol 23 | { 24 | virtual void write_character(CharType c) = 0; 25 | virtual void write_characters(const CharType* s, std::size_t length) = 0; 26 | virtual ~output_adapter_protocol() = default; 27 | 28 | output_adapter_protocol() = default; 29 | output_adapter_protocol(const output_adapter_protocol&) = default; 30 | output_adapter_protocol(output_adapter_protocol&&) noexcept = default; 31 | output_adapter_protocol& operator=(const output_adapter_protocol&) = default; 32 | output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; 33 | }; 34 | 35 | /// a type to simplify interfaces 36 | template 37 | using output_adapter_t = std::shared_ptr>; 38 | 39 | /// output adapter for byte vectors 40 | template> 41 | class output_vector_adapter : public output_adapter_protocol 42 | { 43 | public: 44 | explicit output_vector_adapter(std::vector& vec) noexcept 45 | : v(vec) 46 | {} 47 | 48 | void write_character(CharType c) override 49 | { 50 | v.push_back(c); 51 | } 52 | 53 | JSON_HEDLEY_NON_NULL(2) 54 | void write_characters(const CharType* s, std::size_t length) override 55 | { 56 | v.insert(v.end(), s, s + length); 57 | } 58 | 59 | private: 60 | std::vector& v; 61 | }; 62 | 63 | #ifndef JSON_NO_IO 64 | /// output adapter for output streams 65 | template 66 | class output_stream_adapter : public output_adapter_protocol 67 | { 68 | public: 69 | explicit output_stream_adapter(std::basic_ostream& s) noexcept 70 | : stream(s) 71 | {} 72 | 73 | void write_character(CharType c) override 74 | { 75 | stream.put(c); 76 | } 77 | 78 | JSON_HEDLEY_NON_NULL(2) 79 | void write_characters(const CharType* s, std::size_t length) override 80 | { 81 | stream.write(s, static_cast(length)); 82 | } 83 | 84 | private: 85 | std::basic_ostream& stream; 86 | }; 87 | #endif // JSON_NO_IO 88 | 89 | /// output adapter for basic_string 90 | template> 91 | class output_string_adapter : public output_adapter_protocol 92 | { 93 | public: 94 | explicit output_string_adapter(StringType& s) noexcept 95 | : str(s) 96 | {} 97 | 98 | void write_character(CharType c) override 99 | { 100 | str.push_back(c); 101 | } 102 | 103 | JSON_HEDLEY_NON_NULL(2) 104 | void write_characters(const CharType* s, std::size_t length) override 105 | { 106 | str.append(s, length); 107 | } 108 | 109 | private: 110 | StringType& str; 111 | }; 112 | 113 | template> 114 | class output_adapter 115 | { 116 | public: 117 | template> 118 | output_adapter(std::vector& vec) 119 | : oa(std::make_shared>(vec)) {} 120 | 121 | #ifndef JSON_NO_IO 122 | output_adapter(std::basic_ostream& s) 123 | : oa(std::make_shared>(s)) {} 124 | #endif // JSON_NO_IO 125 | 126 | output_adapter(StringType& s) 127 | : oa(std::make_shared>(s)) {} 128 | 129 | operator output_adapter_t() 130 | { 131 | return oa; 132 | } 133 | 134 | private: 135 | output_adapter_t oa = nullptr; 136 | }; 137 | } // namespace detail 138 | } // namespace nlohmann 139 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/value_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // array 4 | #include // size_t 5 | #include // uint8_t 6 | #include // string 7 | 8 | #include 9 | #if JSON_HAS_THREE_WAY_COMPARISON 10 | #include // partial_ordering 11 | #endif 12 | 13 | namespace nlohmann 14 | { 15 | namespace detail 16 | { 17 | /////////////////////////// 18 | // JSON type enumeration // 19 | /////////////////////////// 20 | 21 | /*! 22 | @brief the JSON type enumeration 23 | 24 | This enumeration collects the different JSON types. It is internally used to 25 | distinguish the stored values, and the functions @ref basic_json::is_null(), 26 | @ref basic_json::is_object(), @ref basic_json::is_array(), 27 | @ref basic_json::is_string(), @ref basic_json::is_boolean(), 28 | @ref basic_json::is_number() (with @ref basic_json::is_number_integer(), 29 | @ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), 30 | @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and 31 | @ref basic_json::is_structured() rely on it. 32 | 33 | @note There are three enumeration entries (number_integer, number_unsigned, and 34 | number_float), because the library distinguishes these three types for numbers: 35 | @ref basic_json::number_unsigned_t is used for unsigned integers, 36 | @ref basic_json::number_integer_t is used for signed integers, and 37 | @ref basic_json::number_float_t is used for floating-point numbers or to 38 | approximate integers which do not fit in the limits of their respective type. 39 | 40 | @sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON 41 | value with the default value for a given type 42 | 43 | @since version 1.0.0 44 | */ 45 | enum class value_t : std::uint8_t 46 | { 47 | null, ///< null value 48 | object, ///< object (unordered set of name/value pairs) 49 | array, ///< array (ordered collection of values) 50 | string, ///< string value 51 | boolean, ///< boolean value 52 | number_integer, ///< number value (signed integer) 53 | number_unsigned, ///< number value (unsigned integer) 54 | number_float, ///< number value (floating-point) 55 | binary, ///< binary array (ordered collection of bytes) 56 | discarded ///< discarded by the parser callback function 57 | }; 58 | 59 | /*! 60 | @brief comparison operator for JSON types 61 | 62 | Returns an ordering that is similar to Python: 63 | - order: null < boolean < number < object < array < string < binary 64 | - furthermore, each type is not smaller than itself 65 | - discarded values are not comparable 66 | - binary is represented as a b"" string in python and directly comparable to a 67 | string; however, making a binary array directly comparable with a string would 68 | be surprising behavior in a JSON file. 69 | 70 | @since version 1.0.0 71 | */ 72 | #if JSON_HAS_THREE_WAY_COMPARISON 73 | inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* 74 | #else 75 | inline bool operator<(const value_t lhs, const value_t rhs) noexcept 76 | #endif 77 | { 78 | static constexpr std::array order = {{ 79 | 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, 80 | 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, 81 | 6 /* binary */ 82 | } 83 | }; 84 | 85 | const auto l_index = static_cast(lhs); 86 | const auto r_index = static_cast(rhs); 87 | #if JSON_HAS_THREE_WAY_COMPARISON 88 | if (l_index < order.size() && r_index < order.size()) 89 | { 90 | return order[l_index] <=> order[r_index]; // *NOPAD* 91 | } 92 | return std::partial_ordering::unordered; 93 | #else 94 | return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; 95 | #endif 96 | } 97 | 98 | // GCC selects the built-in operator< over an operator rewritten from 99 | // a user-defined spaceship operator 100 | // Clang, MSVC, and ICC select the rewritten candidate 101 | // (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) 102 | #if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) 103 | inline bool operator<(const value_t lhs, const value_t rhs) noexcept 104 | { 105 | return std::is_lt(lhs <=> rhs); // *NOPAD* 106 | } 107 | #endif 108 | } // namespace detail 109 | } // namespace nlohmann 110 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ISP Image Signal Processor in C 2 | 3 | This repo is an implementation of ISP in c function, basically it is re-implemented from [openISP](https://github.com/cruxopen/openISP) in python. It's currently in very first version, I list some [TODO ](#TODO)list to make pipeline more robust. 4 | 5 | And if you find something wrong in my implementation, welcome to let me know. 6 | 7 | 8 | ![](image/isp_pipeline.png) 9 | 10 | **Function list** 11 | 12 | - [x] Dead Pixel Correction 13 | 14 | - [x] Black Level Compensation 15 | 16 | - [ ] ~~Len Shading Correction~~ 17 | 18 | (need calibration parameters) 19 | 20 | - [x] Anti-aliasing Noise Filter 21 | 22 | - [x] AWB gain Control 23 | 24 | - [x] CFA interpolation 25 | 26 | only implement rggb bayer pattern 27 | 28 | - [x] Color Correction 29 | 30 | - [x] Gamma Correction 31 | 32 | piecewise LUT 33 | 34 | - [x] Color Space Conversion 35 | 36 | - [x] Noise Filter for chroma 37 | 38 | - [x] False Color Suppression 39 | 40 | - [x] Hue Saturation Control 41 | 42 | - [x] Noise Filter for Luma 43 | 44 | - [x] Non local mean denoise 45 | - [x] Bilateral Filter 46 | 47 | - [x] Edge Enhancement 48 | 49 | - [x] Contrast Brightness Control 50 | 51 | ### Usage 52 | 53 | build exe file, 54 | 55 | ``` 56 | mkdir build/ 57 | cd build 58 | cmake .. 59 | cmake --build . 60 | ``` 61 | 62 | then isp_pipeline.exe will in prebuilt/ folder 63 | 64 | test isp pipeline 65 | 66 | ```shell 67 | isp_pipeline.exe test.raw 68 | ``` 69 | 70 | #### Configuration 71 | 72 | The configuration can be a adjusted as input raw image. 73 | 74 | In the config file , parameters are floats which are converted to fixed point type in C function to make operation in integer type. 75 | 76 | **config.json** 77 | 78 | ```json 79 | { 80 | "width": 1920, 81 | "height": 1080, 82 | "image_bits": 10, 83 | "blc": { 84 | "bl_r": 0, 85 | "bl_gr": 0, 86 | "bl_gb": 0, 87 | "bl_b": 0, 88 | "alpha": 0.0, 89 | "beta": 0.0 90 | }, 91 | "dpc": { 92 | "dead_thres": 30, 93 | "mode": "gradient" 94 | }, 95 | "bayer_pattern": "rggb", 96 | "cfa_mode": "malvar", 97 | "awb_gain": { 98 | "r_gain": 1.5, 99 | "gr_gain": 1.0, 100 | "gb_gain": 1.0, 101 | "b_gain": 1.1 102 | }, 103 | "ccm": [ 104 | [ 105 | 1.0, 106 | 0.0, 107 | 0.0, 108 | 0.0 109 | ], 110 | [ 111 | 0.0, 112 | 1.0, 113 | 0.0, 114 | 0.0 115 | ], 116 | [ 117 | 0.0, 118 | 0.0, 119 | 1.0, 120 | 0.0 121 | ] 122 | ], 123 | "gamma": 0.8, 124 | "csc": [ 125 | [0.2568,0.5041,0.0979,16], 126 | [-0.1482,-0.291,0.4392,128], 127 | [0.4392,-0.3678,-0.0714,128] 128 | ], 129 | "nlm":{ 130 | "Ds":4, 131 | "ds":1, 132 | "h":5 133 | }, 134 | "bnf":{ 135 | "dw":[ 136 | [8,12,32,12,8], 137 | [12,64,128,64,12], 138 | [32,128,1024,128,32], 139 | [12,64,128,64,12], 140 | [8,12,32,12,8] 141 | ], 142 | "rw":[0,8,16,32], 143 | "rthres":[128,32,8] 144 | }, 145 | "edge_filter":[ 146 | [-1,0,-1,0,-1], 147 | [-1,0,8,0,-1], 148 | [-1,0,-1,0,-1] 149 | ], 150 | "eeh":{ 151 | "gain_min":32, 152 | "gain_max":128, 153 | "thres_min":4, 154 | "thres_max":16, 155 | "em_clip_min":-64, 156 | "em_clip_max":64 157 | }, 158 | "fcs":{ 159 | "edge_min":32, 160 | "edge_max":64 161 | }, 162 | "hsc":{ 163 | "hue_offset":0, 164 | "saturation_gain":1.3 165 | }, 166 | "bcc":{ 167 | "brightness":0, 168 | "contrast":1.1 169 | } 170 | 171 | 172 | } 173 | 174 | ``` 175 | 176 | 177 | 178 | ## TODO 179 | 180 | - board condition (I didn't handle any board condition in any function) 181 | 182 | - lens shading correction (if I have parameters) 183 | 184 | - CFA ( with more bayer pattern) 185 | 186 | - color space conversion (with more yuv format) 187 | 188 | - Non local mean denoise (optimization in exponential operation) 189 | 190 | - bilateral filter (with non-fixed kernel and optimize in fixed point operation) 191 | 192 | - False color suppression (the current result is kind of weird, need to find the reference algorithm)s 193 | 194 | - Hue Saturation Control (the current result is kind of weird, need to find the reference algorithm) 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /src/isp_nlm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "isp.h" 3 | extern isp_config_t g_isp_config; 4 | 5 | void integrate_gray(uint8_t *image, uint16_t image_width, uint16_t image_height, uint32_t *image_out) 6 | { 7 | 8 | image_out[0] = image[0]; 9 | //integrate first row 10 | for (int j = 1; j < image_width; j++) 11 | { 12 | image_out[j] = image_out[j - 1] + image[j]; 13 | } 14 | 15 | //integrate first col 16 | for (int i = 1; i < image_height; i++) 17 | { 18 | image_out[i * image_width] = image_out[(i - 1) * image_width] + image[i * image_width]; 19 | } 20 | 21 | for (int i = 1; i < image_height; i++) 22 | { 23 | for (int j = 1; j < image_width; j++) 24 | { 25 | 26 | image_out[i * image_width + j] = image_out[(i - 1) * image_width + j] + image_out[i * image_width + (j - 1)] - 27 | image_out[(i - 1) * image_width + (j - 1)] + image[i * image_width + j]; 28 | } 29 | } 30 | } 31 | 32 | void isp_nlm(uint8_t *src_y_image,uint8_t *dst_y_image) 33 | { 34 | 35 | uint16_t image_height, image_width; 36 | uint16_t blk_x0, blk_x1, blk_y0, blk_y1; 37 | uint16_t sblk_x0, sblk_x1, sblk_y0, sblk_y1; 38 | uint32_t *integ_image; 39 | int64_t blk_sum, sblk_sum; 40 | uint8_t table_size; 41 | float *weight_table; 42 | float distance, weight, k; 43 | uint8_t Ds, ds, h; 44 | 45 | Ds = g_isp_config.nlm_config.Ds; 46 | ds = g_isp_config.nlm_config.ds; 47 | h = g_isp_config.nlm_config.h; 48 | 49 | image_width = g_isp_config.image_width; 50 | image_height = g_isp_config.image_height; 51 | 52 | table_size = 2 * (Ds - ds) + 1; 53 | 54 | //d = 1.0 / ((2 * ds + 1) * (2 * ds + 1)); 55 | //TOOD: convert to fixed-point 56 | k = -1.0 / ((2 * ds + 1) * (2 * ds + 1) * h * h); 57 | 58 | integ_image = (uint32_t *)malloc(image_width * image_height * sizeof(uint32_t)); 59 | 60 | weight_table = (float *)malloc(table_size * table_size * sizeof(float)); 61 | 62 | integrate_gray(src_y_image, image_width, image_height, integ_image); 63 | 64 | for (int i = Ds; i < image_height - Ds; i++) 65 | { 66 | for (int j = Ds; j < image_width - Ds; j++) 67 | { 68 | blk_x0 = j - ds; 69 | blk_x1 = j + ds; 70 | blk_y0 = i - ds; 71 | blk_y1 = i + ds; 72 | 73 | blk_sum = integ_image[blk_y0 * image_width + blk_x0] + integ_image[blk_y1 * image_width + blk_x1] - 74 | integ_image[blk_y0 * image_width + blk_x1] - integ_image[blk_y1 * image_width + blk_x0]; 75 | 76 | float weight_max = 0; 77 | float weight_sum = 0; 78 | uint16_t idx = 0; 79 | for (int m = -Ds + ds; m < Ds - ds; m++) 80 | { 81 | for (int n = -Ds + ds; n < Ds - ds; n++) 82 | { 83 | sblk_x0 = j + n - ds; 84 | sblk_x1 = j + n + ds; 85 | sblk_y0 = i + m - ds; 86 | sblk_y1 = i + m + ds; 87 | sblk_sum = integ_image[sblk_y0 * image_width + sblk_x0] + integ_image[sblk_y1 * image_width + sblk_x1] - 88 | integ_image[sblk_y0 * image_width + sblk_x1] - integ_image[sblk_y1 * image_width + sblk_x0]; 89 | 90 | // n = -distance/h^2 91 | // n = - (d*(blk_sum - sblk_sum)*(blk_sum - sblk_sum))/h^2 92 | // n = - (blk_sum - sblk_sum)*(blk_sum - sblk_sum)/((2 * ds + 1) * (2 * ds + 1))*h*h 93 | // n = k * (blk_sum - sblk_sum)*(blk_sum - sblk_sum) 94 | // distance = d * pow((blk_sum - sblk_sum), 2); 95 | // weight = pow(2.718, (-distance / (h * h))); 96 | 97 | //TODO: use taylor series to improve 98 | weight = pow(2.718, k * (blk_sum - sblk_sum) * (blk_sum - sblk_sum)); 99 | 100 | if (weight > weight_max) 101 | { 102 | weight_max = weight; 103 | } 104 | weight_sum += weight; 105 | 106 | weight_table[idx] = weight; 107 | idx++; 108 | } 109 | } 110 | weight_table[(Ds - ds + 1) * table_size + Ds - ds + 1] = weight_max; 111 | 112 | float value = 0.0; 113 | idx = 0; 114 | for (int m = -Ds + ds; m < Ds - ds; m++) 115 | { 116 | for (int n = -Ds + ds; n < Ds - ds; n++) 117 | { 118 | value += weight_table[idx] * src_y_image[(i + m) * image_width + (j + n)]; 119 | idx++; 120 | } 121 | } 122 | value /= weight_sum; 123 | if (value > 255) 124 | { 125 | value = 255; 126 | } 127 | 128 | dst_y_image[i * image_width + j] = (uint8_t)value; 129 | } 130 | } 131 | 132 | free(integ_image); 133 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/meta/cpp_future.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type 5 | #include // index_sequence, make_index_sequence, index_sequence_for 6 | 7 | #include 8 | 9 | namespace nlohmann 10 | { 11 | namespace detail 12 | { 13 | 14 | template 15 | using uncvref_t = typename std::remove_cv::type>::type; 16 | 17 | #ifdef JSON_HAS_CPP_14 18 | 19 | // the following utilities are natively available in C++14 20 | using std::enable_if_t; 21 | using std::index_sequence; 22 | using std::make_index_sequence; 23 | using std::index_sequence_for; 24 | 25 | #else 26 | 27 | // alias templates to reduce boilerplate 28 | template 29 | using enable_if_t = typename std::enable_if::type; 30 | 31 | // The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h 32 | // which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. 33 | 34 | //// START OF CODE FROM GOOGLE ABSEIL 35 | 36 | // integer_sequence 37 | // 38 | // Class template representing a compile-time integer sequence. An instantiation 39 | // of `integer_sequence` has a sequence of integers encoded in its 40 | // type through its template arguments (which is a common need when 41 | // working with C++11 variadic templates). `absl::integer_sequence` is designed 42 | // to be a drop-in replacement for C++14's `std::integer_sequence`. 43 | // 44 | // Example: 45 | // 46 | // template< class T, T... Ints > 47 | // void user_function(integer_sequence); 48 | // 49 | // int main() 50 | // { 51 | // // user_function's `T` will be deduced to `int` and `Ints...` 52 | // // will be deduced to `0, 1, 2, 3, 4`. 53 | // user_function(make_integer_sequence()); 54 | // } 55 | template 56 | struct integer_sequence 57 | { 58 | using value_type = T; 59 | static constexpr std::size_t size() noexcept 60 | { 61 | return sizeof...(Ints); 62 | } 63 | }; 64 | 65 | // index_sequence 66 | // 67 | // A helper template for an `integer_sequence` of `size_t`, 68 | // `absl::index_sequence` is designed to be a drop-in replacement for C++14's 69 | // `std::index_sequence`. 70 | template 71 | using index_sequence = integer_sequence; 72 | 73 | namespace utility_internal 74 | { 75 | 76 | template 77 | struct Extend; 78 | 79 | // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. 80 | template 81 | struct Extend, SeqSize, 0> 82 | { 83 | using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; 84 | }; 85 | 86 | template 87 | struct Extend, SeqSize, 1> 88 | { 89 | using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; 90 | }; 91 | 92 | // Recursion helper for 'make_integer_sequence'. 93 | // 'Gen::type' is an alias for 'integer_sequence'. 94 | template 95 | struct Gen 96 | { 97 | using type = 98 | typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; 99 | }; 100 | 101 | template 102 | struct Gen 103 | { 104 | using type = integer_sequence; 105 | }; 106 | 107 | } // namespace utility_internal 108 | 109 | // Compile-time sequences of integers 110 | 111 | // make_integer_sequence 112 | // 113 | // This template alias is equivalent to 114 | // `integer_sequence`, and is designed to be a drop-in 115 | // replacement for C++14's `std::make_integer_sequence`. 116 | template 117 | using make_integer_sequence = typename utility_internal::Gen::type; 118 | 119 | // make_index_sequence 120 | // 121 | // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, 122 | // and is designed to be a drop-in replacement for C++14's 123 | // `std::make_index_sequence`. 124 | template 125 | using make_index_sequence = make_integer_sequence; 126 | 127 | // index_sequence_for 128 | // 129 | // Converts a typename pack into an index sequence of the same length, and 130 | // is designed to be a drop-in replacement for C++14's 131 | // `std::index_sequence_for()` 132 | template 133 | using index_sequence_for = make_index_sequence; 134 | 135 | //// END OF CODE FROM GOOGLE ABSEIL 136 | 137 | #endif 138 | 139 | // dispatch utility (taken from ranges-v3) 140 | template struct priority_tag : priority_tag < N - 1 > {}; 141 | template<> struct priority_tag<0> {}; 142 | 143 | // taken from ranges-v3 144 | template 145 | struct static_const 146 | { 147 | static constexpr T value{}; 148 | }; 149 | 150 | #ifndef JSON_HAS_CPP_17 151 | 152 | template 153 | constexpr T static_const::value; // NOLINT(readability-redundant-declaration) 154 | 155 | #endif 156 | 157 | } // namespace detail 158 | } // namespace nlohmann 159 | -------------------------------------------------------------------------------- /inc/nlohmann/thirdparty/hedley/hedley_undef.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #undef JSON_HEDLEY_ALWAYS_INLINE 4 | #undef JSON_HEDLEY_ARM_VERSION 5 | #undef JSON_HEDLEY_ARM_VERSION_CHECK 6 | #undef JSON_HEDLEY_ARRAY_PARAM 7 | #undef JSON_HEDLEY_ASSUME 8 | #undef JSON_HEDLEY_BEGIN_C_DECLS 9 | #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE 10 | #undef JSON_HEDLEY_CLANG_HAS_BUILTIN 11 | #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE 12 | #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE 13 | #undef JSON_HEDLEY_CLANG_HAS_EXTENSION 14 | #undef JSON_HEDLEY_CLANG_HAS_FEATURE 15 | #undef JSON_HEDLEY_CLANG_HAS_WARNING 16 | #undef JSON_HEDLEY_COMPCERT_VERSION 17 | #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK 18 | #undef JSON_HEDLEY_CONCAT 19 | #undef JSON_HEDLEY_CONCAT3 20 | #undef JSON_HEDLEY_CONCAT3_EX 21 | #undef JSON_HEDLEY_CONCAT_EX 22 | #undef JSON_HEDLEY_CONST 23 | #undef JSON_HEDLEY_CONSTEXPR 24 | #undef JSON_HEDLEY_CONST_CAST 25 | #undef JSON_HEDLEY_CPP_CAST 26 | #undef JSON_HEDLEY_CRAY_VERSION 27 | #undef JSON_HEDLEY_CRAY_VERSION_CHECK 28 | #undef JSON_HEDLEY_C_DECL 29 | #undef JSON_HEDLEY_DEPRECATED 30 | #undef JSON_HEDLEY_DEPRECATED_FOR 31 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL 32 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ 33 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED 34 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES 35 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS 36 | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION 37 | #undef JSON_HEDLEY_DIAGNOSTIC_POP 38 | #undef JSON_HEDLEY_DIAGNOSTIC_PUSH 39 | #undef JSON_HEDLEY_DMC_VERSION 40 | #undef JSON_HEDLEY_DMC_VERSION_CHECK 41 | #undef JSON_HEDLEY_EMPTY_BASES 42 | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION 43 | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK 44 | #undef JSON_HEDLEY_END_C_DECLS 45 | #undef JSON_HEDLEY_FLAGS 46 | #undef JSON_HEDLEY_FLAGS_CAST 47 | #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE 48 | #undef JSON_HEDLEY_GCC_HAS_BUILTIN 49 | #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE 50 | #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE 51 | #undef JSON_HEDLEY_GCC_HAS_EXTENSION 52 | #undef JSON_HEDLEY_GCC_HAS_FEATURE 53 | #undef JSON_HEDLEY_GCC_HAS_WARNING 54 | #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK 55 | #undef JSON_HEDLEY_GCC_VERSION 56 | #undef JSON_HEDLEY_GCC_VERSION_CHECK 57 | #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE 58 | #undef JSON_HEDLEY_GNUC_HAS_BUILTIN 59 | #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE 60 | #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE 61 | #undef JSON_HEDLEY_GNUC_HAS_EXTENSION 62 | #undef JSON_HEDLEY_GNUC_HAS_FEATURE 63 | #undef JSON_HEDLEY_GNUC_HAS_WARNING 64 | #undef JSON_HEDLEY_GNUC_VERSION 65 | #undef JSON_HEDLEY_GNUC_VERSION_CHECK 66 | #undef JSON_HEDLEY_HAS_ATTRIBUTE 67 | #undef JSON_HEDLEY_HAS_BUILTIN 68 | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE 69 | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS 70 | #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE 71 | #undef JSON_HEDLEY_HAS_EXTENSION 72 | #undef JSON_HEDLEY_HAS_FEATURE 73 | #undef JSON_HEDLEY_HAS_WARNING 74 | #undef JSON_HEDLEY_IAR_VERSION 75 | #undef JSON_HEDLEY_IAR_VERSION_CHECK 76 | #undef JSON_HEDLEY_IBM_VERSION 77 | #undef JSON_HEDLEY_IBM_VERSION_CHECK 78 | #undef JSON_HEDLEY_IMPORT 79 | #undef JSON_HEDLEY_INLINE 80 | #undef JSON_HEDLEY_INTEL_CL_VERSION 81 | #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK 82 | #undef JSON_HEDLEY_INTEL_VERSION 83 | #undef JSON_HEDLEY_INTEL_VERSION_CHECK 84 | #undef JSON_HEDLEY_IS_CONSTANT 85 | #undef JSON_HEDLEY_IS_CONSTEXPR_ 86 | #undef JSON_HEDLEY_LIKELY 87 | #undef JSON_HEDLEY_MALLOC 88 | #undef JSON_HEDLEY_MCST_LCC_VERSION 89 | #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK 90 | #undef JSON_HEDLEY_MESSAGE 91 | #undef JSON_HEDLEY_MSVC_VERSION 92 | #undef JSON_HEDLEY_MSVC_VERSION_CHECK 93 | #undef JSON_HEDLEY_NEVER_INLINE 94 | #undef JSON_HEDLEY_NON_NULL 95 | #undef JSON_HEDLEY_NO_ESCAPE 96 | #undef JSON_HEDLEY_NO_RETURN 97 | #undef JSON_HEDLEY_NO_THROW 98 | #undef JSON_HEDLEY_NULL 99 | #undef JSON_HEDLEY_PELLES_VERSION 100 | #undef JSON_HEDLEY_PELLES_VERSION_CHECK 101 | #undef JSON_HEDLEY_PGI_VERSION 102 | #undef JSON_HEDLEY_PGI_VERSION_CHECK 103 | #undef JSON_HEDLEY_PREDICT 104 | #undef JSON_HEDLEY_PRINTF_FORMAT 105 | #undef JSON_HEDLEY_PRIVATE 106 | #undef JSON_HEDLEY_PUBLIC 107 | #undef JSON_HEDLEY_PURE 108 | #undef JSON_HEDLEY_REINTERPRET_CAST 109 | #undef JSON_HEDLEY_REQUIRE 110 | #undef JSON_HEDLEY_REQUIRE_CONSTEXPR 111 | #undef JSON_HEDLEY_REQUIRE_MSG 112 | #undef JSON_HEDLEY_RESTRICT 113 | #undef JSON_HEDLEY_RETURNS_NON_NULL 114 | #undef JSON_HEDLEY_SENTINEL 115 | #undef JSON_HEDLEY_STATIC_ASSERT 116 | #undef JSON_HEDLEY_STATIC_CAST 117 | #undef JSON_HEDLEY_STRINGIFY 118 | #undef JSON_HEDLEY_STRINGIFY_EX 119 | #undef JSON_HEDLEY_SUNPRO_VERSION 120 | #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK 121 | #undef JSON_HEDLEY_TINYC_VERSION 122 | #undef JSON_HEDLEY_TINYC_VERSION_CHECK 123 | #undef JSON_HEDLEY_TI_ARMCL_VERSION 124 | #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK 125 | #undef JSON_HEDLEY_TI_CL2000_VERSION 126 | #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK 127 | #undef JSON_HEDLEY_TI_CL430_VERSION 128 | #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK 129 | #undef JSON_HEDLEY_TI_CL6X_VERSION 130 | #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK 131 | #undef JSON_HEDLEY_TI_CL7X_VERSION 132 | #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK 133 | #undef JSON_HEDLEY_TI_CLPRU_VERSION 134 | #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK 135 | #undef JSON_HEDLEY_TI_VERSION 136 | #undef JSON_HEDLEY_TI_VERSION_CHECK 137 | #undef JSON_HEDLEY_UNAVAILABLE 138 | #undef JSON_HEDLEY_UNLIKELY 139 | #undef JSON_HEDLEY_UNPREDICTABLE 140 | #undef JSON_HEDLEY_UNREACHABLE 141 | #undef JSON_HEDLEY_UNREACHABLE_RETURN 142 | #undef JSON_HEDLEY_VERSION 143 | #undef JSON_HEDLEY_VERSION_DECODE_MAJOR 144 | #undef JSON_HEDLEY_VERSION_DECODE_MINOR 145 | #undef JSON_HEDLEY_VERSION_DECODE_REVISION 146 | #undef JSON_HEDLEY_VERSION_ENCODE 147 | #undef JSON_HEDLEY_WARNING 148 | #undef JSON_HEDLEY_WARN_UNUSED_RESULT 149 | #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG 150 | #undef JSON_HEDLEY_FALL_THROUGH 151 | -------------------------------------------------------------------------------- /src/isp_dpc.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | #include 3 | extern isp_config_t g_isp_config; 4 | void isp_dpc(uint16_t *raw_buf) 5 | { 6 | uint16_t image_width; 7 | uint16_t image_height; 8 | uint16_t max_value; 9 | uint8_t dead_thres; 10 | bool is_dead = false; 11 | string dpc_mode; 12 | uint16_t nieghbor_value[8] = {0}; 13 | uint16_t center_value, double_center_value; 14 | uint16_t diff_value; 15 | uint16_t dv, dh, ddr, ddl; 16 | uint16_t neighbor_sum[4]; // order: dv, dh, ddr, ddl; 17 | 18 | image_width = g_isp_config.image_width; 19 | image_height = g_isp_config.image_height; 20 | max_value = (1 << g_isp_config.image_bits) - 1; 21 | dead_thres = g_isp_config.dpc_dead_thres; 22 | dpc_mode = g_isp_config.dpc_mode; 23 | 24 | uint32_t idx; 25 | for (int i = 2; i < image_height - 2; i++) 26 | { 27 | for (int j = 2; j < image_width - 2; j++) 28 | { 29 | is_dead = true; 30 | idx = i * image_width + j; 31 | // dead pixel detection 32 | center_value = raw_buf[idx]; 33 | nieghbor_value[0] = raw_buf[idx - 2 * image_width - 2]; 34 | nieghbor_value[1] = raw_buf[idx - 2 * image_width]; 35 | nieghbor_value[2] = raw_buf[idx - 2 * image_width + 2]; 36 | nieghbor_value[3] = raw_buf[idx - 2]; 37 | nieghbor_value[4] = raw_buf[idx + 2]; 38 | nieghbor_value[5] = raw_buf[idx + 2 * image_width - 2]; 39 | nieghbor_value[6] = raw_buf[idx + 2 * image_width]; 40 | nieghbor_value[7] = raw_buf[idx + 2 * image_width + 2]; 41 | 42 | for (int n = 0; n < 8; n++) 43 | { 44 | diff_value = nieghbor_value[n] > center_value ? (nieghbor_value[n] - center_value) : (center_value - nieghbor_value[n]); 45 | if (diff_value > dead_thres) 46 | { 47 | is_dead = is_dead & 1; 48 | } 49 | else 50 | { 51 | is_dead = is_dead & 0; 52 | } 53 | } 54 | 55 | // if(is_dead){ 56 | // cout << "center = "<< center_value < neighbor_sum[0] ? (double_center_value - neighbor_sum[0]) : (neighbor_sum[0] - double_center_value); 72 | 73 | // horizontal gradient 74 | neighbor_sum[1] = nieghbor_value[3] + nieghbor_value[4]; 75 | dh = double_center_value > neighbor_sum[1] ? (double_center_value - neighbor_sum[1]) : (neighbor_sum[1] - double_center_value); 76 | 77 | // diagonal right gradient 78 | neighbor_sum[2] = nieghbor_value[2] + nieghbor_value[5]; 79 | ddr = double_center_value > neighbor_sum[2] ? (double_center_value - neighbor_sum[2]) : (neighbor_sum[2] - double_center_value); 80 | 81 | // diagonal left gradient 82 | neighbor_sum[3] = nieghbor_value[0] + nieghbor_value[7]; 83 | ddl = double_center_value > neighbor_sum[3] ? (double_center_value - neighbor_sum[3]) : (neighbor_sum[3] - double_center_value); 84 | 85 | uint16_t min_value = 9999; 86 | if (dv < min_value) 87 | { 88 | min_value = dv; 89 | } 90 | 91 | if (dh < min_value) 92 | { 93 | min_value = dh; 94 | } 95 | 96 | if (ddr < min_value) 97 | { 98 | min_value = ddr; 99 | } 100 | 101 | if (ddl < min_value) 102 | { 103 | min_value = ddl; 104 | } 105 | 106 | if (min_value == dv) 107 | { 108 | center_value = (neighbor_sum[0] + 1) >> 1; 109 | raw_buf[idx] = clip_max(center_value, max_value); 110 | } 111 | 112 | if (min_value == dh) 113 | { 114 | center_value = (neighbor_sum[1] + 1) >> 1; 115 | raw_buf[idx] = clip_max(center_value, max_value); 116 | } 117 | 118 | if (min_value == ddr) 119 | { 120 | center_value = (neighbor_sum[2] + 1) >> 1; 121 | raw_buf[idx] = clip_max(center_value, max_value); 122 | } 123 | 124 | if (min_value == ddl) 125 | { 126 | center_value = (neighbor_sum[3] + 1) >> 1; 127 | raw_buf[idx] = clip_max(center_value, max_value); 128 | } 129 | } 130 | else if (dpc_mode.compare("mean") == 0) 131 | { 132 | center_value = (nieghbor_value[1] + nieghbor_value[3] + nieghbor_value[4] + nieghbor_value[6]) >> 2; 133 | raw_buf[idx] = clip_max(center_value, max_value); 134 | } 135 | else 136 | { 137 | cout << "Dead pixel mode " << dpc_mode << " not implement yet!" << endl; 138 | cout << "You can try \"mean\" or \"gradient\" mode." << endl; 139 | } 140 | } 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /inc/nlohmann/detail/string_concat.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // strlen 4 | #include // string 5 | #include // forward 6 | 7 | #include 8 | #include 9 | 10 | namespace nlohmann 11 | { 12 | namespace detail 13 | { 14 | 15 | inline std::size_t concat_length() 16 | { 17 | return 0; 18 | } 19 | 20 | template 21 | inline std::size_t concat_length(const char* cstr, Args&& ... rest); 22 | 23 | template 24 | inline std::size_t concat_length(const StringType& str, Args&& ... rest); 25 | 26 | template 27 | inline std::size_t concat_length(const char /*c*/, Args&& ... rest) 28 | { 29 | return 1 + concat_length(std::forward(rest)...); 30 | } 31 | 32 | template 33 | inline std::size_t concat_length(const char* cstr, Args&& ... rest) 34 | { 35 | // cppcheck-suppress ignoredReturnValue 36 | return ::strlen(cstr) + concat_length(std::forward(rest)...); 37 | } 38 | 39 | template 40 | inline std::size_t concat_length(const StringType& str, Args&& ... rest) 41 | { 42 | return str.size() + concat_length(std::forward(rest)...); 43 | } 44 | 45 | template 46 | inline void concat_into(OutStringType& /*out*/) 47 | {} 48 | 49 | template 50 | using string_can_append = decltype(std::declval().append(std::declval < Arg && > ())); 51 | 52 | template 53 | using detect_string_can_append = is_detected; 54 | 55 | template 56 | using string_can_append_op = decltype(std::declval() += std::declval < Arg && > ()); 57 | 58 | template 59 | using detect_string_can_append_op = is_detected; 60 | 61 | template 62 | using string_can_append_iter = decltype(std::declval().append(std::declval().begin(), std::declval().end())); 63 | 64 | template 65 | using detect_string_can_append_iter = is_detected; 66 | 67 | template 68 | using string_can_append_data = decltype(std::declval().append(std::declval().data(), std::declval().size())); 69 | 70 | template 71 | using detect_string_can_append_data = is_detected; 72 | 73 | template < typename OutStringType, typename Arg, typename... Args, 74 | enable_if_t < !detect_string_can_append::value 75 | && detect_string_can_append_op::value, int > = 0 > 76 | inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest); 77 | 78 | template < typename OutStringType, typename Arg, typename... Args, 79 | enable_if_t < !detect_string_can_append::value 80 | && !detect_string_can_append_op::value 81 | && detect_string_can_append_iter::value, int > = 0 > 82 | inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest); 83 | 84 | template < typename OutStringType, typename Arg, typename... Args, 85 | enable_if_t < !detect_string_can_append::value 86 | && !detect_string_can_append_op::value 87 | && !detect_string_can_append_iter::value 88 | && detect_string_can_append_data::value, int > = 0 > 89 | inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest); 90 | 91 | template::value, int> = 0> 93 | inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest) 94 | { 95 | out.append(std::forward(arg)); 96 | concat_into(out, std::forward(rest)...); 97 | } 98 | 99 | template < typename OutStringType, typename Arg, typename... Args, 100 | enable_if_t < !detect_string_can_append::value 101 | && detect_string_can_append_op::value, int > > 102 | inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest) 103 | { 104 | out += std::forward(arg); 105 | concat_into(out, std::forward(rest)...); 106 | } 107 | 108 | template < typename OutStringType, typename Arg, typename... Args, 109 | enable_if_t < !detect_string_can_append::value 110 | && !detect_string_can_append_op::value 111 | && detect_string_can_append_iter::value, int > > 112 | inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest) 113 | { 114 | out.append(arg.begin(), arg.end()); 115 | concat_into(out, std::forward(rest)...); 116 | } 117 | 118 | template < typename OutStringType, typename Arg, typename... Args, 119 | enable_if_t < !detect_string_can_append::value 120 | && !detect_string_can_append_op::value 121 | && !detect_string_can_append_iter::value 122 | && detect_string_can_append_data::value, int > > 123 | inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest) 124 | { 125 | out.append(arg.data(), arg.size()); 126 | concat_into(out, std::forward(rest)...); 127 | } 128 | 129 | template 130 | inline OutStringType concat(Args && ... args) 131 | { 132 | OutStringType str; 133 | str.reserve(concat_length(std::forward(args)...)); 134 | concat_into(str, std::forward(args)...); 135 | return str; 136 | } 137 | 138 | } // namespace detail 139 | } // namespace nlohmann 140 | -------------------------------------------------------------------------------- /src/isp_cfa.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | extern isp_config_t g_isp_config; 3 | 4 | void isp_cfa_malvar(uint16_t *raw_buf, uint16_t image_width, uint16_t image_height, uint16_t max_value, string bayer_pattern, uint16_t *rgb_buf) 5 | { 6 | if (bayer_pattern.compare("rggb") == 0) 7 | { 8 | int count = 0; 9 | uint64_t idx, base_idx; 10 | int32_t r, g, b; 11 | 12 | for (int i = 2; i < image_height - 2; i += 2) 13 | { 14 | for (int j = 2; j < image_width - 2; j += 2) 15 | { 16 | 17 | base_idx = i * image_width + j; 18 | // debayer red idx pixel 19 | idx = base_idx; 20 | 21 | r = raw_buf[idx]; 22 | g = 4 * raw_buf[idx] - raw_buf[idx - 2 * image_width] - raw_buf[idx - 2] - raw_buf[idx + 2 * image_width] - raw_buf[idx + 2] + 23 | 2 * (raw_buf[idx + image_width] + raw_buf[idx + 1] + raw_buf[idx - image_width] + raw_buf[idx - 1]); 24 | b = 6 * raw_buf[idx] - ((3 * (raw_buf[idx - 2 * image_width] + raw_buf[idx - 2] + raw_buf[idx + 2 * image_width] + raw_buf[idx + 2])) >> 1) + 25 | 2 * (raw_buf[idx - image_width - 1] + raw_buf[idx - image_width + 1] + raw_buf[idx + image_width - 1] + raw_buf[idx + image_width + 1]); 26 | 27 | r = clip_min(r, 0); 28 | g = clip_min(g, 0); 29 | b = clip_min(b, 0); 30 | 31 | g = g >> 3; 32 | b = b >> 3; 33 | 34 | rgb_buf[3 * idx] = clip_max(r, max_value); 35 | rgb_buf[3 * idx + 1] = clip_max(g, max_value); 36 | rgb_buf[3 * idx + 2] = clip_max(b, max_value); 37 | 38 | // debayer gr idx pixel 39 | idx = base_idx + 1; 40 | r = 5 * raw_buf[idx] - raw_buf[idx - 2] - raw_buf[idx - image_width - 1] - raw_buf[idx + image_width - 1] - 41 | raw_buf[idx - image_width + 1] - raw_buf[idx + image_width + 1] - raw_buf[idx + 2] + 42 | ((raw_buf[idx - 2 * image_width] + raw_buf[idx + 2 * image_width]) >> 1) + 4 * (raw_buf[idx - 1] + raw_buf[idx + 1]); 43 | 44 | g = raw_buf[idx]; 45 | b = 5 * raw_buf[idx] - raw_buf[idx - 2 * image_width] - raw_buf[idx - image_width - 1] - raw_buf[idx - image_width + 1] - 46 | raw_buf[idx + 2 * image_width] - raw_buf[idx + image_width - 1] - raw_buf[idx + image_width + 1] + 47 | ((raw_buf[idx - 2] + raw_buf[idx + 2]) >> 1) + 4 * (raw_buf[idx - image_width] + raw_buf[idx + image_width]); 48 | 49 | r = clip_min(r, 0); 50 | g = clip_min(g, 0); 51 | b = clip_min(b, 0); 52 | 53 | r = r >> 3; 54 | b = b >> 3; 55 | 56 | rgb_buf[3 * idx] = clip_max(r, max_value); 57 | rgb_buf[3 * idx + 1] = clip_max(g, max_value); 58 | rgb_buf[3 * idx + 2] = clip_max(b, max_value); 59 | 60 | // debayer gb idx pixel 61 | idx = base_idx + image_width; 62 | r = 5 * raw_buf[idx] - raw_buf[idx - 2 * image_width] - raw_buf[idx - image_width - 1] - raw_buf[idx - image_width + 1] - 63 | raw_buf[idx + 2 * image_width] - raw_buf[idx + image_width - 1] - raw_buf[idx + image_width + 1] + 64 | ((raw_buf[idx - 2] - raw_buf[idx + 2]) >> 1) + 4 * (raw_buf[idx - image_width] + raw_buf[idx + image_width]); 65 | 66 | g = raw_buf[idx]; 67 | 68 | b = 5 * raw_buf[idx] - raw_buf[idx - 2] - raw_buf[idx - image_width - 1] - raw_buf[idx + image_width - 1] - raw_buf[idx - image_width + 1] - 69 | raw_buf[idx + image_width + 1] - raw_buf[idx + 2] + 70 | +((raw_buf[idx - 2 * image_width] + raw_buf[idx + 2 * image_width]) >> 1) + 4 * (raw_buf[idx - 1] + raw_buf[idx + 1]); 71 | 72 | r = clip_min(r, 0); 73 | g = clip_min(g, 0); 74 | b = clip_min(b, 0); 75 | 76 | r = r >> 3; 77 | b = b >> 3; 78 | 79 | rgb_buf[3 * idx] = clip_max(r, max_value); 80 | rgb_buf[3 * idx + 1] = clip_max(g, max_value); 81 | rgb_buf[3 * idx + 2] = clip_max(b, max_value); 82 | 83 | // debayer blue idex pixel 84 | idx = base_idx + image_width + 1; 85 | r = 6 * raw_buf[idx] - ((3 * (raw_buf[idx - 2 * image_width] + raw_buf[idx - 2] + raw_buf[idx + 2 * image_width] + raw_buf[idx + 2])) >> 1) + 86 | 2 * (raw_buf[idx - image_width - 1] + raw_buf[idx - image_width + 1] + raw_buf[idx + image_width - 1] + raw_buf[idx + image_width + 1]); 87 | 88 | g = 4 * raw_buf[idx] - raw_buf[idx - 2 * image_width] - raw_buf[idx - 2] - raw_buf[idx + 2 * image_width] - raw_buf[idx + 2] + 89 | 2 * (raw_buf[idx + image_width] + raw_buf[idx + 1] + raw_buf[idx - image_width] + raw_buf[idx - 1]); 90 | 91 | b = raw_buf[idx]; 92 | 93 | r = clip_min(r, 0); 94 | g = clip_min(g, 0); 95 | b = clip_min(b, 0); 96 | 97 | r = r >> 3; 98 | g = g >> 3; 99 | 100 | rgb_buf[3 * idx] = clip_max(r, max_value); 101 | rgb_buf[3 * idx + 1] = clip_max(g, max_value); 102 | rgb_buf[3 * idx + 2] = clip_max(b, max_value); 103 | } 104 | } 105 | } 106 | else 107 | { 108 | 109 | cout << "Oppos! Bayer pattern " << g_isp_config.bayer_pattern << " not implemented yet..." << endl; 110 | cout << "bye bye QQ~" << endl; 111 | } 112 | } 113 | 114 | void isp_cfa(uint16_t *raw_buf, uint16_t *rgb_buf) 115 | { 116 | 117 | uint16_t image_width; 118 | uint16_t image_height; 119 | uint16_t max_value; 120 | string bayer_pattern; 121 | string cfa_mode; 122 | 123 | bayer_pattern = g_isp_config.bayer_pattern; 124 | cfa_mode = g_isp_config.cfa_mode; 125 | image_width = g_isp_config.image_width; 126 | image_height = g_isp_config.image_height; 127 | max_value = (1 << g_isp_config.image_bits) - 1; 128 | 129 | if (cfa_mode.compare("malvar") == 0) 130 | { 131 | isp_cfa_malvar(raw_buf, image_width, image_height, max_value, bayer_pattern, rgb_buf); 132 | } 133 | else 134 | { 135 | cout << "not implement other cfa method yet, bye~"< // size_t 4 | #include // declval 5 | #include // string 6 | 7 | #include 8 | #include 9 | 10 | namespace nlohmann 11 | { 12 | namespace detail 13 | { 14 | template 15 | using null_function_t = decltype(std::declval().null()); 16 | 17 | template 18 | using boolean_function_t = 19 | decltype(std::declval().boolean(std::declval())); 20 | 21 | template 22 | using number_integer_function_t = 23 | decltype(std::declval().number_integer(std::declval())); 24 | 25 | template 26 | using number_unsigned_function_t = 27 | decltype(std::declval().number_unsigned(std::declval())); 28 | 29 | template 30 | using number_float_function_t = decltype(std::declval().number_float( 31 | std::declval(), std::declval())); 32 | 33 | template 34 | using string_function_t = 35 | decltype(std::declval().string(std::declval())); 36 | 37 | template 38 | using binary_function_t = 39 | decltype(std::declval().binary(std::declval())); 40 | 41 | template 42 | using start_object_function_t = 43 | decltype(std::declval().start_object(std::declval())); 44 | 45 | template 46 | using key_function_t = 47 | decltype(std::declval().key(std::declval())); 48 | 49 | template 50 | using end_object_function_t = decltype(std::declval().end_object()); 51 | 52 | template 53 | using start_array_function_t = 54 | decltype(std::declval().start_array(std::declval())); 55 | 56 | template 57 | using end_array_function_t = decltype(std::declval().end_array()); 58 | 59 | template 60 | using parse_error_function_t = decltype(std::declval().parse_error( 61 | std::declval(), std::declval(), 62 | std::declval())); 63 | 64 | template 65 | struct is_sax 66 | { 67 | private: 68 | static_assert(is_basic_json::value, 69 | "BasicJsonType must be of type basic_json<...>"); 70 | 71 | using number_integer_t = typename BasicJsonType::number_integer_t; 72 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 73 | using number_float_t = typename BasicJsonType::number_float_t; 74 | using string_t = typename BasicJsonType::string_t; 75 | using binary_t = typename BasicJsonType::binary_t; 76 | using exception_t = typename BasicJsonType::exception; 77 | 78 | public: 79 | static constexpr bool value = 80 | is_detected_exact::value && 81 | is_detected_exact::value && 82 | is_detected_exact::value && 83 | is_detected_exact::value && 84 | is_detected_exact::value && 85 | is_detected_exact::value && 86 | is_detected_exact::value && 87 | is_detected_exact::value && 88 | is_detected_exact::value && 89 | is_detected_exact::value && 90 | is_detected_exact::value && 91 | is_detected_exact::value && 92 | is_detected_exact::value; 93 | }; 94 | 95 | template 96 | struct is_sax_static_asserts 97 | { 98 | private: 99 | static_assert(is_basic_json::value, 100 | "BasicJsonType must be of type basic_json<...>"); 101 | 102 | using number_integer_t = typename BasicJsonType::number_integer_t; 103 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 104 | using number_float_t = typename BasicJsonType::number_float_t; 105 | using string_t = typename BasicJsonType::string_t; 106 | using binary_t = typename BasicJsonType::binary_t; 107 | using exception_t = typename BasicJsonType::exception; 108 | 109 | public: 110 | static_assert(is_detected_exact::value, 111 | "Missing/invalid function: bool null()"); 112 | static_assert(is_detected_exact::value, 113 | "Missing/invalid function: bool boolean(bool)"); 114 | static_assert(is_detected_exact::value, 115 | "Missing/invalid function: bool boolean(bool)"); 116 | static_assert( 117 | is_detected_exact::value, 119 | "Missing/invalid function: bool number_integer(number_integer_t)"); 120 | static_assert( 121 | is_detected_exact::value, 123 | "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); 124 | static_assert(is_detected_exact::value, 126 | "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); 127 | static_assert( 128 | is_detected_exact::value, 129 | "Missing/invalid function: bool string(string_t&)"); 130 | static_assert( 131 | is_detected_exact::value, 132 | "Missing/invalid function: bool binary(binary_t&)"); 133 | static_assert(is_detected_exact::value, 134 | "Missing/invalid function: bool start_object(std::size_t)"); 135 | static_assert(is_detected_exact::value, 136 | "Missing/invalid function: bool key(string_t&)"); 137 | static_assert(is_detected_exact::value, 138 | "Missing/invalid function: bool end_object()"); 139 | static_assert(is_detected_exact::value, 140 | "Missing/invalid function: bool start_array(std::size_t)"); 141 | static_assert(is_detected_exact::value, 142 | "Missing/invalid function: bool end_array()"); 143 | static_assert( 144 | is_detected_exact::value, 145 | "Missing/invalid function: bool parse_error(std::size_t, const " 146 | "std::string&, const exception&)"); 147 | }; 148 | } // namespace detail 149 | } // namespace nlohmann 150 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/iterators/iteration_proxy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // size_t 4 | #include // input_iterator_tag 5 | #include // string, to_string 6 | #include // tuple_size, get, tuple_element 7 | #include // move 8 | 9 | #if JSON_HAS_RANGES 10 | #include // enable_borrowed_range 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | namespace nlohmann 17 | { 18 | namespace detail 19 | { 20 | template 21 | void int_to_string( string_type& target, std::size_t value ) 22 | { 23 | // For ADL 24 | using std::to_string; 25 | target = to_string(value); 26 | } 27 | template class iteration_proxy_value 28 | { 29 | public: 30 | using difference_type = std::ptrdiff_t; 31 | using value_type = iteration_proxy_value; 32 | using pointer = value_type *; 33 | using reference = value_type &; 34 | using iterator_category = std::input_iterator_tag; 35 | using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; 36 | 37 | private: 38 | /// the iterator 39 | IteratorType anchor{}; 40 | /// an index for arrays (used to create key names) 41 | std::size_t array_index = 0; 42 | /// last stringified array index 43 | mutable std::size_t array_index_last = 0; 44 | /// a string representation of the array index 45 | mutable string_type array_index_str = "0"; 46 | /// an empty string (to return a reference for primitive values) 47 | string_type empty_str{}; 48 | 49 | public: 50 | explicit iteration_proxy_value() = default; 51 | explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) 52 | noexcept(std::is_nothrow_move_constructible::value 53 | && std::is_nothrow_default_constructible::value) 54 | : anchor(std::move(it)) 55 | , array_index(array_index_) 56 | {} 57 | 58 | iteration_proxy_value(iteration_proxy_value const&) = default; 59 | iteration_proxy_value& operator=(iteration_proxy_value const&) = default; 60 | // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions 61 | iteration_proxy_value(iteration_proxy_value&&) 62 | noexcept(std::is_nothrow_move_constructible::value 63 | && std::is_nothrow_move_constructible::value) = default; 64 | iteration_proxy_value& operator=(iteration_proxy_value&&) 65 | noexcept(std::is_nothrow_move_assignable::value 66 | && std::is_nothrow_move_assignable::value) = default; 67 | ~iteration_proxy_value() = default; 68 | 69 | /// dereference operator (needed for range-based for) 70 | const iteration_proxy_value& operator*() const 71 | { 72 | return *this; 73 | } 74 | 75 | /// increment operator (needed for range-based for) 76 | iteration_proxy_value& operator++() 77 | { 78 | ++anchor; 79 | ++array_index; 80 | 81 | return *this; 82 | } 83 | 84 | iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) 85 | { 86 | auto tmp = iteration_proxy_value(anchor, array_index); 87 | ++anchor; 88 | ++array_index; 89 | return tmp; 90 | } 91 | 92 | /// equality operator (needed for InputIterator) 93 | bool operator==(const iteration_proxy_value& o) const 94 | { 95 | return anchor == o.anchor; 96 | } 97 | 98 | /// inequality operator (needed for range-based for) 99 | bool operator!=(const iteration_proxy_value& o) const 100 | { 101 | return anchor != o.anchor; 102 | } 103 | 104 | /// return key of the iterator 105 | const string_type& key() const 106 | { 107 | JSON_ASSERT(anchor.m_object != nullptr); 108 | 109 | switch (anchor.m_object->type()) 110 | { 111 | // use integer array index as key 112 | case value_t::array: 113 | { 114 | if (array_index != array_index_last) 115 | { 116 | int_to_string( array_index_str, array_index ); 117 | array_index_last = array_index; 118 | } 119 | return array_index_str; 120 | } 121 | 122 | // use key from the object 123 | case value_t::object: 124 | return anchor.key(); 125 | 126 | // use an empty key for all primitive types 127 | case value_t::null: 128 | case value_t::string: 129 | case value_t::boolean: 130 | case value_t::number_integer: 131 | case value_t::number_unsigned: 132 | case value_t::number_float: 133 | case value_t::binary: 134 | case value_t::discarded: 135 | default: 136 | return empty_str; 137 | } 138 | } 139 | 140 | /// return value of the iterator 141 | typename IteratorType::reference value() const 142 | { 143 | return anchor.value(); 144 | } 145 | }; 146 | 147 | /// proxy class for the items() function 148 | template class iteration_proxy 149 | { 150 | private: 151 | /// the container to iterate 152 | typename IteratorType::pointer container = nullptr; 153 | 154 | public: 155 | explicit iteration_proxy() = default; 156 | 157 | /// construct iteration proxy from a container 158 | explicit iteration_proxy(typename IteratorType::reference cont) noexcept 159 | : container(&cont) {} 160 | 161 | iteration_proxy(iteration_proxy const&) = default; 162 | iteration_proxy& operator=(iteration_proxy const&) = default; 163 | iteration_proxy(iteration_proxy&&) noexcept = default; 164 | iteration_proxy& operator=(iteration_proxy&&) noexcept = default; 165 | ~iteration_proxy() = default; 166 | 167 | /// return iterator begin (needed for range-based for) 168 | iteration_proxy_value begin() const noexcept 169 | { 170 | return iteration_proxy_value(container->begin()); 171 | } 172 | 173 | /// return iterator end (needed for range-based for) 174 | iteration_proxy_value end() const noexcept 175 | { 176 | return iteration_proxy_value(container->end()); 177 | } 178 | }; 179 | 180 | // Structured Bindings Support 181 | // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 182 | // And see https://github.com/nlohmann/json/pull/1391 183 | template = 0> 184 | auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) 185 | { 186 | return i.key(); 187 | } 188 | // Structured Bindings Support 189 | // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 190 | // And see https://github.com/nlohmann/json/pull/1391 191 | template = 0> 192 | auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) 193 | { 194 | return i.value(); 195 | } 196 | } // namespace detail 197 | } // namespace nlohmann 198 | 199 | // The Addition to the STD Namespace is required to add 200 | // Structured Bindings Support to the iteration_proxy_value class 201 | // For further reference see https://blog.tartanllama.xyz/structured-bindings/ 202 | // And see https://github.com/nlohmann/json/pull/1391 203 | namespace std 204 | { 205 | #if defined(__clang__) 206 | // Fix: https://github.com/nlohmann/json/issues/1401 207 | #pragma clang diagnostic push 208 | #pragma clang diagnostic ignored "-Wmismatched-tags" 209 | #endif 210 | template 211 | class tuple_size<::nlohmann::detail::iteration_proxy_value> 212 | : public std::integral_constant {}; 213 | 214 | template 215 | class tuple_element> 216 | { 217 | public: 218 | using type = decltype( 219 | get(std::declval < 220 | ::nlohmann::detail::iteration_proxy_value> ())); 221 | }; 222 | #if defined(__clang__) 223 | #pragma clang diagnostic pop 224 | #endif 225 | } // namespace std 226 | 227 | #if JSON_HAS_RANGES 228 | template 229 | inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy> = true; 230 | #endif 231 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/exceptions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // nullptr_t 4 | #include // exception 5 | #include // runtime_error 6 | #include // to_string 7 | #include // vector 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | namespace nlohmann 19 | { 20 | namespace detail 21 | { 22 | //////////////// 23 | // exceptions // 24 | //////////////// 25 | 26 | /// @brief general exception of the @ref basic_json class 27 | /// @sa https://json.nlohmann.me/api/basic_json/exception/ 28 | class exception : public std::exception 29 | { 30 | public: 31 | /// returns the explanatory string 32 | const char* what() const noexcept override 33 | { 34 | return m.what(); 35 | } 36 | 37 | /// the id of the exception 38 | const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) 39 | 40 | protected: 41 | JSON_HEDLEY_NON_NULL(3) 42 | exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) 43 | 44 | static std::string name(const std::string& ename, int id_) 45 | { 46 | return concat("[json.exception.", ename, '.', std::to_string(id_), "] "); 47 | } 48 | 49 | static std::string diagnostics(std::nullptr_t /*leaf_element*/) 50 | { 51 | return ""; 52 | } 53 | 54 | template 55 | static std::string diagnostics(const BasicJsonType* leaf_element) 56 | { 57 | #if JSON_DIAGNOSTICS 58 | std::vector tokens; 59 | for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent) 60 | { 61 | switch (current->m_parent->type()) 62 | { 63 | case value_t::array: 64 | { 65 | for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) 66 | { 67 | if (¤t->m_parent->m_value.array->operator[](i) == current) 68 | { 69 | tokens.emplace_back(std::to_string(i)); 70 | break; 71 | } 72 | } 73 | break; 74 | } 75 | 76 | case value_t::object: 77 | { 78 | for (const auto& element : *current->m_parent->m_value.object) 79 | { 80 | if (&element.second == current) 81 | { 82 | tokens.emplace_back(element.first.c_str()); 83 | break; 84 | } 85 | } 86 | break; 87 | } 88 | 89 | case value_t::null: // LCOV_EXCL_LINE 90 | case value_t::string: // LCOV_EXCL_LINE 91 | case value_t::boolean: // LCOV_EXCL_LINE 92 | case value_t::number_integer: // LCOV_EXCL_LINE 93 | case value_t::number_unsigned: // LCOV_EXCL_LINE 94 | case value_t::number_float: // LCOV_EXCL_LINE 95 | case value_t::binary: // LCOV_EXCL_LINE 96 | case value_t::discarded: // LCOV_EXCL_LINE 97 | default: // LCOV_EXCL_LINE 98 | break; // LCOV_EXCL_LINE 99 | } 100 | } 101 | 102 | if (tokens.empty()) 103 | { 104 | return ""; 105 | } 106 | 107 | auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, 108 | [](const std::string & a, const std::string & b) 109 | { 110 | return concat(a, '/', detail::escape(b)); 111 | }); 112 | return concat('(', str, ") "); 113 | #else 114 | static_cast(leaf_element); 115 | return ""; 116 | #endif 117 | } 118 | 119 | private: 120 | /// an exception object as storage for error messages 121 | std::runtime_error m; 122 | }; 123 | 124 | /// @brief exception indicating a parse error 125 | /// @sa https://json.nlohmann.me/api/basic_json/parse_error/ 126 | class parse_error : public exception 127 | { 128 | public: 129 | /*! 130 | @brief create a parse error exception 131 | @param[in] id_ the id of the exception 132 | @param[in] pos the position where the error occurred (or with 133 | chars_read_total=0 if the position cannot be 134 | determined) 135 | @param[in] what_arg the explanatory string 136 | @return parse_error object 137 | */ 138 | template::value, int> = 0> 139 | static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) 140 | { 141 | std::string w = concat(exception::name("parse_error", id_), "parse error", 142 | position_string(pos), ": ", exception::diagnostics(context), what_arg); 143 | return {id_, pos.chars_read_total, w.c_str()}; 144 | } 145 | 146 | template::value, int> = 0> 147 | static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) 148 | { 149 | std::string w = concat(exception::name("parse_error", id_), "parse error", 150 | (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), 151 | ": ", exception::diagnostics(context), what_arg); 152 | return {id_, byte_, w.c_str()}; 153 | } 154 | 155 | /*! 156 | @brief byte index of the parse error 157 | 158 | The byte index of the last read character in the input file. 159 | 160 | @note For an input with n bytes, 1 is the index of the first character and 161 | n+1 is the index of the terminating null byte or the end of file. 162 | This also holds true when reading a byte vector (CBOR or MessagePack). 163 | */ 164 | const std::size_t byte; 165 | 166 | private: 167 | parse_error(int id_, std::size_t byte_, const char* what_arg) 168 | : exception(id_, what_arg), byte(byte_) {} 169 | 170 | static std::string position_string(const position_t& pos) 171 | { 172 | return concat(" at line ", std::to_string(pos.lines_read + 1), 173 | ", column ", std::to_string(pos.chars_read_current_line)); 174 | } 175 | }; 176 | 177 | /// @brief exception indicating errors with iterators 178 | /// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/ 179 | class invalid_iterator : public exception 180 | { 181 | public: 182 | template::value, int> = 0> 183 | static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context) 184 | { 185 | std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg); 186 | return {id_, w.c_str()}; 187 | } 188 | 189 | private: 190 | JSON_HEDLEY_NON_NULL(3) 191 | invalid_iterator(int id_, const char* what_arg) 192 | : exception(id_, what_arg) {} 193 | }; 194 | 195 | /// @brief exception indicating executing a member function with a wrong type 196 | /// @sa https://json.nlohmann.me/api/basic_json/type_error/ 197 | class type_error : public exception 198 | { 199 | public: 200 | template::value, int> = 0> 201 | static type_error create(int id_, const std::string& what_arg, BasicJsonContext context) 202 | { 203 | std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg); 204 | return {id_, w.c_str()}; 205 | } 206 | 207 | private: 208 | JSON_HEDLEY_NON_NULL(3) 209 | type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} 210 | }; 211 | 212 | /// @brief exception indicating access out of the defined range 213 | /// @sa https://json.nlohmann.me/api/basic_json/out_of_range/ 214 | class out_of_range : public exception 215 | { 216 | public: 217 | template::value, int> = 0> 218 | static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context) 219 | { 220 | std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg); 221 | return {id_, w.c_str()}; 222 | } 223 | 224 | private: 225 | JSON_HEDLEY_NON_NULL(3) 226 | out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} 227 | }; 228 | 229 | /// @brief exception indicating other library errors 230 | /// @sa https://json.nlohmann.me/api/basic_json/other_error/ 231 | class other_error : public exception 232 | { 233 | public: 234 | template::value, int> = 0> 235 | static other_error create(int id_, const std::string& what_arg, BasicJsonContext context) 236 | { 237 | std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg); 238 | return {id_, w.c_str()}; 239 | } 240 | 241 | private: 242 | JSON_HEDLEY_NON_NULL(3) 243 | other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} 244 | }; 245 | 246 | } // namespace detail 247 | } // namespace nlohmann 248 | -------------------------------------------------------------------------------- /src/isp_core.cpp: -------------------------------------------------------------------------------- 1 | #include "isp.h" 2 | #include 3 | #include 4 | #include "opencv2/opencv.hpp" 5 | 6 | using namespace cv; 7 | using json = nlohmann::json; 8 | extern isp_config_t g_isp_config; 9 | uint8_t *gamma_table; 10 | uint16_t g_table_size; 11 | 12 | void isp_load_config(string filename, isp_config_t *isp_config) 13 | { 14 | 15 | // uint32_t ccm_matrix[12] = {0}; 16 | 17 | std::ifstream file(filename); 18 | json jfile = json::parse(file); 19 | 20 | isp_config->image_height = jfile["height"]; 21 | isp_config->image_width = jfile["width"]; 22 | isp_config->image_bits = jfile["image_bits"]; 23 | isp_config->bayer_pattern = jfile["bayer_pattern"]; 24 | isp_config->blc_config.bl_r = jfile["blc"]["bl_r"]; 25 | isp_config->blc_config.bl_gr = jfile["blc"]["bl_gr"]; 26 | isp_config->blc_config.bl_gb = jfile["blc"]["bl_gb"]; 27 | isp_config->blc_config.bl_b = jfile["blc"]["bl_b"]; 28 | isp_config->blc_config.alpha = jfile["blc"]["alpha"]; 29 | isp_config->blc_config.beta = jfile["blc"]["beta"]; 30 | isp_config->dpc_dead_thres = jfile["dpc"]["dead_thres"]; 31 | isp_config->dpc_mode = jfile["dpc"]["mode"]; 32 | isp_config->awb_gain.r_gain = jfile["awb_gain"]["r_gain"]; 33 | isp_config->awb_gain.gr_gain = jfile["awb_gain"]["gr_gain"]; 34 | isp_config->awb_gain.gb_gain = jfile["awb_gain"]["gb_gain"]; 35 | isp_config->awb_gain.b_gain = jfile["awb_gain"]["b_gain"]; 36 | isp_config->cfa_mode = jfile["cfa_mode"]; 37 | isp_config->gamma = jfile["gamma"]; 38 | isp_config->nlm_config.Ds = jfile["nlm"]["Ds"]; 39 | isp_config->nlm_config.ds = jfile["nlm"]["ds"]; 40 | isp_config->nlm_config.h = jfile["nlm"]["h"]; 41 | isp_config->eeh_config.gain_min = jfile["eeh"]["gain_min"]; 42 | isp_config->eeh_config.gain_max = jfile["eeh"]["gain_max"]; 43 | isp_config->eeh_config.thres_min = jfile["eeh"]["thres_min"]; 44 | isp_config->eeh_config.thres_max = jfile["eeh"]["thres_max"]; 45 | isp_config->eeh_config.em_clip_min = jfile["eeh"]["em_clip_min"]; 46 | isp_config->eeh_config.em_clip_max = jfile["eeh"]["em_clip_max"]; 47 | isp_config->fcs_config.edge_min = jfile["fcs"]["edge_min"]; 48 | isp_config->fcs_config.edge_max = jfile["fcs"]["edge_max"]; 49 | 50 | isp_config->hsc_config.hue_offset = jfile["hsc"]["hue_offset"]; 51 | isp_config->hsc_config.saturation_gain = jfile["hsc"]["saturation_gain"]; 52 | isp_config->bcc_config.brightness = jfile["bcc"]["brightness"]; 53 | isp_config->bcc_config.contrast = jfile["bcc"]["contrast"]; 54 | 55 | 56 | std::vector> m; 57 | m = jfile["ccm"].get>>(); 58 | int count = 0; 59 | for (auto i : m) 60 | { 61 | for (auto j : i) 62 | { 63 | 64 | isp_config->ccm_matrix[count] = (float)j; 65 | count++; 66 | } 67 | 68 | } 69 | 70 | std::vector> c; 71 | c = jfile["csc"].get>>(); 72 | count = 0; 73 | for (auto i : c) 74 | { 75 | for (auto j : i) 76 | { 77 | 78 | isp_config->csc_matrix[count] = (float)j; 79 | count++; 80 | } 81 | } 82 | 83 | std::vector> e; 84 | e = jfile["edge_filter"].get>>(); 85 | count = 0; 86 | for (auto i : e) 87 | { 88 | for (auto j : i) 89 | { 90 | 91 | isp_config->edge_filter[count] = (int16_t)j; 92 | count++; 93 | } 94 | } 95 | 96 | std::vector> w0; 97 | w0 = jfile["bnf"]["dw"].get>>(); 98 | count = 0; 99 | for (auto i : w0) 100 | { 101 | for (auto j : i) 102 | { 103 | 104 | isp_config->bnf_config.dw[count] = (uint16_t)j; 105 | count++; 106 | } 107 | } 108 | 109 | std::vector w1; 110 | w1 = jfile["bnf"]["rw"].get>(); 111 | count = 0; 112 | for (auto i : w1) 113 | { 114 | 115 | isp_config->bnf_config.rw[count] = (uint16_t)i; 116 | count++; 117 | } 118 | 119 | std::vector w2; 120 | w2 = jfile["bnf"]["rthres"].get>(); 121 | count = 0; 122 | for (auto i : w2) 123 | { 124 | 125 | isp_config->bnf_config.rthres[count] = (uint16_t)i; 126 | count++; 127 | } 128 | 129 | #if 0 130 | //log config 131 | cout << "isp pipeline config:" << endl; 132 | cout << "image resolution = " << isp_config->image_width << "x" << isp_config->image_height << "," << isp_config->image_bits << " bits/pixels" << endl; 133 | cout << "bayer_patter = " << isp_config->bayer_pattern << endl; 134 | cout << "gamma = " << isp_config->gamma << endl; 135 | cout << "dpc_threshold = " << isp_config->dpc_dead_thres << endl; 136 | cout << "awb gain :" << endl; 137 | cout << "r_gain = " << isp_config->awb_gain.r_gain << endl; 138 | cout << "gr_gain = " << isp_config->awb_gain.gr_gain << endl; 139 | cout << "gb_gain = " << isp_config->awb_gain.gb_gain << endl; 140 | cout << "b_gain = " << isp_config->awb_gain.b_gain << endl; 141 | cout << "ccm matrix:" << endl; 142 | cout << isp_config->ccm_matrix[0] << "," << isp_config->ccm_matrix[1] << "," << isp_config->ccm_matrix[2] << "," << isp_config->ccm_matrix[3] << endl; 143 | cout << isp_config->ccm_matrix[4] << "," << isp_config->ccm_matrix[5] << "," << isp_config->ccm_matrix[6] << "," << isp_config->ccm_matrix[7] << endl; 144 | cout << isp_config->ccm_matrix[8] << "," << isp_config->ccm_matrix[9] << "," << isp_config->ccm_matrix[10] << "," << isp_config->ccm_matrix[11] << endl; 145 | cout << "bnf dw:" << endl; 146 | cout << isp_config->bnf_config.dw[0] << "," << isp_config->bnf_config.dw[1] << "," << isp_config->bnf_config.dw[2] << "," << isp_config->bnf_config.dw[3] << "," << isp_config->bnf_config.dw[4] << endl; 147 | cout << isp_config->bnf_config.dw[5] << "," << isp_config->bnf_config.dw[6] << "," << isp_config->bnf_config.dw[7] << "," << isp_config->bnf_config.dw[8] << "," << isp_config->bnf_config.dw[9] << endl; 148 | cout << isp_config->bnf_config.dw[10] << "," << isp_config->bnf_config.dw[11] << "," << isp_config->bnf_config.dw[12] << "," << isp_config->bnf_config.dw[13] << "," << isp_config->bnf_config.dw[14] << endl; 149 | cout << isp_config->bnf_config.dw[15] << "," << isp_config->bnf_config.dw[16] << "," << isp_config->bnf_config.dw[17] << "," << isp_config->bnf_config.dw[18] << "," << isp_config->bnf_config.dw[19] << endl; 150 | cout << isp_config->bnf_config.dw[20] << "," << isp_config->bnf_config.dw[21] << "," << isp_config->bnf_config.dw[22] << "," << isp_config->bnf_config.dw[23] << "," << isp_config->bnf_config.dw[24] << endl; 151 | cout << "bnf rw:" << endl; 152 | cout << isp_config->bnf_config.rw[0] << "," << isp_config->bnf_config.rw[1] << "," << isp_config->bnf_config.rw[2] << "," << isp_config->bnf_config.rw[3] << endl; 153 | cout << "bnf rthres:" << endl; 154 | cout << isp_config->bnf_config.rthres[0] << "," << isp_config->bnf_config.rthres[1] << "," << isp_config->bnf_config.rthres[2] << endl; 155 | cout << "edge_filter:" << endl; 156 | cout << isp_config->edge_filter[0] << "," << isp_config->edge_filter[1] << "," << isp_config->edge_filter[2] << "," << isp_config->edge_filter[3] << "," << isp_config->edge_filter[4] << endl; 157 | cout << isp_config->edge_filter[5] << "," << isp_config->edge_filter[6] << "," << isp_config->edge_filter[7] << "," << isp_config->edge_filter[8] << "," << isp_config->edge_filter[9] << endl; 158 | cout << isp_config->edge_filter[10] << "," << isp_config->edge_filter[11] << "," << isp_config->edge_filter[12] << "," << isp_config->edge_filter[13] << "," << isp_config->edge_filter[14] << endl; 159 | cout << "eeh gain_min = " << isp_config->eeh_config.gain_min << endl; 160 | cout << "eeh gain_max = " << isp_config->eeh_config.gain_max << endl; 161 | cout << "eeh thres_min = " << isp_config->eeh_config.thres_min << endl; 162 | cout << "eeh thres_max = " << isp_config->eeh_config.thres_max << endl; 163 | cout << "eeh em_clip_min = " << isp_config->eeh_config.em_clip_min << endl; 164 | cout << "eeh em_clip_max = " << isp_config->eeh_config.em_clip_max << endl; 165 | cout << "fcs:" << endl; 166 | cout << "fcs edge min = " << +isp_config->fcs_config.edge_min << endl; 167 | cout << "fcs edge max = " << +isp_config->fcs_config.edge_max << endl; 168 | cout << "hsc:"<< endl; 169 | cout << "hsc hue_offset = " << +isp_config->hsc_config.hue_offset <> GAMMA_STEP; 224 | isp_gac(rgb_10b_buf, gamma_table, table_size, rgb_buf); 225 | 226 | free(rgb_10b_buf); 227 | } 228 | 229 | void isp_yuv_run(uint8_t *rgb_buf, uint8_t *yuv_buf) 230 | { 231 | uint32_t image_size = g_isp_config.image_height * g_isp_config.image_width; 232 | 233 | uint8_t *y_nlm_image = (uint8_t *)malloc(sizeof(uint8_t) * image_size); 234 | int8_t *ege_map = (int8_t *)malloc(sizeof(int8_t) * image_size); 235 | 236 | 237 | //rgb ro yuv 238 | isp_csc(rgb_buf, yuv_buf); 239 | 240 | /////////////////////////////////////////////////// 241 | /* Y channel processing */ 242 | /////////////////////////////////////////////////// 243 | 244 | //non local mean denoise 245 | isp_nlm(yuv_buf, y_nlm_image); 246 | // Mat mat_image_1(g_isp_config.image_height, g_isp_config.image_width, CV_8UC1, y_nlm_image); 247 | // imwrite("nlm.png", mat_image_1); 248 | 249 | // bilateral filter denoise 250 | isp_bnf(y_nlm_image, yuv_buf); 251 | // Mat mat_image_2(g_isp_config.image_height, g_isp_config.image_width, CV_8UC1, yuv_buf); 252 | // imwrite("bnf.png", mat_image_2); 253 | 254 | // edge enhancement 255 | isp_eeh(yuv_buf, ege_map); 256 | // Mat mat_image_3(g_isp_config.image_height, g_isp_config.image_width, CV_8UC1, yuv_buf); 257 | // imwrite("eeh.png", mat_image_3); 258 | 259 | //brightness contrast control 260 | isp_bcc(yuv_buf); 261 | // Mat mat_image_4(g_isp_config.image_height, g_isp_config.image_width, CV_8UC1, yuv_buf); 262 | // imwrite("bcc.png", mat_image_4); 263 | 264 | 265 | /////////////////////////////////////////////////// 266 | /* color channel processing */ 267 | /////////////////////////////////////////////////// 268 | 269 | //false color suppression 270 | isp_fcs(yuv_buf + image_size, ege_map); 271 | //hue saturation control 272 | isp_hsc(yuv_buf + image_size); 273 | 274 | 275 | free(y_nlm_image); 276 | free(ege_map); 277 | } -------------------------------------------------------------------------------- /inc/nlohmann/ordered_map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // equal_to, less 4 | #include // initializer_list 5 | #include // input_iterator_tag, iterator_traits 6 | #include // allocator 7 | #include // for out_of_range 8 | #include // enable_if, is_convertible 9 | #include // pair 10 | #include // vector 11 | 12 | #include 13 | #include 14 | 15 | namespace nlohmann 16 | { 17 | 18 | /// ordered_map: a minimal map-like container that preserves insertion order 19 | /// for use within nlohmann::basic_json 20 | template , 21 | class Allocator = std::allocator>> 22 | struct ordered_map : std::vector, Allocator> 23 | { 24 | using key_type = Key; 25 | using mapped_type = T; 26 | using Container = std::vector, Allocator>; 27 | using iterator = typename Container::iterator; 28 | using const_iterator = typename Container::const_iterator; 29 | using size_type = typename Container::size_type; 30 | using value_type = typename Container::value_type; 31 | #ifdef JSON_HAS_CPP_14 32 | using key_compare = std::equal_to<>; 33 | #else 34 | using key_compare = std::equal_to; 35 | #endif 36 | 37 | // Explicit constructors instead of `using Container::Container` 38 | // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) 39 | ordered_map() noexcept(noexcept(Container())) : Container{} {} 40 | explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} 41 | template 42 | ordered_map(It first, It last, const Allocator& alloc = Allocator()) 43 | : Container{first, last, alloc} {} 44 | ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) 45 | : Container{init, alloc} {} 46 | 47 | std::pair emplace(const key_type& key, T&& t) 48 | { 49 | for (auto it = this->begin(); it != this->end(); ++it) 50 | { 51 | if (m_compare(it->first, key)) 52 | { 53 | return {it, false}; 54 | } 55 | } 56 | Container::emplace_back(key, std::forward(t)); 57 | return {std::prev(this->end()), true}; 58 | } 59 | 60 | template::value, int> = 0> 62 | std::pair emplace(KeyType && key, T && t) 63 | { 64 | for (auto it = this->begin(); it != this->end(); ++it) 65 | { 66 | if (m_compare(it->first, key)) 67 | { 68 | return {it, false}; 69 | } 70 | } 71 | Container::emplace_back(std::forward(key), std::forward(t)); 72 | return {std::prev(this->end()), true}; 73 | } 74 | 75 | T& operator[](const key_type& key) 76 | { 77 | return emplace(key, T{}).first->second; 78 | } 79 | 80 | template::value, int> = 0> 82 | T & operator[](KeyType && key) 83 | { 84 | return emplace(std::forward(key), T{}).first->second; 85 | } 86 | 87 | const T& operator[](const key_type& key) const 88 | { 89 | return at(key); 90 | } 91 | 92 | template::value, int> = 0> 94 | const T & operator[](KeyType && key) const 95 | { 96 | return at(std::forward(key)); 97 | } 98 | 99 | T& at(const key_type& key) 100 | { 101 | for (auto it = this->begin(); it != this->end(); ++it) 102 | { 103 | if (m_compare(it->first, key)) 104 | { 105 | return it->second; 106 | } 107 | } 108 | 109 | JSON_THROW(std::out_of_range("key not found")); 110 | } 111 | 112 | template::value, int> = 0> 114 | T & at(KeyType && key) 115 | { 116 | for (auto it = this->begin(); it != this->end(); ++it) 117 | { 118 | if (m_compare(it->first, key)) 119 | { 120 | return it->second; 121 | } 122 | } 123 | 124 | JSON_THROW(std::out_of_range("key not found")); 125 | } 126 | 127 | const T& at(const key_type& key) const 128 | { 129 | for (auto it = this->begin(); it != this->end(); ++it) 130 | { 131 | if (m_compare(it->first, key)) 132 | { 133 | return it->second; 134 | } 135 | } 136 | 137 | JSON_THROW(std::out_of_range("key not found")); 138 | } 139 | 140 | template::value, int> = 0> 142 | const T & at(KeyType && key) const 143 | { 144 | for (auto it = this->begin(); it != this->end(); ++it) 145 | { 146 | if (m_compare(it->first, key)) 147 | { 148 | return it->second; 149 | } 150 | } 151 | 152 | JSON_THROW(std::out_of_range("key not found")); 153 | } 154 | 155 | size_type erase(const key_type& key) 156 | { 157 | for (auto it = this->begin(); it != this->end(); ++it) 158 | { 159 | if (m_compare(it->first, key)) 160 | { 161 | // Since we cannot move const Keys, re-construct them in place 162 | for (auto next = it; ++next != this->end(); ++it) 163 | { 164 | it->~value_type(); // Destroy but keep allocation 165 | new (&*it) value_type{std::move(*next)}; 166 | } 167 | Container::pop_back(); 168 | return 1; 169 | } 170 | } 171 | return 0; 172 | } 173 | 174 | template::value, int> = 0> 176 | size_type erase(KeyType && key) 177 | { 178 | for (auto it = this->begin(); it != this->end(); ++it) 179 | { 180 | if (m_compare(it->first, key)) 181 | { 182 | // Since we cannot move const Keys, re-construct them in place 183 | for (auto next = it; ++next != this->end(); ++it) 184 | { 185 | it->~value_type(); // Destroy but keep allocation 186 | new (&*it) value_type{std::move(*next)}; 187 | } 188 | Container::pop_back(); 189 | return 1; 190 | } 191 | } 192 | return 0; 193 | } 194 | 195 | iterator erase(iterator pos) 196 | { 197 | return erase(pos, std::next(pos)); 198 | } 199 | 200 | iterator erase(iterator first, iterator last) 201 | { 202 | if (first == last) 203 | { 204 | return first; 205 | } 206 | 207 | const auto elements_affected = std::distance(first, last); 208 | const auto offset = std::distance(Container::begin(), first); 209 | 210 | // This is the start situation. We need to delete elements_affected 211 | // elements (3 in this example: e, f, g), and need to return an 212 | // iterator past the last deleted element (h in this example). 213 | // Note that offset is the distance from the start of the vector 214 | // to first. We will need this later. 215 | 216 | // [ a, b, c, d, e, f, g, h, i, j ] 217 | // ^ ^ 218 | // first last 219 | 220 | // Since we cannot move const Keys, we re-construct them in place. 221 | // We start at first and re-construct (viz. copy) the elements from 222 | // the back of the vector. Example for first iteration: 223 | 224 | // ,--------. 225 | // v | destroy e and re-construct with h 226 | // [ a, b, c, d, e, f, g, h, i, j ] 227 | // ^ ^ 228 | // it it + elements_affected 229 | 230 | for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) 231 | { 232 | it->~value_type(); // destroy but keep allocation 233 | new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it 234 | } 235 | 236 | // [ a, b, c, d, h, i, j, h, i, j ] 237 | // ^ ^ 238 | // first last 239 | 240 | // remove the unneeded elements at the end of the vector 241 | Container::resize(this->size() - static_cast(elements_affected)); 242 | 243 | // [ a, b, c, d, h, i, j ] 244 | // ^ ^ 245 | // first last 246 | 247 | // first is now pointing past the last deleted element, but we cannot 248 | // use this iterator, because it may have been invalidated by the 249 | // resize call. Instead, we can return begin() + offset. 250 | return Container::begin() + offset; 251 | } 252 | 253 | size_type count(const key_type& key) const 254 | { 255 | for (auto it = this->begin(); it != this->end(); ++it) 256 | { 257 | if (m_compare(it->first, key)) 258 | { 259 | return 1; 260 | } 261 | } 262 | return 0; 263 | } 264 | 265 | template::value, int> = 0> 267 | size_type count(KeyType && key) const 268 | { 269 | for (auto it = this->begin(); it != this->end(); ++it) 270 | { 271 | if (m_compare(it->first, key)) 272 | { 273 | return 1; 274 | } 275 | } 276 | return 0; 277 | } 278 | 279 | iterator find(const key_type& key) 280 | { 281 | for (auto it = this->begin(); it != this->end(); ++it) 282 | { 283 | if (m_compare(it->first, key)) 284 | { 285 | return it; 286 | } 287 | } 288 | return Container::end(); 289 | } 290 | 291 | template::value, int> = 0> 293 | iterator find(KeyType && key) 294 | { 295 | for (auto it = this->begin(); it != this->end(); ++it) 296 | { 297 | if (m_compare(it->first, key)) 298 | { 299 | return it; 300 | } 301 | } 302 | return Container::end(); 303 | } 304 | 305 | const_iterator find(const key_type& key) const 306 | { 307 | for (auto it = this->begin(); it != this->end(); ++it) 308 | { 309 | if (m_compare(it->first, key)) 310 | { 311 | return it; 312 | } 313 | } 314 | return Container::end(); 315 | } 316 | 317 | std::pair insert( value_type&& value ) 318 | { 319 | return emplace(value.first, std::move(value.second)); 320 | } 321 | 322 | std::pair insert( const value_type& value ) 323 | { 324 | for (auto it = this->begin(); it != this->end(); ++it) 325 | { 326 | if (m_compare(it->first, value.first)) 327 | { 328 | return {it, false}; 329 | } 330 | } 331 | Container::push_back(value); 332 | return {--this->end(), true}; 333 | } 334 | 335 | template 336 | using require_input_iter = typename std::enable_if::iterator_category, 337 | std::input_iterator_tag>::value>::type; 338 | 339 | template> 340 | void insert(InputIt first, InputIt last) 341 | { 342 | for (auto it = first; it != last; ++it) 343 | { 344 | insert(*it); 345 | } 346 | } 347 | 348 | private: 349 | JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare(); 350 | }; 351 | 352 | } // namespace nlohmann 353 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/conversions/to_json.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // copy 4 | #include // begin, end 5 | #include // string 6 | #include // tuple, get 7 | #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type 8 | #include // move, forward, declval, pair 9 | #include // valarray 10 | #include // vector 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if JSON_HAS_EXPERIMENTAL_FILESYSTEM 19 | #include 20 | namespace nlohmann::detail 21 | { 22 | namespace std_fs = std::experimental::filesystem; 23 | } // namespace nlohmann::detail 24 | #elif JSON_HAS_FILESYSTEM 25 | #include 26 | namespace nlohmann::detail 27 | { 28 | namespace std_fs = std::filesystem; 29 | } // namespace nlohmann::detail 30 | #endif 31 | 32 | namespace nlohmann 33 | { 34 | namespace detail 35 | { 36 | ////////////////// 37 | // constructors // 38 | ////////////////// 39 | 40 | /* 41 | * Note all external_constructor<>::construct functions need to call 42 | * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an 43 | * allocated value (e.g., a string). See bug issue 44 | * https://github.com/nlohmann/json/issues/2865 for more information. 45 | */ 46 | 47 | template struct external_constructor; 48 | 49 | template<> 50 | struct external_constructor 51 | { 52 | template 53 | static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept 54 | { 55 | j.m_value.destroy(j.m_type); 56 | j.m_type = value_t::boolean; 57 | j.m_value = b; 58 | j.assert_invariant(); 59 | } 60 | }; 61 | 62 | template<> 63 | struct external_constructor 64 | { 65 | template 66 | static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) 67 | { 68 | j.m_value.destroy(j.m_type); 69 | j.m_type = value_t::string; 70 | j.m_value = s; 71 | j.assert_invariant(); 72 | } 73 | 74 | template 75 | static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) 76 | { 77 | j.m_value.destroy(j.m_type); 78 | j.m_type = value_t::string; 79 | j.m_value = std::move(s); 80 | j.assert_invariant(); 81 | } 82 | 83 | template < typename BasicJsonType, typename CompatibleStringType, 84 | enable_if_t < !std::is_same::value, 85 | int > = 0 > 86 | static void construct(BasicJsonType& j, const CompatibleStringType& str) 87 | { 88 | j.m_value.destroy(j.m_type); 89 | j.m_type = value_t::string; 90 | j.m_value.string = j.template create(str); 91 | j.assert_invariant(); 92 | } 93 | }; 94 | 95 | template<> 96 | struct external_constructor 97 | { 98 | template 99 | static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) 100 | { 101 | j.m_value.destroy(j.m_type); 102 | j.m_type = value_t::binary; 103 | j.m_value = typename BasicJsonType::binary_t(b); 104 | j.assert_invariant(); 105 | } 106 | 107 | template 108 | static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) 109 | { 110 | j.m_value.destroy(j.m_type); 111 | j.m_type = value_t::binary; 112 | j.m_value = typename BasicJsonType::binary_t(std::move(b)); 113 | j.assert_invariant(); 114 | } 115 | }; 116 | 117 | template<> 118 | struct external_constructor 119 | { 120 | template 121 | static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept 122 | { 123 | j.m_value.destroy(j.m_type); 124 | j.m_type = value_t::number_float; 125 | j.m_value = val; 126 | j.assert_invariant(); 127 | } 128 | }; 129 | 130 | template<> 131 | struct external_constructor 132 | { 133 | template 134 | static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept 135 | { 136 | j.m_value.destroy(j.m_type); 137 | j.m_type = value_t::number_unsigned; 138 | j.m_value = val; 139 | j.assert_invariant(); 140 | } 141 | }; 142 | 143 | template<> 144 | struct external_constructor 145 | { 146 | template 147 | static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept 148 | { 149 | j.m_value.destroy(j.m_type); 150 | j.m_type = value_t::number_integer; 151 | j.m_value = val; 152 | j.assert_invariant(); 153 | } 154 | }; 155 | 156 | template<> 157 | struct external_constructor 158 | { 159 | template 160 | static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) 161 | { 162 | j.m_value.destroy(j.m_type); 163 | j.m_type = value_t::array; 164 | j.m_value = arr; 165 | j.set_parents(); 166 | j.assert_invariant(); 167 | } 168 | 169 | template 170 | static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) 171 | { 172 | j.m_value.destroy(j.m_type); 173 | j.m_type = value_t::array; 174 | j.m_value = std::move(arr); 175 | j.set_parents(); 176 | j.assert_invariant(); 177 | } 178 | 179 | template < typename BasicJsonType, typename CompatibleArrayType, 180 | enable_if_t < !std::is_same::value, 181 | int > = 0 > 182 | static void construct(BasicJsonType& j, const CompatibleArrayType& arr) 183 | { 184 | using std::begin; 185 | using std::end; 186 | 187 | j.m_value.destroy(j.m_type); 188 | j.m_type = value_t::array; 189 | j.m_value.array = j.template create(begin(arr), end(arr)); 190 | j.set_parents(); 191 | j.assert_invariant(); 192 | } 193 | 194 | template 195 | static void construct(BasicJsonType& j, const std::vector& arr) 196 | { 197 | j.m_value.destroy(j.m_type); 198 | j.m_type = value_t::array; 199 | j.m_value = value_t::array; 200 | j.m_value.array->reserve(arr.size()); 201 | for (const bool x : arr) 202 | { 203 | j.m_value.array->push_back(x); 204 | j.set_parent(j.m_value.array->back()); 205 | } 206 | j.assert_invariant(); 207 | } 208 | 209 | template::value, int> = 0> 211 | static void construct(BasicJsonType& j, const std::valarray& arr) 212 | { 213 | j.m_value.destroy(j.m_type); 214 | j.m_type = value_t::array; 215 | j.m_value = value_t::array; 216 | j.m_value.array->resize(arr.size()); 217 | if (arr.size() > 0) 218 | { 219 | std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); 220 | } 221 | j.set_parents(); 222 | j.assert_invariant(); 223 | } 224 | }; 225 | 226 | template<> 227 | struct external_constructor 228 | { 229 | template 230 | static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) 231 | { 232 | j.m_value.destroy(j.m_type); 233 | j.m_type = value_t::object; 234 | j.m_value = obj; 235 | j.set_parents(); 236 | j.assert_invariant(); 237 | } 238 | 239 | template 240 | static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) 241 | { 242 | j.m_value.destroy(j.m_type); 243 | j.m_type = value_t::object; 244 | j.m_value = std::move(obj); 245 | j.set_parents(); 246 | j.assert_invariant(); 247 | } 248 | 249 | template < typename BasicJsonType, typename CompatibleObjectType, 250 | enable_if_t < !std::is_same::value, int > = 0 > 251 | static void construct(BasicJsonType& j, const CompatibleObjectType& obj) 252 | { 253 | using std::begin; 254 | using std::end; 255 | 256 | j.m_value.destroy(j.m_type); 257 | j.m_type = value_t::object; 258 | j.m_value.object = j.template create(begin(obj), end(obj)); 259 | j.set_parents(); 260 | j.assert_invariant(); 261 | } 262 | }; 263 | 264 | ///////////// 265 | // to_json // 266 | ///////////// 267 | 268 | template::value, int> = 0> 270 | inline void to_json(BasicJsonType& j, T b) noexcept 271 | { 272 | external_constructor::construct(j, b); 273 | } 274 | 275 | template::reference&, typename BasicJsonType::boolean_t>::value, int> = 0> 277 | inline void to_json(BasicJsonType& j, const std::vector::reference& b) noexcept 278 | { 279 | external_constructor::construct(j, static_cast(b)); 280 | } 281 | 282 | template::value, int> = 0> 284 | inline void to_json(BasicJsonType& j, const CompatibleString& s) 285 | { 286 | external_constructor::construct(j, s); 287 | } 288 | 289 | template 290 | inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) 291 | { 292 | external_constructor::construct(j, std::move(s)); 293 | } 294 | 295 | template::value, int> = 0> 297 | inline void to_json(BasicJsonType& j, FloatType val) noexcept 298 | { 299 | external_constructor::construct(j, static_cast(val)); 300 | } 301 | 302 | template::value, int> = 0> 304 | inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept 305 | { 306 | external_constructor::construct(j, static_cast(val)); 307 | } 308 | 309 | template::value, int> = 0> 311 | inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept 312 | { 313 | external_constructor::construct(j, static_cast(val)); 314 | } 315 | 316 | #if !JSON_DISABLE_ENUM_SERIALIZATION 317 | template::value, int> = 0> 319 | inline void to_json(BasicJsonType& j, EnumType e) noexcept 320 | { 321 | using underlying_type = typename std::underlying_type::type; 322 | external_constructor::construct(j, static_cast(e)); 323 | } 324 | #endif // JSON_DISABLE_ENUM_SERIALIZATION 325 | 326 | template 327 | inline void to_json(BasicJsonType& j, const std::vector& e) 328 | { 329 | external_constructor::construct(j, e); 330 | } 331 | 332 | template < typename BasicJsonType, typename CompatibleArrayType, 333 | enable_if_t < is_compatible_array_type::value&& 335 | !is_compatible_object_type::value&& 336 | !is_compatible_string_type::value&& 337 | !std::is_same::value&& 338 | !is_basic_json::value, 339 | int > = 0 > 340 | inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) 341 | { 342 | external_constructor::construct(j, arr); 343 | } 344 | 345 | template 346 | inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) 347 | { 348 | external_constructor::construct(j, bin); 349 | } 350 | 351 | template::value, int> = 0> 353 | inline void to_json(BasicJsonType& j, const std::valarray& arr) 354 | { 355 | external_constructor::construct(j, std::move(arr)); 356 | } 357 | 358 | template 359 | inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) 360 | { 361 | external_constructor::construct(j, std::move(arr)); 362 | } 363 | 364 | template < typename BasicJsonType, typename CompatibleObjectType, 365 | enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > 366 | inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) 367 | { 368 | external_constructor::construct(j, obj); 369 | } 370 | 371 | template 372 | inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) 373 | { 374 | external_constructor::construct(j, std::move(obj)); 375 | } 376 | 377 | template < 378 | typename BasicJsonType, typename T, std::size_t N, 379 | enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 381 | int > = 0 > 382 | inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 383 | { 384 | external_constructor::construct(j, arr); 385 | } 386 | 387 | template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > 388 | inline void to_json(BasicJsonType& j, const std::pair& p) 389 | { 390 | j = { p.first, p.second }; 391 | } 392 | 393 | // for https://github.com/nlohmann/json/pull/1134 394 | template>::value, int> = 0> 396 | inline void to_json(BasicJsonType& j, const T& b) 397 | { 398 | j = { {b.key(), b.value()} }; 399 | } 400 | 401 | template 402 | inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) 403 | { 404 | j = { std::get(t)... }; 405 | } 406 | 407 | template::value, int > = 0> 408 | inline void to_json(BasicJsonType& j, const T& t) 409 | { 410 | to_json_tuple_impl(j, t, make_index_sequence::value> {}); 411 | } 412 | 413 | #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM 414 | template 415 | inline void to_json(BasicJsonType& j, const std_fs::path& p) 416 | { 417 | j = p.string(); 418 | } 419 | #endif 420 | 421 | struct to_json_fn 422 | { 423 | template 424 | auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) 425 | -> decltype(to_json(j, std::forward(val)), void()) 426 | { 427 | return to_json(j, std::forward(val)); 428 | } 429 | }; 430 | } // namespace detail 431 | 432 | #ifndef JSON_HAS_CPP_17 433 | /// namespace to hold default `to_json` function 434 | /// to see why this is required: 435 | /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html 436 | namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) 437 | { 438 | #endif 439 | JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers) 440 | detail::static_const::value; 441 | #ifndef JSON_HAS_CPP_17 442 | } // namespace 443 | #endif 444 | } // namespace nlohmann 445 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/input/input_adapters.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // array 4 | #include // size_t 5 | #include // strlen 6 | #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next 7 | #include // shared_ptr, make_shared, addressof 8 | #include // accumulate 9 | #include // string, char_traits 10 | #include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer 11 | #include // pair, declval 12 | 13 | #ifndef JSON_NO_IO 14 | #include // FILE * 15 | #include // istream 16 | #endif // JSON_NO_IO 17 | 18 | #include 19 | #include 20 | 21 | namespace nlohmann 22 | { 23 | namespace detail 24 | { 25 | /// the supported input formats 26 | enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata }; 27 | 28 | //////////////////// 29 | // input adapters // 30 | //////////////////// 31 | 32 | #ifndef JSON_NO_IO 33 | /*! 34 | Input adapter for stdio file access. This adapter read only 1 byte and do not use any 35 | buffer. This adapter is a very low level adapter. 36 | */ 37 | class file_input_adapter 38 | { 39 | public: 40 | using char_type = char; 41 | 42 | JSON_HEDLEY_NON_NULL(2) 43 | explicit file_input_adapter(std::FILE* f) noexcept 44 | : m_file(f) 45 | {} 46 | 47 | // make class move-only 48 | file_input_adapter(const file_input_adapter&) = delete; 49 | file_input_adapter(file_input_adapter&&) noexcept = default; 50 | file_input_adapter& operator=(const file_input_adapter&) = delete; 51 | file_input_adapter& operator=(file_input_adapter&&) = delete; 52 | ~file_input_adapter() = default; 53 | 54 | std::char_traits::int_type get_character() noexcept 55 | { 56 | return std::fgetc(m_file); 57 | } 58 | 59 | private: 60 | /// the file pointer to read from 61 | std::FILE* m_file; 62 | }; 63 | 64 | 65 | /*! 66 | Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at 67 | beginning of input. Does not support changing the underlying std::streambuf 68 | in mid-input. Maintains underlying std::istream and std::streambuf to support 69 | subsequent use of standard std::istream operations to process any input 70 | characters following those used in parsing the JSON input. Clears the 71 | std::istream flags; any input errors (e.g., EOF) will be detected by the first 72 | subsequent call for input from the std::istream. 73 | */ 74 | class input_stream_adapter 75 | { 76 | public: 77 | using char_type = char; 78 | 79 | ~input_stream_adapter() 80 | { 81 | // clear stream flags; we use underlying streambuf I/O, do not 82 | // maintain ifstream flags, except eof 83 | if (is != nullptr) 84 | { 85 | is->clear(is->rdstate() & std::ios::eofbit); 86 | } 87 | } 88 | 89 | explicit input_stream_adapter(std::istream& i) 90 | : is(&i), sb(i.rdbuf()) 91 | {} 92 | 93 | // delete because of pointer members 94 | input_stream_adapter(const input_stream_adapter&) = delete; 95 | input_stream_adapter& operator=(input_stream_adapter&) = delete; 96 | input_stream_adapter& operator=(input_stream_adapter&&) = delete; 97 | 98 | input_stream_adapter(input_stream_adapter&& rhs) noexcept 99 | : is(rhs.is), sb(rhs.sb) 100 | { 101 | rhs.is = nullptr; 102 | rhs.sb = nullptr; 103 | } 104 | 105 | // std::istream/std::streambuf use std::char_traits::to_int_type, to 106 | // ensure that std::char_traits::eof() and the character 0xFF do not 107 | // end up as the same value, e.g. 0xFFFFFFFF. 108 | std::char_traits::int_type get_character() 109 | { 110 | auto res = sb->sbumpc(); 111 | // set eof manually, as we don't use the istream interface. 112 | if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) 113 | { 114 | is->clear(is->rdstate() | std::ios::eofbit); 115 | } 116 | return res; 117 | } 118 | 119 | private: 120 | /// the associated input stream 121 | std::istream* is = nullptr; 122 | std::streambuf* sb = nullptr; 123 | }; 124 | #endif // JSON_NO_IO 125 | 126 | // General-purpose iterator-based adapter. It might not be as fast as 127 | // theoretically possible for some containers, but it is extremely versatile. 128 | template 129 | class iterator_input_adapter 130 | { 131 | public: 132 | using char_type = typename std::iterator_traits::value_type; 133 | 134 | iterator_input_adapter(IteratorType first, IteratorType last) 135 | : current(std::move(first)), end(std::move(last)) 136 | {} 137 | 138 | typename std::char_traits::int_type get_character() 139 | { 140 | if (JSON_HEDLEY_LIKELY(current != end)) 141 | { 142 | auto result = std::char_traits::to_int_type(*current); 143 | std::advance(current, 1); 144 | return result; 145 | } 146 | 147 | return std::char_traits::eof(); 148 | } 149 | 150 | private: 151 | IteratorType current; 152 | IteratorType end; 153 | 154 | template 155 | friend struct wide_string_input_helper; 156 | 157 | bool empty() const 158 | { 159 | return current == end; 160 | } 161 | }; 162 | 163 | 164 | template 165 | struct wide_string_input_helper; 166 | 167 | template 168 | struct wide_string_input_helper 169 | { 170 | // UTF-32 171 | static void fill_buffer(BaseInputAdapter& input, 172 | std::array::int_type, 4>& utf8_bytes, 173 | size_t& utf8_bytes_index, 174 | size_t& utf8_bytes_filled) 175 | { 176 | utf8_bytes_index = 0; 177 | 178 | if (JSON_HEDLEY_UNLIKELY(input.empty())) 179 | { 180 | utf8_bytes[0] = std::char_traits::eof(); 181 | utf8_bytes_filled = 1; 182 | } 183 | else 184 | { 185 | // get the current character 186 | const auto wc = input.get_character(); 187 | 188 | // UTF-32 to UTF-8 encoding 189 | if (wc < 0x80) 190 | { 191 | utf8_bytes[0] = static_cast::int_type>(wc); 192 | utf8_bytes_filled = 1; 193 | } 194 | else if (wc <= 0x7FF) 195 | { 196 | utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); 197 | utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 198 | utf8_bytes_filled = 2; 199 | } 200 | else if (wc <= 0xFFFF) 201 | { 202 | utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); 203 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); 204 | utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 205 | utf8_bytes_filled = 3; 206 | } 207 | else if (wc <= 0x10FFFF) 208 | { 209 | utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); 210 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); 211 | utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); 212 | utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 213 | utf8_bytes_filled = 4; 214 | } 215 | else 216 | { 217 | // unknown character 218 | utf8_bytes[0] = static_cast::int_type>(wc); 219 | utf8_bytes_filled = 1; 220 | } 221 | } 222 | } 223 | }; 224 | 225 | template 226 | struct wide_string_input_helper 227 | { 228 | // UTF-16 229 | static void fill_buffer(BaseInputAdapter& input, 230 | std::array::int_type, 4>& utf8_bytes, 231 | size_t& utf8_bytes_index, 232 | size_t& utf8_bytes_filled) 233 | { 234 | utf8_bytes_index = 0; 235 | 236 | if (JSON_HEDLEY_UNLIKELY(input.empty())) 237 | { 238 | utf8_bytes[0] = std::char_traits::eof(); 239 | utf8_bytes_filled = 1; 240 | } 241 | else 242 | { 243 | // get the current character 244 | const auto wc = input.get_character(); 245 | 246 | // UTF-16 to UTF-8 encoding 247 | if (wc < 0x80) 248 | { 249 | utf8_bytes[0] = static_cast::int_type>(wc); 250 | utf8_bytes_filled = 1; 251 | } 252 | else if (wc <= 0x7FF) 253 | { 254 | utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); 255 | utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 256 | utf8_bytes_filled = 2; 257 | } 258 | else if (0xD800 > wc || wc >= 0xE000) 259 | { 260 | utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); 261 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); 262 | utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); 263 | utf8_bytes_filled = 3; 264 | } 265 | else 266 | { 267 | if (JSON_HEDLEY_UNLIKELY(!input.empty())) 268 | { 269 | const auto wc2 = static_cast(input.get_character()); 270 | const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); 271 | utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); 272 | utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); 273 | utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); 274 | utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); 275 | utf8_bytes_filled = 4; 276 | } 277 | else 278 | { 279 | utf8_bytes[0] = static_cast::int_type>(wc); 280 | utf8_bytes_filled = 1; 281 | } 282 | } 283 | } 284 | } 285 | }; 286 | 287 | // Wraps another input apdater to convert wide character types into individual bytes. 288 | template 289 | class wide_string_input_adapter 290 | { 291 | public: 292 | using char_type = char; 293 | 294 | wide_string_input_adapter(BaseInputAdapter base) 295 | : base_adapter(base) {} 296 | 297 | typename std::char_traits::int_type get_character() noexcept 298 | { 299 | // check if buffer needs to be filled 300 | if (utf8_bytes_index == utf8_bytes_filled) 301 | { 302 | fill_buffer(); 303 | 304 | JSON_ASSERT(utf8_bytes_filled > 0); 305 | JSON_ASSERT(utf8_bytes_index == 0); 306 | } 307 | 308 | // use buffer 309 | JSON_ASSERT(utf8_bytes_filled > 0); 310 | JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); 311 | return utf8_bytes[utf8_bytes_index++]; 312 | } 313 | 314 | private: 315 | BaseInputAdapter base_adapter; 316 | 317 | template 318 | void fill_buffer() 319 | { 320 | wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); 321 | } 322 | 323 | /// a buffer for UTF-8 bytes 324 | std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; 325 | 326 | /// index to the utf8_codes array for the next valid byte 327 | std::size_t utf8_bytes_index = 0; 328 | /// number of valid bytes in the utf8_codes array 329 | std::size_t utf8_bytes_filled = 0; 330 | }; 331 | 332 | 333 | template 334 | struct iterator_input_adapter_factory 335 | { 336 | using iterator_type = IteratorType; 337 | using char_type = typename std::iterator_traits::value_type; 338 | using adapter_type = iterator_input_adapter; 339 | 340 | static adapter_type create(IteratorType first, IteratorType last) 341 | { 342 | return adapter_type(std::move(first), std::move(last)); 343 | } 344 | }; 345 | 346 | template 347 | struct is_iterator_of_multibyte 348 | { 349 | using value_type = typename std::iterator_traits::value_type; 350 | enum 351 | { 352 | value = sizeof(value_type) > 1 353 | }; 354 | }; 355 | 356 | template 357 | struct iterator_input_adapter_factory::value>> 358 | { 359 | using iterator_type = IteratorType; 360 | using char_type = typename std::iterator_traits::value_type; 361 | using base_adapter_type = iterator_input_adapter; 362 | using adapter_type = wide_string_input_adapter; 363 | 364 | static adapter_type create(IteratorType first, IteratorType last) 365 | { 366 | return adapter_type(base_adapter_type(std::move(first), std::move(last))); 367 | } 368 | }; 369 | 370 | // General purpose iterator-based input 371 | template 372 | typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) 373 | { 374 | using factory_type = iterator_input_adapter_factory; 375 | return factory_type::create(first, last); 376 | } 377 | 378 | // Convenience shorthand from container to iterator 379 | // Enables ADL on begin(container) and end(container) 380 | // Encloses the using declarations in namespace for not to leak them to outside scope 381 | 382 | namespace container_input_adapter_factory_impl 383 | { 384 | 385 | using std::begin; 386 | using std::end; 387 | 388 | template 389 | struct container_input_adapter_factory {}; 390 | 391 | template 392 | struct container_input_adapter_factory< ContainerType, 393 | void_t()), end(std::declval()))>> 394 | { 395 | using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); 396 | 397 | static adapter_type create(const ContainerType& container) 398 | { 399 | return input_adapter(begin(container), end(container)); 400 | } 401 | }; 402 | 403 | } // namespace container_input_adapter_factory_impl 404 | 405 | template 406 | typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) 407 | { 408 | return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); 409 | } 410 | 411 | #ifndef JSON_NO_IO 412 | // Special cases with fast paths 413 | inline file_input_adapter input_adapter(std::FILE* file) 414 | { 415 | return file_input_adapter(file); 416 | } 417 | 418 | inline input_stream_adapter input_adapter(std::istream& stream) 419 | { 420 | return input_stream_adapter(stream); 421 | } 422 | 423 | inline input_stream_adapter input_adapter(std::istream&& stream) 424 | { 425 | return input_stream_adapter(stream); 426 | } 427 | #endif // JSON_NO_IO 428 | 429 | using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); 430 | 431 | // Null-delimited strings, and the like. 432 | template < typename CharT, 433 | typename std::enable_if < 434 | std::is_pointer::value&& 435 | !std::is_array::value&& 436 | std::is_integral::type>::value&& 437 | sizeof(typename std::remove_pointer::type) == 1, 438 | int >::type = 0 > 439 | contiguous_bytes_input_adapter input_adapter(CharT b) 440 | { 441 | auto length = std::strlen(reinterpret_cast(b)); 442 | const auto* ptr = reinterpret_cast(b); 443 | return input_adapter(ptr, ptr + length); 444 | } 445 | 446 | template 447 | auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 448 | { 449 | return input_adapter(array, array + N); 450 | } 451 | 452 | // This class only handles inputs of input_buffer_adapter type. 453 | // It's required so that expressions like {ptr, len} can be implicitly cast 454 | // to the correct adapter. 455 | class span_input_adapter 456 | { 457 | public: 458 | template < typename CharT, 459 | typename std::enable_if < 460 | std::is_pointer::value&& 461 | std::is_integral::type>::value&& 462 | sizeof(typename std::remove_pointer::type) == 1, 463 | int >::type = 0 > 464 | span_input_adapter(CharT b, std::size_t l) 465 | : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} 466 | 467 | template::iterator_category, std::random_access_iterator_tag>::value, 470 | int>::type = 0> 471 | span_input_adapter(IteratorType first, IteratorType last) 472 | : ia(input_adapter(first, last)) {} 473 | 474 | contiguous_bytes_input_adapter&& get() 475 | { 476 | return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) 477 | } 478 | 479 | private: 480 | contiguous_bytes_input_adapter ia; 481 | }; 482 | } // namespace detail 483 | } // namespace nlohmann 484 | -------------------------------------------------------------------------------- /inc/nlohmann/detail/input/parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // isfinite 4 | #include // uint8_t 5 | #include // function 6 | #include // string 7 | #include // move 8 | #include // vector 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace nlohmann 20 | { 21 | namespace detail 22 | { 23 | //////////// 24 | // parser // 25 | //////////// 26 | 27 | enum class parse_event_t : std::uint8_t 28 | { 29 | /// the parser read `{` and started to process a JSON object 30 | object_start, 31 | /// the parser read `}` and finished processing a JSON object 32 | object_end, 33 | /// the parser read `[` and started to process a JSON array 34 | array_start, 35 | /// the parser read `]` and finished processing a JSON array 36 | array_end, 37 | /// the parser read a key of a value in an object 38 | key, 39 | /// the parser finished reading a JSON value 40 | value 41 | }; 42 | 43 | template 44 | using parser_callback_t = 45 | std::function; 46 | 47 | /*! 48 | @brief syntax analysis 49 | 50 | This class implements a recursive descent parser. 51 | */ 52 | template 53 | class parser 54 | { 55 | using number_integer_t = typename BasicJsonType::number_integer_t; 56 | using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 57 | using number_float_t = typename BasicJsonType::number_float_t; 58 | using string_t = typename BasicJsonType::string_t; 59 | using lexer_t = lexer; 60 | using token_type = typename lexer_t::token_type; 61 | 62 | public: 63 | /// a parser reading from an input adapter 64 | explicit parser(InputAdapterType&& adapter, 65 | const parser_callback_t cb = nullptr, 66 | const bool allow_exceptions_ = true, 67 | const bool skip_comments = false) 68 | : callback(cb) 69 | , m_lexer(std::move(adapter), skip_comments) 70 | , allow_exceptions(allow_exceptions_) 71 | { 72 | // read first token 73 | get_token(); 74 | } 75 | 76 | /*! 77 | @brief public parser interface 78 | 79 | @param[in] strict whether to expect the last token to be EOF 80 | @param[in,out] result parsed JSON value 81 | 82 | @throw parse_error.101 in case of an unexpected token 83 | @throw parse_error.102 if to_unicode fails or surrogate error 84 | @throw parse_error.103 if to_unicode fails 85 | */ 86 | void parse(const bool strict, BasicJsonType& result) 87 | { 88 | if (callback) 89 | { 90 | json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); 91 | sax_parse_internal(&sdp); 92 | 93 | // in strict mode, input must be completely read 94 | if (strict && (get_token() != token_type::end_of_input)) 95 | { 96 | sdp.parse_error(m_lexer.get_position(), 97 | m_lexer.get_token_string(), 98 | parse_error::create(101, m_lexer.get_position(), 99 | exception_message(token_type::end_of_input, "value"), nullptr)); 100 | } 101 | 102 | // in case of an error, return discarded value 103 | if (sdp.is_errored()) 104 | { 105 | result = value_t::discarded; 106 | return; 107 | } 108 | 109 | // set top-level value to null if it was discarded by the callback 110 | // function 111 | if (result.is_discarded()) 112 | { 113 | result = nullptr; 114 | } 115 | } 116 | else 117 | { 118 | json_sax_dom_parser sdp(result, allow_exceptions); 119 | sax_parse_internal(&sdp); 120 | 121 | // in strict mode, input must be completely read 122 | if (strict && (get_token() != token_type::end_of_input)) 123 | { 124 | sdp.parse_error(m_lexer.get_position(), 125 | m_lexer.get_token_string(), 126 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); 127 | } 128 | 129 | // in case of an error, return discarded value 130 | if (sdp.is_errored()) 131 | { 132 | result = value_t::discarded; 133 | return; 134 | } 135 | } 136 | 137 | result.assert_invariant(); 138 | } 139 | 140 | /*! 141 | @brief public accept interface 142 | 143 | @param[in] strict whether to expect the last token to be EOF 144 | @return whether the input is a proper JSON text 145 | */ 146 | bool accept(const bool strict = true) 147 | { 148 | json_sax_acceptor sax_acceptor; 149 | return sax_parse(&sax_acceptor, strict); 150 | } 151 | 152 | template 153 | JSON_HEDLEY_NON_NULL(2) 154 | bool sax_parse(SAX* sax, const bool strict = true) 155 | { 156 | (void)detail::is_sax_static_asserts {}; 157 | const bool result = sax_parse_internal(sax); 158 | 159 | // strict mode: next byte must be EOF 160 | if (result && strict && (get_token() != token_type::end_of_input)) 161 | { 162 | return sax->parse_error(m_lexer.get_position(), 163 | m_lexer.get_token_string(), 164 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr)); 165 | } 166 | 167 | return result; 168 | } 169 | 170 | private: 171 | template 172 | JSON_HEDLEY_NON_NULL(2) 173 | bool sax_parse_internal(SAX* sax) 174 | { 175 | // stack to remember the hierarchy of structured values we are parsing 176 | // true = array; false = object 177 | std::vector states; 178 | // value to avoid a goto (see comment where set to true) 179 | bool skip_to_state_evaluation = false; 180 | 181 | while (true) 182 | { 183 | if (!skip_to_state_evaluation) 184 | { 185 | // invariant: get_token() was called before each iteration 186 | switch (last_token) 187 | { 188 | case token_type::begin_object: 189 | { 190 | if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) 191 | { 192 | return false; 193 | } 194 | 195 | // closing } -> we are done 196 | if (get_token() == token_type::end_object) 197 | { 198 | if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) 199 | { 200 | return false; 201 | } 202 | break; 203 | } 204 | 205 | // parse key 206 | if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) 207 | { 208 | return sax->parse_error(m_lexer.get_position(), 209 | m_lexer.get_token_string(), 210 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); 211 | } 212 | if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) 213 | { 214 | return false; 215 | } 216 | 217 | // parse separator (:) 218 | if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) 219 | { 220 | return sax->parse_error(m_lexer.get_position(), 221 | m_lexer.get_token_string(), 222 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); 223 | } 224 | 225 | // remember we are now inside an object 226 | states.push_back(false); 227 | 228 | // parse values 229 | get_token(); 230 | continue; 231 | } 232 | 233 | case token_type::begin_array: 234 | { 235 | if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) 236 | { 237 | return false; 238 | } 239 | 240 | // closing ] -> we are done 241 | if (get_token() == token_type::end_array) 242 | { 243 | if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) 244 | { 245 | return false; 246 | } 247 | break; 248 | } 249 | 250 | // remember we are now inside an array 251 | states.push_back(true); 252 | 253 | // parse values (no need to call get_token) 254 | continue; 255 | } 256 | 257 | case token_type::value_float: 258 | { 259 | const auto res = m_lexer.get_number_float(); 260 | 261 | if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) 262 | { 263 | return sax->parse_error(m_lexer.get_position(), 264 | m_lexer.get_token_string(), 265 | out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); 266 | } 267 | 268 | if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) 269 | { 270 | return false; 271 | } 272 | 273 | break; 274 | } 275 | 276 | case token_type::literal_false: 277 | { 278 | if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) 279 | { 280 | return false; 281 | } 282 | break; 283 | } 284 | 285 | case token_type::literal_null: 286 | { 287 | if (JSON_HEDLEY_UNLIKELY(!sax->null())) 288 | { 289 | return false; 290 | } 291 | break; 292 | } 293 | 294 | case token_type::literal_true: 295 | { 296 | if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) 297 | { 298 | return false; 299 | } 300 | break; 301 | } 302 | 303 | case token_type::value_integer: 304 | { 305 | if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) 306 | { 307 | return false; 308 | } 309 | break; 310 | } 311 | 312 | case token_type::value_string: 313 | { 314 | if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) 315 | { 316 | return false; 317 | } 318 | break; 319 | } 320 | 321 | case token_type::value_unsigned: 322 | { 323 | if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) 324 | { 325 | return false; 326 | } 327 | break; 328 | } 329 | 330 | case token_type::parse_error: 331 | { 332 | // using "uninitialized" to avoid "expected" message 333 | return sax->parse_error(m_lexer.get_position(), 334 | m_lexer.get_token_string(), 335 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr)); 336 | } 337 | 338 | case token_type::uninitialized: 339 | case token_type::end_array: 340 | case token_type::end_object: 341 | case token_type::name_separator: 342 | case token_type::value_separator: 343 | case token_type::end_of_input: 344 | case token_type::literal_or_value: 345 | default: // the last token was unexpected 346 | { 347 | return sax->parse_error(m_lexer.get_position(), 348 | m_lexer.get_token_string(), 349 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr)); 350 | } 351 | } 352 | } 353 | else 354 | { 355 | skip_to_state_evaluation = false; 356 | } 357 | 358 | // we reached this line after we successfully parsed a value 359 | if (states.empty()) 360 | { 361 | // empty stack: we reached the end of the hierarchy: done 362 | return true; 363 | } 364 | 365 | if (states.back()) // array 366 | { 367 | // comma -> next value 368 | if (get_token() == token_type::value_separator) 369 | { 370 | // parse a new value 371 | get_token(); 372 | continue; 373 | } 374 | 375 | // closing ] 376 | if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) 377 | { 378 | if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) 379 | { 380 | return false; 381 | } 382 | 383 | // We are done with this array. Before we can parse a 384 | // new value, we need to evaluate the new state first. 385 | // By setting skip_to_state_evaluation to false, we 386 | // are effectively jumping to the beginning of this if. 387 | JSON_ASSERT(!states.empty()); 388 | states.pop_back(); 389 | skip_to_state_evaluation = true; 390 | continue; 391 | } 392 | 393 | return sax->parse_error(m_lexer.get_position(), 394 | m_lexer.get_token_string(), 395 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr)); 396 | } 397 | 398 | // states.back() is false -> object 399 | 400 | // comma -> next value 401 | if (get_token() == token_type::value_separator) 402 | { 403 | // parse key 404 | if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) 405 | { 406 | return sax->parse_error(m_lexer.get_position(), 407 | m_lexer.get_token_string(), 408 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr)); 409 | } 410 | 411 | if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) 412 | { 413 | return false; 414 | } 415 | 416 | // parse separator (:) 417 | if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) 418 | { 419 | return sax->parse_error(m_lexer.get_position(), 420 | m_lexer.get_token_string(), 421 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr)); 422 | } 423 | 424 | // parse values 425 | get_token(); 426 | continue; 427 | } 428 | 429 | // closing } 430 | if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) 431 | { 432 | if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) 433 | { 434 | return false; 435 | } 436 | 437 | // We are done with this object. Before we can parse a 438 | // new value, we need to evaluate the new state first. 439 | // By setting skip_to_state_evaluation to false, we 440 | // are effectively jumping to the beginning of this if. 441 | JSON_ASSERT(!states.empty()); 442 | states.pop_back(); 443 | skip_to_state_evaluation = true; 444 | continue; 445 | } 446 | 447 | return sax->parse_error(m_lexer.get_position(), 448 | m_lexer.get_token_string(), 449 | parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr)); 450 | } 451 | } 452 | 453 | /// get next token from lexer 454 | token_type get_token() 455 | { 456 | return last_token = m_lexer.scan(); 457 | } 458 | 459 | std::string exception_message(const token_type expected, const std::string& context) 460 | { 461 | std::string error_msg = "syntax error "; 462 | 463 | if (!context.empty()) 464 | { 465 | error_msg += concat("while parsing ", context, ' '); 466 | } 467 | 468 | error_msg += "- "; 469 | 470 | if (last_token == token_type::parse_error) 471 | { 472 | error_msg += concat(m_lexer.get_error_message(), "; last read: '", 473 | m_lexer.get_token_string(), '\''); 474 | } 475 | else 476 | { 477 | error_msg += concat("unexpected ", lexer_t::token_type_name(last_token)); 478 | } 479 | 480 | if (expected != token_type::uninitialized) 481 | { 482 | error_msg += concat("; expected ", lexer_t::token_type_name(expected)); 483 | } 484 | 485 | return error_msg; 486 | } 487 | 488 | private: 489 | /// callback function 490 | const parser_callback_t callback = nullptr; 491 | /// the type of the last read token 492 | token_type last_token = token_type::uninitialized; 493 | /// the lexer 494 | lexer_t m_lexer; 495 | /// whether to throw exceptions in case of errors 496 | const bool allow_exceptions = true; 497 | }; 498 | 499 | } // namespace detail 500 | } // namespace nlohmann 501 | --------------------------------------------------------------------------------