From 9938a5881431ddcdebb36e0bf270155c9b8b4b3e Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Wed, 3 Jul 2024 18:48:26 +1200 Subject: [PATCH 01/20] copying the makefile preserving history Signed-off-by: Anton Dukhovnikov --- CMakeLists.txt => CMakeLists_tmp.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CMakeLists.txt => CMakeLists_tmp.txt (100%) diff --git a/CMakeLists.txt b/CMakeLists_tmp.txt similarity index 100% rename from CMakeLists.txt rename to CMakeLists_tmp.txt From 638b38e5d5af77caf990109a8fc3de9f7877e8d1 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Wed, 3 Jul 2024 18:46:29 +1200 Subject: [PATCH 02/20] moved the main app into subfolder Signed-off-by: Anton Dukhovnikov --- src/rawtoaces/CMakeLists.txt | 144 +++++++++++++++++++++++++++++ main.cpp => src/rawtoaces/main.cpp | 0 2 files changed, 144 insertions(+) create mode 100644 src/rawtoaces/CMakeLists.txt rename main.cpp => src/rawtoaces/main.cpp (100%) diff --git a/src/rawtoaces/CMakeLists.txt b/src/rawtoaces/CMakeLists.txt new file mode 100644 index 00000000..0b91e2da --- /dev/null +++ b/src/rawtoaces/CMakeLists.txt @@ -0,0 +1,144 @@ +cmake_minimum_required(VERSION 3.5) +project( RAWTOACES ) + +set( RAWTOACES_MAJOR_VERSION 1 ) +set( RAWTOACES_MINOR_VERSION 0 ) +set( RAWTOACES_PATCH_VERSION 0 ) +set( RAWTOACES_VERSION ${RAWTOACES_MAJOR_VERSION}.${RAWTOACES_MINOR_VERSION}.${RAWTOACES_PATCH_VERSION} ) + +set(RAWTOACESIDTLIB "rawtoaces_idt") +set(RAWTOACESLIB "rawtoaces_util") + +set( CMAKE_MACOSX_RPATH 1 ) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +# set(warnings "/W4 /WX /EHsc") + add_compile_options ( /W0 ) + add_compile_definitions( NOMINMAX ) +endif() + +if (NOT CONFIGURED_ONCE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warnings}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${warnings}") +endif() + +## Make install directories overridable +set( INSTALL_LIB_DIR lib CACHE PATH "Install directory for libraries" ) +set( INSTALL_BIN_DIR bin CACHE PATH "Install directory for executable binaries" ) +set( INSTALL_INCLUDE_DIR include CACHE PATH "Install directory for public header files" ) +if( WIN32 AND NOT CYGWIN ) + set(DEF_INSTALL_CMAKE_DIR CMake) +else() + set(DEF_INSTALL_CMAKE_DIR lib/CMake/RAWTOACES) +endif() +set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Install directory for project CMake files" ) + +# use, i.e. don't skip the full RPATH for the build tree +SET(CMAKE_SKIP_BUILD_RPATH FALSE) +# when building, don't use the install RPATH already +# (but later on when installing) +SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +# SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +# add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +# the RPATH to be used when installing, but only if it's not a system directory +LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) +IF("${isSystemDir}" STREQUAL "-1") + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +ENDIF("${isSystemDir}" STREQUAL "-1") + +## convert install paths to absolute +foreach( p LIB BIN INCLUDE CMAKE ) + set( var INSTALL_${p}_DIR ) + if( NOT IS_ABSOLUTE "${${var}}" ) + set( ${var} "${CMAKE_INSTALL_PREFIX}/${${var}}" ) + endif() +endforeach() + +option( ENABLE_SHARED "Enable Shared Libraries" ON ) + +if ( ENABLE_SHARED ) + set ( DO_SHARED SHARED ) +else () + set ( DO_SHARED STATIC ) +endif () + +include ( configure.cmake ) + + +# generated config files end up in binary dir so to find them, need +# to add to include path +include_directories( "${PROJECT_SOURCE_DIR}/include" ) + +add_definitions( -DPACKAGE="RAWTOACES" -DVERSION="${RAWTOACES_VERSION}" ) +add_subdirectory("src/${RAWTOACESIDTLIB}") +add_subdirectory("src/${RAWTOACESLIB}") + + + +# Create a RAWTOACESBuildTreeSettings.cmake file for the use from the build tree +file(RELATIVE_PATH CONF_REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${INSTALL_INCLUDE_DIR}") +configure_file(config/RAWTOACESBuildTreeSettings.cmake.in "${PROJECT_BINARY_DIR}/RAWTOACESBuildTreeSettings.cmake" @ONLY) +configure_file(config/RAWTOACESConfig.cmake.in "${PROJECT_BINARY_DIR}/RAWTOACESConfig.cmake" @ONLY) +configure_file(config/RAWTOACESConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/RAWTOACESConfigVersion.cmake" @ONLY) + +if ( PKG_CONFIG_FOUND ) + configure_file(config/RAWTOACES.pc.in "${PROJECT_BINARY_DIR}/RAWTOACES.pc" @ONLY) + install( FILES "${PROJECT_BINARY_DIR}/RAWTOACES.pc" DESTINATION lib/pkgconfig COMPONENT dev ) +endif() + +install( FILES + "${PROJECT_BINARY_DIR}/RAWTOACESConfig.cmake" + "${PROJECT_BINARY_DIR}/RAWTOACESConfigVersion.cmake" + DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) + +if ( WIN32 AND NOT CYGWIN ) +install( FILES "${PROJECT_BINARY_DIR}/RAWTOACESLibraryDepends.cmake" DESTINATION + "${INSTALL_CMAKE_DIR}" COMPONENT dev ) +endif( ) + +if ( APPLE OR UNIX ) + install (DIRECTORY data DESTINATION include/rawtoaces) +endif() + +### to build rawtoaces ### + +add_executable( rawtoaces + main.cpp +) + +target_include_directories( rawtoaces + PUBLIC + ${AcesContainer_INCLUDE_DIRS} +) + +target_link_libraries ( rawtoaces + PUBLIC + ${RAWTOACESLIB} + INTERFACE + Boost::headers +) + +if ( LIBRAW_CONFIG_FOUND ) + target_link_libraries ( rawtoaces PUBLIC libraw::raw ) +else () + target_link_directories(rawtoaces PUBLIC ${libraw_LIBRARY_DIRS} ) + target_link_libraries(rawtoaces PUBLIC ${libraw_LIBRARIES} ${libraw_LDFLAGS_OTHER} ) +endif () + +enable_testing() +add_subdirectory(unittest) + +install( TARGETS rawtoaces DESTINATION bin ) + +# uninstall target +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + + diff --git a/main.cpp b/src/rawtoaces/main.cpp similarity index 100% rename from main.cpp rename to src/rawtoaces/main.cpp From f0b601d6f154f645363ae34f16a4ee463e4c2f1b Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Wed, 3 Jul 2024 18:56:37 +1200 Subject: [PATCH 03/20] copying the makefile preserving history -- done Signed-off-by: Anton Dukhovnikov --- CMakeLists_tmp.txt => CMakeLists.txt | 29 +------ src/rawtoaces/CMakeLists.txt | 119 +-------------------------- 2 files changed, 2 insertions(+), 146 deletions(-) rename CMakeLists_tmp.txt => CMakeLists.txt (87%) diff --git a/CMakeLists_tmp.txt b/CMakeLists.txt similarity index 87% rename from CMakeLists_tmp.txt rename to CMakeLists.txt index 0b91e2da..c1405f7a 100644 --- a/CMakeLists_tmp.txt +++ b/CMakeLists.txt @@ -74,7 +74,7 @@ include_directories( "${PROJECT_SOURCE_DIR}/include" ) add_definitions( -DPACKAGE="RAWTOACES" -DVERSION="${RAWTOACES_VERSION}" ) add_subdirectory("src/${RAWTOACESIDTLIB}") add_subdirectory("src/${RAWTOACESLIB}") - +add_subdirectory("src/rawtoaces") # Create a RAWTOACESBuildTreeSettings.cmake file for the use from the build tree @@ -102,36 +102,9 @@ if ( APPLE OR UNIX ) install (DIRECTORY data DESTINATION include/rawtoaces) endif() -### to build rawtoaces ### - -add_executable( rawtoaces - main.cpp -) - -target_include_directories( rawtoaces - PUBLIC - ${AcesContainer_INCLUDE_DIRS} -) - -target_link_libraries ( rawtoaces - PUBLIC - ${RAWTOACESLIB} - INTERFACE - Boost::headers -) - -if ( LIBRAW_CONFIG_FOUND ) - target_link_libraries ( rawtoaces PUBLIC libraw::raw ) -else () - target_link_directories(rawtoaces PUBLIC ${libraw_LIBRARY_DIRS} ) - target_link_libraries(rawtoaces PUBLIC ${libraw_LIBRARIES} ${libraw_LDFLAGS_OTHER} ) -endif () - enable_testing() add_subdirectory(unittest) -install( TARGETS rawtoaces DESTINATION bin ) - # uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" diff --git a/src/rawtoaces/CMakeLists.txt b/src/rawtoaces/CMakeLists.txt index 0b91e2da..abc97ec1 100644 --- a/src/rawtoaces/CMakeLists.txt +++ b/src/rawtoaces/CMakeLists.txt @@ -1,108 +1,5 @@ cmake_minimum_required(VERSION 3.5) -project( RAWTOACES ) - -set( RAWTOACES_MAJOR_VERSION 1 ) -set( RAWTOACES_MINOR_VERSION 0 ) -set( RAWTOACES_PATCH_VERSION 0 ) -set( RAWTOACES_VERSION ${RAWTOACES_MAJOR_VERSION}.${RAWTOACES_MINOR_VERSION}.${RAWTOACES_PATCH_VERSION} ) - -set(RAWTOACESIDTLIB "rawtoaces_idt") -set(RAWTOACESLIB "rawtoaces_util") - -set( CMAKE_MACOSX_RPATH 1 ) - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") -# set(warnings "/W4 /WX /EHsc") - add_compile_options ( /W0 ) - add_compile_definitions( NOMINMAX ) -endif() - -if (NOT CONFIGURED_ONCE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warnings}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${warnings}") -endif() - -## Make install directories overridable -set( INSTALL_LIB_DIR lib CACHE PATH "Install directory for libraries" ) -set( INSTALL_BIN_DIR bin CACHE PATH "Install directory for executable binaries" ) -set( INSTALL_INCLUDE_DIR include CACHE PATH "Install directory for public header files" ) -if( WIN32 AND NOT CYGWIN ) - set(DEF_INSTALL_CMAKE_DIR CMake) -else() - set(DEF_INSTALL_CMAKE_DIR lib/CMake/RAWTOACES) -endif() -set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Install directory for project CMake files" ) - -# use, i.e. don't skip the full RPATH for the build tree -SET(CMAKE_SKIP_BUILD_RPATH FALSE) -# when building, don't use the install RPATH already -# (but later on when installing) -SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -# SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -# add the automatically determined parts of the RPATH -# which point to directories outside the build tree to the install RPATH -SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -# the RPATH to be used when installing, but only if it's not a system directory -LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) -IF("${isSystemDir}" STREQUAL "-1") - SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -ENDIF("${isSystemDir}" STREQUAL "-1") - -## convert install paths to absolute -foreach( p LIB BIN INCLUDE CMAKE ) - set( var INSTALL_${p}_DIR ) - if( NOT IS_ABSOLUTE "${${var}}" ) - set( ${var} "${CMAKE_INSTALL_PREFIX}/${${var}}" ) - endif() -endforeach() - -option( ENABLE_SHARED "Enable Shared Libraries" ON ) - -if ( ENABLE_SHARED ) - set ( DO_SHARED SHARED ) -else () - set ( DO_SHARED STATIC ) -endif () - -include ( configure.cmake ) - - -# generated config files end up in binary dir so to find them, need -# to add to include path -include_directories( "${PROJECT_SOURCE_DIR}/include" ) - -add_definitions( -DPACKAGE="RAWTOACES" -DVERSION="${RAWTOACES_VERSION}" ) -add_subdirectory("src/${RAWTOACESIDTLIB}") -add_subdirectory("src/${RAWTOACESLIB}") - - - -# Create a RAWTOACESBuildTreeSettings.cmake file for the use from the build tree -file(RELATIVE_PATH CONF_REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${INSTALL_INCLUDE_DIR}") -configure_file(config/RAWTOACESBuildTreeSettings.cmake.in "${PROJECT_BINARY_DIR}/RAWTOACESBuildTreeSettings.cmake" @ONLY) -configure_file(config/RAWTOACESConfig.cmake.in "${PROJECT_BINARY_DIR}/RAWTOACESConfig.cmake" @ONLY) -configure_file(config/RAWTOACESConfigVersion.cmake.in "${PROJECT_BINARY_DIR}/RAWTOACESConfigVersion.cmake" @ONLY) - -if ( PKG_CONFIG_FOUND ) - configure_file(config/RAWTOACES.pc.in "${PROJECT_BINARY_DIR}/RAWTOACES.pc" @ONLY) - install( FILES "${PROJECT_BINARY_DIR}/RAWTOACES.pc" DESTINATION lib/pkgconfig COMPONENT dev ) -endif() - -install( FILES - "${PROJECT_BINARY_DIR}/RAWTOACESConfig.cmake" - "${PROJECT_BINARY_DIR}/RAWTOACESConfigVersion.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) - -if ( WIN32 AND NOT CYGWIN ) -install( FILES "${PROJECT_BINARY_DIR}/RAWTOACESLibraryDepends.cmake" DESTINATION - "${INSTALL_CMAKE_DIR}" COMPONENT dev ) -endif( ) - -if ( APPLE OR UNIX ) - install (DIRECTORY data DESTINATION include/rawtoaces) -endif() - -### to build rawtoaces ### +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_executable( rawtoaces main.cpp @@ -127,18 +24,4 @@ else () target_link_libraries(rawtoaces PUBLIC ${libraw_LIBRARIES} ${libraw_LDFLAGS_OTHER} ) endif () -enable_testing() -add_subdirectory(unittest) - install( TARGETS rawtoaces DESTINATION bin ) - -# uninstall target -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) - -add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) - - From 35efa4a5d00d05e31dfccbe8b5ff3c9faa90655f Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 5 Aug 2024 20:11:43 +1200 Subject: [PATCH 04/20] Implement OIIO-based version of the tool Signed-off-by: Anton Dukhovnikov --- .github/workflows/ci.yml | 31 +- CMakeLists.txt | 4 +- build_scripts/install_deps.bash | 1 + build_scripts/install_deps_linux.bash | 8 +- build_scripts/install_deps_mac.bash | 2 +- build_scripts/install_deps_windows.bash | 1 + configure.cmake | 1 + include/rawtoaces/define.h | 18 +- include/rawtoaces/metadata.h | 29 + include/rawtoaces/rawtoaces_util.h | 167 +++++ include/rawtoaces/rta.h | 15 +- src/rawtoaces2/CMakeLists.txt | 21 + src/rawtoaces2/main.cpp | 106 +++ src/rawtoaces_idt/rta.cpp | 98 +-- src/rawtoaces_util/acesrender.cpp | 45 +- src/rawtoaces_util2/CMakeLists.txt | 37 + src/rawtoaces_util2/rawtoaces_util.cpp | 958 ++++++++++++++++++++++++ unittest/testDNGIdt.cpp | 119 +-- 18 files changed, 1520 insertions(+), 141 deletions(-) create mode 100644 include/rawtoaces/metadata.h create mode 100644 include/rawtoaces/rawtoaces_util.h create mode 100644 src/rawtoaces2/CMakeLists.txt create mode 100644 src/rawtoaces2/main.cpp create mode 100644 src/rawtoaces_util2/CMakeLists.txt create mode 100644 src/rawtoaces_util2/rawtoaces_util.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 801e5844..fda874ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,7 @@ jobs: CC: ${{matrix.cc_compiler}} CMAKE_CXX_STANDARD: ${{matrix.cxx_std}} OPENEXR_VERSION: ${{matrix.openexr_ver}} + CMAKE_CXX_FLAGS: "-lstdc++fs" steps: - uses: actions/checkout@v4 @@ -83,40 +84,46 @@ jobs: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + title: [ubuntu, windows, macos] build_type: [Release] c_compiler: [gcc, clang, cl] include: - - os: windows-latest + - title: windows + os: windows-latest c_compiler: cl cpp_compiler: cl install_deps: install_deps_windows toolchain_file: "C:/vcpkg/scripts/buildsystems/vcpkg.cmake" build_shared_libs: OFF - - os: ubuntu-latest + - title: ubuntu + os: ubuntu-24.04 c_compiler: gcc cpp_compiler: g++ install_deps: install_deps_linux - - os: ubuntu-latest - c_compiler: clang + - title: ubuntu + os: ubuntu-24.04 cpp_compiler: clang++ install_deps: install_deps_linux - - os: macos-latest + - title: macos + os: macos-latest c_compiler: clang cpp_compiler: clang++ install_deps: install_deps_mac exclude: - - os: windows-latest + - title: windows c_compiler: gcc - - os: windows-latest + - title: windows c_compiler: clang - - os: ubuntu-latest + - title: ubuntu c_compiler: cl - - os: macos-latest + - title: macos c_compiler: cl - - os: macos-latest + - title: macos c_compiler: gcc + env: + CMAKE_CXX_FLAGS: "-lstdc++fs" + steps: - uses: actions/checkout@v4 @@ -140,7 +147,7 @@ jobs: cmake -B ${{ steps.strings.outputs.build-output-dir }} -S ${{ github.workspace }} - -DCXX_STANDARD=C++14 + -DCXX_STANDARD=C++17 -DCMAKE_TOOLCHAIN_FILE="${{ matrix.toolchain_file }}" -DENABLE_SHARED="${{ matrix.build_shared_libs }}" diff --git a/CMakeLists.txt b/CMakeLists.txt index c1405f7a..0d6f761d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,9 +12,9 @@ set(RAWTOACESLIB "rawtoaces_util") set( CMAKE_MACOSX_RPATH 1 ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") -# set(warnings "/W4 /WX /EHsc") add_compile_options ( /W0 ) add_compile_definitions( NOMINMAX ) + add_compile_options ( $<$:/utf-8> ) endif() if (NOT CONFIGURED_ONCE) @@ -76,6 +76,8 @@ add_subdirectory("src/${RAWTOACESIDTLIB}") add_subdirectory("src/${RAWTOACESLIB}") add_subdirectory("src/rawtoaces") +add_subdirectory("src/rawtoaces_util2") +add_subdirectory("src/rawtoaces2") # Create a RAWTOACESBuildTreeSettings.cmake file for the use from the build tree file(RELATIVE_PATH CONF_REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${INSTALL_INCLUDE_DIR}") diff --git a/build_scripts/install_deps.bash b/build_scripts/install_deps.bash index b56f40af..d9519954 100755 --- a/build_scripts/install_deps.bash +++ b/build_scripts/install_deps.bash @@ -8,6 +8,7 @@ time sudo apt-get update time sudo apt-get -q -f install -y \ libunwind-dev libilmbase-dev libopenexr-dev \ + libopenimageio-dev \ libboost-dev libboost-thread-dev libboost-filesystem-dev \ libboost-test-dev \ libraw-dev libceres-dev diff --git a/build_scripts/install_deps_linux.bash b/build_scripts/install_deps_linux.bash index e29f9c4c..a72b1d8c 100755 --- a/build_scripts/install_deps_linux.bash +++ b/build_scripts/install_deps_linux.bash @@ -5,7 +5,11 @@ set -ex time sudo apt-get update time sudo apt-get -q -f install -y \ - libunwind-dev libimath-dev \ + libunwind-dev \ + libimath-dev libopenexr-dev \ libboost-dev libboost-filesystem-dev \ libboost-test-dev \ - libraw-dev libceres-dev + libraw-dev libceres-dev \ + libopencv-dev \ + openimageio-tools \ + libopenimageio-dev diff --git a/build_scripts/install_deps_mac.bash b/build_scripts/install_deps_mac.bash index 223fd737..15d4f440 100755 --- a/build_scripts/install_deps_mac.bash +++ b/build_scripts/install_deps_mac.bash @@ -2,4 +2,4 @@ set -ex -brew install ceres-solver imath openexr libraw boost +brew install ceres-solver imath openexr libraw boost openimageio diff --git a/build_scripts/install_deps_windows.bash b/build_scripts/install_deps_windows.bash index b0dd8a14..9743b622 100755 --- a/build_scripts/install_deps_windows.bash +++ b/build_scripts/install_deps_windows.bash @@ -6,6 +6,7 @@ vcpkg install \ libraw:x64-windows \ ceres:x64-windows \ imath:x64-windows \ + openimageio:x64-windows \ boost-system:x64-windows \ boost-foreach:x64-windows \ boost-filesystem:x64-windows \ diff --git a/configure.cmake b/configure.cmake index 6e831feb..51b9cec5 100644 --- a/configure.cmake +++ b/configure.cmake @@ -3,6 +3,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_INSTALL_PREFIX}/share/CMake") +find_package ( OpenImageIO CONFIG REQUIRED ) find_package ( AcesContainer CONFIG REQUIRED ) find_package ( Eigen3 CONFIG REQUIRED ) find_package ( Imath CONFIG REQUIRED ) diff --git a/include/rawtoaces/define.h b/include/rawtoaces/define.h index 3b3a28ab..77794c14 100644 --- a/include/rawtoaces/define.h +++ b/include/rawtoaces/define.h @@ -266,6 +266,20 @@ static const double XYZ_acesrgb_4[4][4] = { { 0.0, 0.0, 0.0, 1.0 } }; +static const float XYZ_acesrgb_float_4[4][4] = { + { 1.0498110175, 0.0000000000, -0.0000974845, 0.0 }, + { -0.4959030231, 1.3733130458, 0.0982400361, 0.0 }, + { 0.0000000000, 0.0000000000, 0.9912520182, 0.0 }, + { 0.0, 0.0, 0.0, 1.0 } +}; + +static const float XYZ_acesrgb_transposed_4[4][4] = { + { 1.0498110175, -0.4959030231, 0.0000000000, 0.0 }, + { 0.0000000000, 1.3733130458, 0.0000000000, 0.0 }, + { -0.0000974845, 0.0982400361, 0.9912520182, 0.0 }, + { 0.0000000000, 0.0000000000, 0.0000000000, 1.0 } +}; + static const double acesrgb_XYZ_3[3][3] = { { 0.952552395938186, 0.0, 9.36786316604686e-05 }, { 0.343966449765075, 0.728166096613485, -0.0721325463785608 }, @@ -390,8 +404,8 @@ inline bool isCTLetterDigit( const char c ) // to represent color temperature(s) (e.g., D60, 3200K) inline bool isValidCT( string str ) { - int i = 0; - int length = str.length(); + int i = 0; + size_t length = str.length(); if ( length == 0 ) return false; diff --git a/include/rawtoaces/metadata.h b/include/rawtoaces/metadata.h new file mode 100644 index 00000000..3abd5741 --- /dev/null +++ b/include/rawtoaces/metadata.h @@ -0,0 +1,29 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#ifndef RTA_METADATA_H_ +#define RTA_METADATA_H_ + +namespace rta +{ + +struct Metadata +{ + // Colorimetry + std::vector cameraCalibration1; + std::vector cameraCalibration2; + std::vector xyz2rgbMatrix1; + std::vector xyz2rgbMatrix2; + double calibrationIlluminant1; + double calibrationIlluminant2; + + std::vector analogBalance; + std::vector neutralRGB; + + double baselineExposure; +}; + +} // namespace rta + +#endif // RTA_METADATA_H_ diff --git a/include/rawtoaces/rawtoaces_util.h b/include/rawtoaces/rawtoaces_util.h new file mode 100644 index 00000000..618644f0 --- /dev/null +++ b/include/rawtoaces/rawtoaces_util.h @@ -0,0 +1,167 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#ifndef _RAWTOACES_UTIL_H_ +#define _RAWTOACES_UTIL_H_ + +#include +#include +#include + +namespace rta +{ + +/// An image converter converts an image read from a camera raw image file +/// into an ACESContainer compatible image. +class ImageConverter +{ +public: + ImageConverter(); + + /// The white balancing method to use for conversion can be specified + /// + enum class WBMethod + { + /// Use the metadata provided in the image file. This mode is mostly + /// usable with DNG files, as the information needed for conversion + /// is mandatory in the DNG format. + Metadata, + /// White balance to a specified illuminant. See the `illuminant` + /// property for more information on the supported illuminants. This + /// mode can only be used if spectral sensitivities are available for + /// the camera. + Illuminant, + /// Calculate white balance by averaging over a specified region of + /// the image. See `wbBox`. In this mode if an empty box if provided, + /// white balancing is done by averaging over the whole image. + Box, + /// Use custom white balancing multipliers. This mode is useful if + /// the white balancing coefficients are calculated by an external + /// tool. + Custom + } wbMethod = WBMethod::Metadata; + + enum class MatrixMethod + { + /// Use the camera spectral sensitivity curves to solve for the colour + /// conversion matrix. In this mode the illuminant is either provided + /// directly in `illuminant` if `wbMethod` == + /// `WBMethod::Illuminant`, or the best illuminant is derived from the + /// white balancing multipliers. + Spectral, + /// Use the metadata provided in the image file. This mode is mostly + /// usable with DNG files, as the information needed for conversion + /// is mandatory in the DNG format. + Metadata, + /// Use the Adobe colour matrix for the camera supplied in LibRaw. + Adobe, + /// Specify a custom matrix in `colourMatrix`. This mode is useful if + /// the matrix is calculated by an external tool. + Custom + } matrixMethod = MatrixMethod::Spectral; + + /// An illuminant to use for white balancing and/or colour matrix + /// calculation. Only used when `wbMethod` == + /// `WBMethod::Illuminant` or `matrixMethod` == `MatrixMethod::Spectral`. + /// An illuminant can be provided as a black body correlated colour + /// temperature, like `3200K`; or a D-series illuminant, like `D56`; + /// or any other illuminant, in such case it must be present in the data + /// folder. + std::string illuminant; + + float headroom = 6.0; + int wbBox[4] = { 0 }; + float customWB[4] = { 1.0, 1.0, 1.0, 1.0 }; + float customMatrix[3][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }; + + bool no_auto_bright = false; + float adjust_maximum_threshold = 0.75; + int black_level = -1; + int saturation_level = -1; + bool half_size = false; + int highlight_mode = 0; + int flip = 0; + int cropbox[4] = { 0, 0, 0, 0 }; + + int verbosity; + + /// Returns a class which will be used for parsing the command line + /// parameters. Can be used to add additional parameters before calling + /// `parse()`. The additional parameters will be parsed by ignored by this + /// class. + /// @result A non-const reference to an + /// initialised OIIO::ArgParse class. + OIIO::ArgParse &argParse(); + + /// Returns an image buffer, containing the image in the current state + /// after the previous step of processing. The image can be modified before + /// executing the next step if needed. + /// @result A non-const reference to the image buffer. + OIIO::ImageBuf &imageBuffer(); + + /// Parse the command line parameters. This method can be used to + /// configure the converter instead of modifying each conversion parameter + /// individually. Additional command line parameters can be added by + /// modifying the structure returned by `argParse()`. + /// @param argc + /// number of parameters + /// @param argv + /// list of parameters + /// @result + /// `true` if parsed successfully + bool parse( int argc, const char *argv[] ); + + /// Configures the converter using the requested white balance and colour + /// matrix method, and the metadata of the file provided in `input_file`. + /// @param input_filename + /// A file name of the raw image file to read the metadata from. + /// @result + /// `true` if configured successfully. + bool configure( const std::string &input_filename ); + + /// Loads an image to convert. Note that the image file name in + /// `input_filename` can be differnt from the one used in `configure()`. + /// This is useful for configuring the converter using one image, and + /// applying the conversion to a different one, or multiple images. + /// @param input_filename + /// A file name of the raw image file to read the pixels from. + /// @result + /// `true` if loaded successfully. + bool load( const std::string &input_filename ); + + /// Converts the image from raw camera colour space to ACES. + /// @result + /// `true` if converted successfully. + bool process(); + + /// Saves the image into ACES Container. + /// @result + /// `true` if saved successfully. + bool save( const std::string &output_filename ); + +private: + void initArgParse(); + void prepareIDT_DNG(); + void prepareIDT_nonDNG(); + void prepareIDT_spectral( bool calc_white_balance, bool calc_matrix ); + void applyMatrix( const std::vector> &matrix ); + + bool _is_DNG; + std::string _configFilename; + std::string _cameraMake; + std::string _cameraModel; + + OIIO::ArgParse _argParse; + OIIO::ImageSpec _inputHint; + OIIO::ImageSpec _inputFull; + OIIO::ImageBuf _imageBuffer; + + std::vector _WB_mults; + std::vector> _IDT_matrix; + std::vector> _CAT_matrix; +}; + +} // namespace rta + +#endif // _RAWTOACES_UTIL_H_ diff --git a/include/rawtoaces/rta.h b/include/rawtoaces/rta.h index bb867dc3..25b42375 100644 --- a/include/rawtoaces/rta.h +++ b/include/rawtoaces/rta.h @@ -60,6 +60,9 @@ #include #include +#include "mathOps.h" +#include "metadata.h" + using namespace std; namespace rta @@ -226,7 +229,7 @@ class DNGIdt { public: DNGIdt(); - DNGIdt( libraw_rawdata_t R ); + DNGIdt( const Metadata &metadata ); virtual ~DNGIdt(); double ccttoMired( const double cct ) const; @@ -247,16 +250,10 @@ class DNGIdt void getCameraXYZMtxAndWhitePoint(); private: - vector _cameraCalibration1DNG; - vector _cameraCalibration2DNG; vector _cameraToXYZMtx; - vector _xyz2rgbMatrix1DNG; - vector _xyz2rgbMatrix2DNG; - vector _analogBalanceDNG; - vector _neutralRGBDNG; vector _cameraXYZWhitePoint; - vector _calibrateIllum; - double _baseExpo; + + Metadata _metadata; }; struct Objfun diff --git a/src/rawtoaces2/CMakeLists.txt b/src/rawtoaces2/CMakeLists.txt new file mode 100644 index 00000000..4f6c0922 --- /dev/null +++ b/src/rawtoaces2/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.5) +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) + +add_executable( rawtoaces2 + main.cpp +) + +set_property(TARGET rawtoaces2 PROPERTY CXX_STANDARD 17) + +target_include_directories( rawtoaces2 + PUBLIC + ${OpenImageIO_INCLUDE_DIR} +) + +target_link_libraries ( rawtoaces2 + PUBLIC +# OpenImageIO::OpenImageIO + rawtoaces_util2 +) + +install( TARGETS rawtoaces2 DESTINATION bin ) diff --git a/src/rawtoaces2/main.cpp b/src/rawtoaces2/main.cpp new file mode 100644 index 00000000..3e8d8cf0 --- /dev/null +++ b/src/rawtoaces2/main.cpp @@ -0,0 +1,106 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include + +#include + +using namespace rta; + +int main( int argc, const char *argv[] ) +{ + ImageConverter converter; + + if ( !converter.parse( argc, argv ) ) + { + return 1; + } + + auto &argParse = converter.argParse(); + auto files = argParse["filename"].as_vec(); + std::vector files_to_convert; + + for ( auto filename: files ) + { + if ( !std::filesystem::exists( filename ) ) + { + std::cerr << "File or directory not found: " << filename + << std::endl; + return 1; + } + + auto canonical_filename = std::filesystem::canonical( filename ); + + if ( std::filesystem::is_directory( filename ) ) + { + auto it = std::filesystem::directory_iterator( filename ); + + for ( auto filename2: it ) + { + if ( std::filesystem::is_regular_file( filename2 ) || + std::filesystem::is_symlink( filename2 ) ) + { + files_to_convert.push_back( filename2.path().string() ); + } + } + } + else if ( + std::filesystem::is_regular_file( filename ) || + std::filesystem::is_symlink( filename ) ) + { + files_to_convert.push_back( filename ); + } + else + { + std::cerr << "Not a file or directory: " << filename << std::endl; + return 1; + } + } + + bool result = true; + for ( auto const &input_filename: files_to_convert ) + { + std::string output_filename = input_filename; + size_t pos = input_filename.rfind( '.' ); + if ( pos != std::string::npos ) + { + output_filename = input_filename.substr( 0, pos ); + } + output_filename += "_oiio.exr"; + + if ( !converter.configure( input_filename ) ) + { + std::cerr << "Failed to configure the reader for the file: " + << input_filename << std::endl; + result = false; + continue; + } + + if ( !converter.load( input_filename ) ) + { + std::cerr << "Failed to read for the file: " << input_filename + << std::endl; + result = false; + continue; + } + + if ( !converter.process() ) + { + std::cerr << "Failed to convert the file: " << input_filename + << std::endl; + result = false; + continue; + } + + if ( !converter.save( output_filename ) ) + { + std::cerr << "Failed to save the file: " << output_filename + << std::endl; + result = false; + continue; + } + } + + return result ? 0 : 1; +} diff --git a/src/rawtoaces_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 73b2973a..6582f3ff 100644 --- a/src/rawtoaces_idt/rta.cpp +++ b/src/rawtoaces_idt/rta.cpp @@ -592,7 +592,7 @@ int Spst::getWLIncrement() int Spst::loadSpst( const string &path, const char *maker, const char *model ) { - assert( path.length() > 0 && maker != nullptr && model != nullptr ); + assert( path.length() > 0 ); vector rgbsen; vector max( 3, dmin ); @@ -603,12 +603,12 @@ int Spst::loadSpst( const string &path, const char *maker, const char *model ) read_json( path, pt ); string cmaker = pt.get( "header.manufacturer" ); - if ( cmp_str( maker, cmaker.c_str() ) ) + if ( maker != nullptr && cmp_str( maker, cmaker.c_str() ) ) return 0; setBrand( cmaker.c_str() ); string cmodel = pt.get( "header.model" ); - if ( cmp_str( model, cmodel.c_str() ) ) + if ( model != nullptr && cmp_str( model, cmodel.c_str() ) ) return 0; setModel( cmodel.c_str() ); @@ -1543,67 +1543,21 @@ const vector Idt::getWB() const DNGIdt::DNGIdt() { - _cameraCalibration1DNG = vector( 9, 1.0 ); - _cameraCalibration2DNG = vector( 9, 1.0 ); - _cameraToXYZMtx = vector( 9, 1.0 ); - _xyz2rgbMatrix1DNG = vector( 9, 1.0 ); - _xyz2rgbMatrix2DNG = vector( 9, 1.0 ); - _analogBalanceDNG = vector( 3, 1.0 ); - _neutralRGBDNG = vector( 3, 1.0 ); - _cameraXYZWhitePoint = vector( 3, 1.0 ); - _calibrateIllum = vector( 2, 1.0 ); - _baseExpo = 1.0; -} - -DNGIdt::DNGIdt( libraw_rawdata_t R ) -{ - _cameraCalibration1DNG = vector( 9, 1.0 ); - _cameraCalibration2DNG = vector( 9, 1.0 ); - _cameraToXYZMtx = vector( 9, 1.0 ); - _xyz2rgbMatrix1DNG = vector( 9, 1.0 ); - _xyz2rgbMatrix2DNG = vector( 9, 1.0 ); - _analogBalanceDNG = vector( 3, 1.0 ); - _neutralRGBDNG = vector( 3, 1.0 ); - _cameraXYZWhitePoint = vector( 3, 1.0 ); - _calibrateIllum = vector( 2, 1.0 ); - -#if LIBRAW_VERSION >= LIBRAW_MAKE_VERSION( 0, 20, 0 ) - _baseExpo = static_cast( R.color.dng_levels.baseline_exposure ); -#else - _baseExpo = static_cast( R.color.baseline_exposure ); -#endif - _calibrateIllum[0] = static_cast( R.color.dng_color[0].illuminant ); - _calibrateIllum[1] = static_cast( R.color.dng_color[1].illuminant ); - - FORI( 3 ) - { - _neutralRGBDNG[i] = 1.0 / static_cast( R.color.cam_mul[i] ); - } + _cameraToXYZMtx = vector( 9, 1.0 ); + _cameraXYZWhitePoint = vector( 3, 1.0 ); +} - FORIJ( 3, 3 ) - { - _xyz2rgbMatrix1DNG[i * 3 + j] = - static_cast( ( R.color.dng_color[0].colormatrix )[i][j] ); - _xyz2rgbMatrix2DNG[i * 3 + j] = - static_cast( ( R.color.dng_color[1].colormatrix )[i][j] ); - _cameraCalibration1DNG[i * 3 + j] = - static_cast( ( R.color.dng_color[0].calibration )[i][j] ); - _cameraCalibration2DNG[i * 3 + j] = - static_cast( ( R.color.dng_color[1].calibration )[i][j] ); - } +DNGIdt::DNGIdt( const Metadata &metadata ) // libraw_rawdata_t R ) +{ + _metadata = metadata; } DNGIdt::~DNGIdt() { - clearVM( _cameraCalibration1DNG ); - clearVM( _cameraCalibration2DNG ); + _metadata = Metadata(); + clearVM( _cameraToXYZMtx ); - clearVM( _xyz2rgbMatrix1DNG ); - clearVM( _xyz2rgbMatrix2DNG ); - clearVM( _analogBalanceDNG ); - clearVM( _neutralRGBDNG ); clearVM( _cameraXYZWhitePoint ); - clearVM( _calibrateIllum ); } double DNGIdt::ccttoMired( const double cct ) const @@ -1689,9 +1643,9 @@ vector DNGIdt::XYZtoCameraWeightedMatrix( double weight = std::max( 0.0, std::min( 1.0, ( mir1 - mir0 ) / ( mir1 - mir2 ) ) ); vector result = - subVectors( _xyz2rgbMatrix2DNG, _xyz2rgbMatrix1DNG ); + subVectors( _metadata.xyz2rgbMatrix2, _metadata.xyz2rgbMatrix1 ); scaleVector( result, weight ); - result = addVectors( result, _xyz2rgbMatrix1DNG ); + result = addVectors( result, _metadata.xyz2rgbMatrix1 ); return result; } @@ -1699,23 +1653,24 @@ vector DNGIdt::XYZtoCameraWeightedMatrix( vector DNGIdt::findXYZtoCameraMtx( const vector &neutralRGB ) const { + assert( _metadata.xyz2rgbMatrix2.size() > 0 ); - if ( _calibrateIllum.size() == 0 ) + if ( _metadata.xyz2rgbMatrix2.size() == 0 ) { - fprintf( stderr, " No calibration illuminants were found. \n " ); - return _xyz2rgbMatrix1DNG; + fprintf( stderr, " Only one calibration matrix found. \n " ); + return _metadata.xyz2rgbMatrix1; } if ( neutralRGB.size() == 0 ) { fprintf( stderr, " no neutral RGB values were found. \n " ); - return _xyz2rgbMatrix1DNG; + return _metadata.xyz2rgbMatrix1; } double cct1 = lightSourceToColorTemp( - static_cast( _calibrateIllum[0] ) ); + static_cast( _metadata.calibrationIlluminant1 ) ); double cct2 = lightSourceToColorTemp( - static_cast( _calibrateIllum[1] ) ); + static_cast( _metadata.calibrationIlluminant2 ) ); double mir1 = ccttoMired( cct1 ); double mir2 = ccttoMired( cct2 ); @@ -1737,7 +1692,7 @@ DNGIdt::findXYZtoCameraMtx( const vector &neutralRGB ) const lerror = mir - ccttoMired( XYZToColorTemperature( mulVector( invertV( XYZtoCameraWeightedMatrix( mir, mir1, mir2 ) ), - _neutralRGBDNG ) ) ); + _metadata.neutralRGB ) ) ); if ( std::fabs( lerror - 0.0 ) <= 1e-09 ) { @@ -1837,19 +1792,20 @@ vector DNGIdt::matrixRGBtoXYZ( const double chromaticities[][2] ) const void DNGIdt::getCameraXYZMtxAndWhitePoint() { - _cameraToXYZMtx = invertV( findXYZtoCameraMtx( _neutralRGBDNG ) ); + _cameraToXYZMtx = invertV( findXYZtoCameraMtx( _metadata.neutralRGB ) ); assert( std::fabs( sumVector( _cameraToXYZMtx ) - 0.0 ) > 1e-09 ); - scaleVector( _cameraToXYZMtx, std::pow( 2.0, _baseExpo ) ); + scaleVector( _cameraToXYZMtx, std::pow( 2.0, _metadata.baselineExposure ) ); - if ( _neutralRGBDNG.size() > 0 ) + if ( _metadata.neutralRGB.size() > 0 ) { - _cameraXYZWhitePoint = mulVector( _cameraToXYZMtx, _neutralRGBDNG ); + _cameraXYZWhitePoint = + mulVector( _cameraToXYZMtx, _metadata.neutralRGB ); } else { _cameraXYZWhitePoint = colorTemperatureToXYZ( - lightSourceToColorTemp( _calibrateIllum[0] ) ); + lightSourceToColorTemp( _metadata.calibrationIlluminant1 ) ); } scaleVector( _cameraXYZWhitePoint, 1.0 / _cameraXYZWhitePoint[1] ); diff --git a/src/rawtoaces_util/acesrender.cpp b/src/rawtoaces_util/acesrender.cpp index 069eb10b..c7a2a0ed 100644 --- a/src/rawtoaces_util/acesrender.cpp +++ b/src/rawtoaces_util/acesrender.cpp @@ -1736,9 +1736,52 @@ float *AcesRender::renderDNG() #define P _rawProcessor->imgdata.idata +#ifdef R +# undef R +#endif + +#define R _rawProcessor->imgdata.rawdata + assert( _image && P.dng_version ); - DNGIdt *dng = new DNGIdt( _rawProcessor->imgdata.rawdata ); + Metadata metadata; + metadata.neutralRGB.resize( 3 ); + metadata.xyz2rgbMatrix1.resize( 9 ); + metadata.xyz2rgbMatrix2.resize( 9 ); + metadata.cameraCalibration1.resize( 9 ); + metadata.cameraCalibration2.resize( 9 ); + +#if LIBRAW_VERSION >= LIBRAW_MAKE_VERSION( 0, 20, 0 ) + metadata.baselineExposure = + static_cast( R.color.dng_levels.baseline_exposure ); +#else + metadata.baselineExposure = + static_cast( R.color.baseline_exposure ); +#endif + metadata.calibrationIlluminant1 = + static_cast( R.color.dng_color[0].illuminant ); + metadata.calibrationIlluminant2 = + static_cast( R.color.dng_color[1].illuminant ); + + FORI( 3 ) + { + metadata.neutralRGB[i] = + 1.0 / static_cast( R.color.cam_mul[i] ); + } + + FORIJ( 3, 3 ) + { + metadata.xyz2rgbMatrix1[i * 3 + j] = + static_cast( ( R.color.dng_color[0].colormatrix )[i][j] ); + metadata.xyz2rgbMatrix2[i * 3 + j] = + static_cast( ( R.color.dng_color[1].colormatrix )[i][j] ); + metadata.cameraCalibration1[i * 3 + j] = + static_cast( ( R.color.dng_color[0].calibration )[i][j] ); + metadata.cameraCalibration2[i * 3 + j] = + static_cast( ( R.color.dng_color[1].calibration )[i][j] ); + } + + DNGIdt *dng = new DNGIdt( metadata ); _catm = dng->getDNGCATMatrix(); _idtm = dng->getDNGIDTMatrix(); diff --git a/src/rawtoaces_util2/CMakeLists.txt b/src/rawtoaces_util2/CMakeLists.txt new file mode 100644 index 00000000..1265985b --- /dev/null +++ b/src/rawtoaces_util2/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.5) +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) + +add_library ( rawtoaces_util2 ${DO_SHARED} + rawtoaces_util.cpp + ${PROJECT_SOURCE_DIR}/include/rawtoaces/rawtoaces_util.h +) + +set_property(TARGET rawtoaces_util2 PROPERTY CXX_STANDARD 17) + +if ( OIIO_FOUND ) + target_include_directories ( rawtoaces_util2 PRIVATE ${OIIO_INCLUDE_DIRS} ) + target_link_directories ( rawtoaces_util2 PUBLIC ${OIIO_LIBRARY_DIRS} ) + target_link_libraries ( rawtoaces_util2 + PUBLIC + ${OIIO_LIBRARIES} + ${OIIO_LDFLAGS_OTHER} + ) +endif() + +target_link_libraries ( rawtoaces_util2 + PUBLIC + ${RAWTOACESIDTLIB} + OpenImageIO::OpenImageIO +) + +set_target_properties( rawtoaces_util2 PROPERTIES + SOVERSION ${RAWTOACES_MAJOR_VERSION}.${RAWTOACES_MINOR_VERSION}.${RAWTOACES_PATCH_VERSION} + VERSION ${RAWTOACES_VERSION} ) + +install( + FILES + ${PROJECT_SOURCE_DIR}/include/rawtoaces/rawtoaces_util.h + DESTINATION include/rawtoaces +) + +install( TARGETS rawtoaces_util2 DESTINATION lib ) diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp new file mode 100644 index 00000000..7ce482f3 --- /dev/null +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -0,0 +1,958 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace rta +{ + +std::string findFile( const std::string &filename ) +{ + auto paths = pathsFinder(); + + for ( auto &path: paths.paths ) + { + std::string full_path = path + "/" + filename; + if ( std::filesystem::exists( full_path ) ) + return full_path; + } + return ""; +} + +std::vector collectDataFiles( const std::string &type ) +{ + std::vector result; + + auto paths = pathsFinder(); + + for ( auto &path: paths.paths ) + { + auto it = std::filesystem::directory_iterator( path + "/" + type ); + + for ( auto filename2: it ) + { + auto p = filename2.path(); + if ( filename2.path().extension() == ".json" ) + { + result.push_back( filename2.path().string() ); + } + } + } + return result; +} + +ImageConverter::ImageConverter() +{ + initArgParse(); +} + +const char *HelpString = + "Rawtoaces converts raw image files from a digital camera to " + "the Academy Colour Encoding System (ACES) compliant images.\n" + "The process consists of two parts:\n" + "- the colour values get converted from the camera native colour " + "space to the ACES AP0 (see \"SMPTE ST 2065-1\"), and \n" + "- the image file gets converted from the camera native raw " + "file format to the ACES Image Container file format " + "(see \"SMPTE ST 2065-4\").\n" + "\n" + "Rawtoaces supports the following white-balancing modes:\n" + "- \"metadata\" uses the white-balancing coefficients from the raw " + "image file, provided by the camera.\n" + "- \"illuminant\" performs white balancing to the illuminant, " + "provided in the \"--illuminant\" parameter. The list of the " + "supported illuminants can be seen using the " + "\"--list-illuminants\" parameter. This mode requires spectral " + "sensitivity data for the camera model the image comes from. " + "The list of cameras such data is available for, can be " + "seen using the \"--list-cameras\" parameter.\n" + "- \"box\" performs white-balancing to make the given region of " + "the image appear neutral gray. The box position (origin and size) " + "can be specified using the \"--wb-box\" parameter. In case no such " + "parameter provided, the whole image is used for white-balancing.\n" + "- \"custom\" uses the custom white balancing coefficients " + "provided using the -\"custom-wb\" parameter.\n" + "\n" + "Rawtoaces supports the following methods of color matrix " + "computation:\n" + "- \"spectral\" uses the camera sensor's spectral sensitivity data " + "to compute the optimal matrix. This mode requires spectral " + "sensitivity data for the camera model the image comes from. " + "The list of cameras such data is available for, can be " + "seen using the \"--list-cameras\" parameter.\n" + "- \"metadata\" uses the matrix (matrices) contained in the raw " + "image file metadata. This mode works best with the images using " + "the DNG format, as the DNG standard mandates the presense of " + "such matrices.\n" + "- \"Adobe\" uses the Adobe coefficients provided by LibRaw. \n" + "- \"custom\" uses a user-provided color conversion matrix. " + "A matrix can be specified using the \"--custom-mat\" parameter.\n" + "\n" + "The paths rawtoaces uses to search for the spectral sensitivity " + "data can be specified in the AMPAS_DATA_PATH environment " + "variable.\n"; + +const char *UsageString = + "\n" + " rawtoaces --wb-method METHOD --mat-method METHOD [PARAMS] " + "path/to/dir/or/file ...\n" + "Examples: \n" + " rawtoaces --wb-method metadata --mat-method metadata raw_file.cr3\n" + " rawtoaces --wb-method illuminant --illuminant 3200K --mat-method " + "spectral raw_file.cr3\n"; + +void ImageConverter::initArgParse() +{ + _argParse.intro( HelpString ).usage( UsageString ); + _argParse.print_defaults( true ); + _argParse.add_help( true ); + _argParse.add_version( "VERSION NUMBER" ); + + _argParse.arg( "filename" ).action( OIIO::ArgParse::append() ).hidden(); + + _argParse.arg( "--wb-method" ) + .help( + "White balance method. Supported options: metadata, illuminant, " + "box, custom." ) + .metavar( "STR" ) + .defaultval( "metadata" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--mat-method" ) + .help( + "IDT matrix calculation method. Supported options: spectral, " + "metadata, Adobe, custom." ) + .metavar( "STR" ) + .defaultval( "spectral" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--illuminant" ) + .help( "Illuminant for white balancing. (default = D55)" ) + .metavar( "STR" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--wb-box" ) + .help( + "Box to use for white balancing. (default = (0,0,0,0) - full " + "image)" ) + .nargs( 4 ) + .metavar( "X Y W H" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--custom-wb" ) + .help( "Custom white balance multipliers." ) + .nargs( 4 ) + .metavar( "R G B G" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--custom-mat" ) + .help( "Custom camera RGB to XYZ matrix." ) + .nargs( 9 ) + .metavar( "Rr Rg Rb Gr Gg Gb Br Bg Bb" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--headroom" ) + .help( "Highlight headroom factor." ) + .metavar( "VAL" ) + .defaultval( 6.0f ) + .action( OIIO::ArgParse::store() ); + + _argParse.separator( "Raw conversion options:" ); + + _argParse.arg( "--no-auto-bright" ) + .help( "Disable automatic exposure adjustment." ) + .action( OIIO::ArgParse::store_true() ); + + _argParse.arg( "--adjust-maximum-threshold" ) + .help( + "Automatically lower the linearity threshold provided in the " + "metadata by this scaling factor." ) + .metavar( "VAL" ) + .defaultval( 0.75f ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--black-level" ) + .help( "If >= 0, override the black level." ) + .metavar( "VAL" ) + .defaultval( -1 ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--saturation-level" ) + .help( + "If not 0, override the level which appears to be saturated " + "after normalisation." ) + .metavar( "VAL" ) + .defaultval( 0 ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--chromatic-aberration" ) + .help( + "Red and blue scale factors for chromatic aberration correction. " + "The value of 1 means no correction." ) + .metavar( "R B" ) + .nargs( 2 ) + .defaultval( 1.0f ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--half-size" ) + .help( "If present, decode image at half size resolution." ) + .action( OIIO::ArgParse::store_true() ); + + _argParse.arg( "--highlight-mode" ) + .help( "0 = clip, 1 = unclip, 2 = blend, 3..9 = rebuild." ) + .metavar( "VAL" ) + .defaultval( 0 ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--cropbox" ) + .help( + "Apply custom crop. If not present, the default crop is applied, " + "which should match the crop of the in-camera JPEG." ) + .nargs( 4 ) + .metavar( "X Y W H" ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--flip" ) + .help( + "If not 0, override the orientation specified in the metadata. " + "1..8 correspond to EXIF orientation codes " + "(3 = 180 deg, 6 = 90 deg CCW, 8 = 90 deg CW.)" ) + .metavar( "VAL" ) + .defaultval( 0 ) + .action( OIIO::ArgParse::store() ); + + _argParse.arg( "--denoise_threshold" ) + .help( "Wavelet denoising threshold" ) + .metavar( "VAL" ) + .defaultval( 0 ) + .action( OIIO::ArgParse::store() ); + + _argParse.separator( "Benchmarking and debugging:" ); + + _argParse.arg( "--list-cameras" ) + .help( "Shows the list of cameras supported in spectral mode." ) + .action( OIIO::ArgParse::store_true() ); + + _argParse.arg( "--list-illuminants" ) + .help( "Shows the list of illuminants supported in spectral mode." ) + .action( OIIO::ArgParse::store_true() ); + + _argParse.arg( "--verbose" ) + .help( "Verbosity level. 0 = off, 1 = info, 2 = debug." ) + .defaultval( 0 ) + .action( OIIO::ArgParse::store() ); +} + +OIIO::ArgParse &ImageConverter::argParse() +{ + return _argParse; +} + +OIIO::ImageBuf &ImageConverter::imageBuffer() +{ + return _imageBuffer; +} + +template +bool check_param( + const std::string &mode_name, + const std::string &mode_value, + const std::string ¶m_name, + const std::vector ¶m_value, + size_t correct_size, + const std::string &default_value_message, + bool is_correct_mode, + F1 on_success, + F2 on_failure ) +{ + if ( is_correct_mode ) + { + if ( param_value.size() == correct_size ) + { + on_success(); + return true; + } + else + { + if ( ( param_value.size() == 0 ) || + ( ( param_value.size() == 1 ) && ( param_value[0] == 0 ) ) ) + { + std::cerr << "Warning: " << mode_name << " was set to \"" + << mode_value << "\", but no \"--" << param_name + << "\" parameter provided. " << default_value_message + << std::endl; + + on_failure(); + return false; + } + + if ( param_value.size() != correct_size ) + { + std::cerr << "Warning: The parameter \"" << param_name + << "\" must have " << correct_size << " values. " + << default_value_message << std::endl; + + on_failure(); + return false; + } + } + } + else + { + if ( ( param_value.size() > 1 ) || + ( ( param_value.size() == 1 ) && ( param_value[0] != 0 ) ) ) + { + std::cerr << "Warning: the \"--" << param_name + << "\" parameter provided, but the " << mode_name + << " is different from \"" << mode_value << "\". " + << default_value_message << std::endl; + + on_failure(); + return false; + } + else + { + return true; + } + } +} + +bool ImageConverter::parse( int argc, const char *argv[] ) +{ + if ( _argParse.parse_args( argc, argv ) ) + { + // report error? + return false; + } + + if ( _argParse["list-cameras"].get() ) + { + std::cout + << "Spectral sensitivity data are available for the following cameras:" + << std::endl; + + Idt idt; + auto paths = collectDataFiles( "camera" ); + std::vector cameras; + for ( auto path: paths ) + { + Spst spst; + if ( spst.loadSpst( path, nullptr, nullptr ) ) + { + cameras.push_back( + std::string( spst.getBrand() ) + " " + spst.getModel() ); + } + } + + std::sort( cameras.begin(), cameras.end() ); + + for ( auto s: cameras ) + std::cout << "- " << s << std::endl; + std::cout << std::endl; + exit( 0 ); + } + + if ( _argParse["list-illuminants"].get() ) + { + std::cout << "The following illuminants are supported:" << std::endl; + std::cout << "- The standard illuminant series D (e.g., D60, D6025)" + << std::endl; + std::cout << "- Black-body radiation (e.g., 3200K)" << std::endl; + + Idt idt; + auto paths = collectDataFiles( "illuminant" ); + std::vector illuminants; + for ( auto path: paths ) + { + Illum illum; + if ( illum.readSPD( path, "na" ) ) + { + illuminants.push_back( illum.getIllumType() ); + } + } + + std::sort( illuminants.begin(), illuminants.end() ); + + for ( auto s: illuminants ) + std::cout << "- " << s << std::endl; + std::cout << std::endl; + exit( 0 ); + } + + verbosity = _argParse["verbose"].get(); + + std::string wb_method = _argParse["wb-method"].get(); + + if ( wb_method == "metadata" ) + { + wbMethod = WBMethod::Metadata; + } + else if ( wb_method == "illuminant" ) + { + wbMethod = WBMethod::Illuminant; + } + else if ( wb_method == "box" ) + { + wbMethod = WBMethod::Box; + } + else if ( wb_method == "custom" ) + { + wbMethod = WBMethod::Custom; + } + else + { + std::cerr << std::endl + << "Unsupported white balancing method: \"" << wb_method + << "\"." << std::endl; + + return false; + } + + std::string mat_method = _argParse["mat-method"].get(); + + if ( mat_method == "spectral" ) + { + matrixMethod = MatrixMethod::Spectral; + } + else if ( mat_method == "metadata" ) + { + matrixMethod = MatrixMethod::Metadata; + } + else if ( mat_method == "Adobe" ) + { + matrixMethod = MatrixMethod::Adobe; + } + else if ( mat_method == "custom" ) + { + matrixMethod = MatrixMethod::Custom; + } + else + { + std::cerr << std::endl + << "Unsupported matrix method: \"" << mat_method << "\"." + << std::endl; + + return false; + } + + headroom = _argParse["headroom"].get(); + + std::string illum = _argParse["illuminant"].get(); + + if ( wbMethod == WBMethod::Illuminant ) + { + if ( illum.size() == 0 ) + { + std::cerr << "Warning: the white balancing method was set to " + << "\"illuminant\", but no \"--illuminant\" parameter " + << "provided. " << illuminant << " will be used." + << std::endl; + } + } + else + { + if ( illum.size() != 0 ) + { + std::cerr << "Warning: the \"--illuminant\" parameter provided " + << "but the white balancing mode different from " + << "\"illuminant\" " + << "requested. The custom illuminant will be ignored." + << std::endl; + } + } + + auto box = _argParse["wb-box"].as_vec(); + check_param( + "white balancing mode", + "box", + "wb-box", + box, + 4, + "The box will be ignored.", + wbMethod == WBMethod::Box, + [&]() { + for ( int i = 0; i < 4; i++ ) + wbBox[i] = box[i]; + }, + [&]() { + for ( int i = 0; i < 4; i++ ) + wbBox[i] = 0; + } ); + + auto custom_wb = _argParse["custom-wb"].as_vec(); + check_param( + "white balancing mode", + "custom", + "custom-wb", + custom_wb, + 4, + "The scalers will be ignored. The default values of (1, 1, 1, 1) will be used", + wbMethod == WBMethod::Custom, + [&]() { + for ( int i = 0; i < 4; i++ ) + customWB[i] = custom_wb[i]; + }, + [&]() { + for ( int i = 0; i < 4; i++ ) + customWB[i] = 1.0; + } ); + + auto custom_mat = _argParse["custom-mat"].as_vec(); + check_param( + "matrix mode", + "custom", + "custom-mat", + custom_mat, + 9, + "Identity matrix will be used", + matrixMethod == MatrixMethod::Custom, + [&]() { + for ( int i = 0; i < 3; i++ ) + for ( int j = 0; j < 3; j++ ) + customMatrix[i][j] = custom_mat[i * 3 + j]; + }, + [&]() { + for ( int i = 0; i < 3; i++ ) + for ( int j = 0; j < 3; j++ ) + customMatrix[i][j] = i == j ? 1.0 : 0.0; + } ); + + auto crop = _argParse["cropbox"].as_vec(); + if ( crop.size() == 4 ) + { + for ( size_t i = 0; i < 4; i++ ) + cropbox[i] = crop[i]; + } + + no_auto_bright = _argParse["no-auto-bright"].get(); + adjust_maximum_threshold = _argParse["adjust-maximum-threshold"].get(); + black_level = _argParse["black-level"].get(); + saturation_level = _argParse["saturation-level"].get(); + half_size = _argParse["half-size"].get(); + highlight_mode = _argParse["highlight-mode"].get(); + flip = _argParse["flip"].get(); + + return true; +} + +bool ImageConverter::configure( const std::string &input_filename ) +{ + _configFilename = input_filename; + + _inputHint = OIIO::ImageSpec(); + + _inputHint["raw:ColorSpace"] = "XYZ"; + _inputHint["raw:use_camera_wb"] = 0; + _inputHint["raw:use_auto_wb"] = 0; + + _inputHint["raw:auto_bright"] = no_auto_bright ? 0 : 1; + _inputHint["raw:adjust_maximum_thr"] = adjust_maximum_threshold; + _inputHint["raw:user_black"] = black_level; + _inputHint["raw:user_sat"] = saturation_level; + _inputHint["raw:half_size"] = (int)half_size; + _inputHint["raw:flip"] = flip; + _inputHint["raw:HighlightMode"] = highlight_mode; + + if ( cropbox[2] != 0 && cropbox[3] != 0 ) + { + _inputHint.attribute( + "raw:cropbox", OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), cropbox ); + } + + auto imageInput = OIIO::ImageInput::create( "raw", false, &_inputHint ); + bool result = imageInput->open( input_filename, _inputFull, _inputHint ); + if ( !result ) + { + return false; + } + + _is_DNG = _inputFull.extra_attribs.find( "raw:dng:version" )->get_int() > 0; + + switch ( wbMethod ) + { + case WBMethod::Metadata: { + float user_mul[4]; + + for ( int i = 0; i < 4; i++ ) + { + user_mul[i] = _inputFull.find_attribute( "raw:cam_mul" ) + ->get_float_indexed( i ) / + 256.0; + } + + _inputHint.attribute( + "raw:user_mul", + OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), + user_mul ); + break; + } + + case WBMethod::Illuminant: { + std::string lower_illuminant( illuminant ); + std::transform( + lower_illuminant.begin(), + lower_illuminant.end(), + lower_illuminant.begin(), + []( unsigned char c ) { return std::tolower( c ); } ); + + if ( !isValidCT( lower_illuminant ) ) + { + std::cerr << "Unrecognised illuminant \'" << illuminant << "\'" + << std::endl; + return false; + } + + break; + } + case WBMethod::Box: + + if ( wbBox[2] == 0 || wbBox[3] == 0 ) + { + // Empty box, use whole image. + _inputHint["raw:use_auto_wb"] = 1; + } + else + { + int32_t box[4]; + for ( int i = 0; i < 4; i++ ) + { + box[i] = wbBox[i]; + } + _inputHint.attribute( + "raw:greybox", + OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), + box ); + } + break; + + case WBMethod::Custom: + _inputHint.attribute( + "raw:user_mul", + OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), + customWB ); + break; + + default: break; + } + + switch ( matrixMethod ) + { + case MatrixMethod::Spectral: + _inputHint["raw:ColorSpace"] = "raw"; + _inputHint["raw:use_camera_matrix"] = 0; + break; + case MatrixMethod::Metadata: + _inputHint["raw:use_camera_matrix"] = _is_DNG ? 1 : 3; + break; + case MatrixMethod::Adobe: + _inputHint["raw:use_camera_matrix"] = 1; + break; + case MatrixMethod::Custom: + _inputHint["raw:use_camera_matrix"] = 0; + _inputHint["raw:ColorSpace"] = "raw"; + + _IDT_matrix.resize( 3 ); + for ( int i = 0; i < 3; i++ ) + { + _IDT_matrix[i].resize( 3 ); + for ( int j = 0; j < 3; j++ ) + { + _IDT_matrix[i][j] = customMatrix[i][j]; + } + } + + break; + default: break; + } + + bool spectral_white_balance = wbMethod == WBMethod::Illuminant; + bool spectral_matrix = matrixMethod == MatrixMethod::Spectral; + + if ( spectral_white_balance || spectral_matrix ) + { + float pre_mul[4]; + + for ( int i = 0; i < 4; i++ ) + { + pre_mul[i] = _inputFull.find_attribute( "raw:pre_mul" ) + ->get_float_indexed( i ); + } + + _cameraMake = _inputFull["Make"]; + _cameraModel = _inputFull["Model"]; + + prepareIDT_spectral( spectral_white_balance, spectral_matrix ); + + if ( spectral_white_balance ) + { + float user_mul[4]; + + for ( int i = 0; i < _WB_mults.size(); i++ ) + { + user_mul[i] = _WB_mults[i]; + } + if ( _WB_mults.size() == 3 ) + user_mul[3] = _WB_mults[1]; + + _inputHint.attribute( + "raw:user_mul", + OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), + user_mul ); + } + } + + if ( matrixMethod == MatrixMethod::Metadata || + matrixMethod == MatrixMethod::Adobe ) + { + if ( _is_DNG ) + { + _inputHint["raw:use_camera_matrix"] = 1; + _inputHint["raw:use_camera_wb"] = 1; + + prepareIDT_DNG(); + } + else + { + prepareIDT_nonDNG(); + } + } + + return true; +} + +bool ImageConverter::load( const std::string &input_filename ) +{ + if ( _configFilename != input_filename ) + { + auto imageInput = OIIO::ImageInput::create( "raw", false, &_inputHint ); + imageInput->open( input_filename, _inputFull, _inputHint ); + } + + _imageBuffer = + OIIO::ImageBuf( input_filename, 0, 0, nullptr, &_inputHint, nullptr ); + bool result = _imageBuffer.init_spec( input_filename, 0, 0 ); + if ( result ) + { + auto &spec = _imageBuffer.spec(); + auto channels = spec.nchannels; + result = + _imageBuffer.read( 0, 0, 0, channels, true, OIIO::TypeDesc::FLOAT ); + } + return result; +} + +void ImageConverter::applyMatrix( + const std::vector> &matrix ) +{ + float M[4][4]; + + size_t n = matrix.size(); + + if ( n ) + { + size_t m = matrix[0].size(); + + for ( size_t i = 0; i < n; i++ ) + { + for ( size_t j = 0; j < m; j++ ) + { + M[j][i] = matrix[i][j]; + } + + for ( size_t j = m; j < 4; j++ ) + M[j][i] = 0; + } + + for ( size_t i = n; i < 4; i++ ) + { + for ( size_t j = 0; j < m; j++ ) + M[j][i] = 0; + for ( size_t j = m; j < 4; j++ ) + M[j][i] = 1; + } + } + + _imageBuffer = OIIO::ImageBufAlgo::colormatrixtransform( _imageBuffer, M ); +} + +bool ImageConverter::process() +{ + if ( _IDT_matrix.size() ) + { + applyMatrix( _IDT_matrix ); + } + + if ( _CAT_matrix.size() ) + { + applyMatrix( _CAT_matrix ); + + _imageBuffer = OIIO::ImageBufAlgo::colormatrixtransform( + _imageBuffer, XYZ_acesrgb_transposed_4 ); + } + + _imageBuffer = OIIO::ImageBufAlgo::mul( _imageBuffer, headroom ); + return true; +} + +bool ImageConverter::save( const std::string &output_filename ) +{ + const float chromaticities[] = { 0.7347, 0.2653, 0, 1, + 0.0001, -0.077, 0.32168, 0.33767 }; + + OIIO::ImageSpec imageSpec = _inputFull; + imageSpec.set_format( OIIO::TypeDesc::HALF ); + imageSpec["acesImageContainerFlag"] = 1; + imageSpec["compression"] = "none"; + imageSpec.attribute( + "chromaticities", + OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 8 ), + chromaticities ); + + auto imageOutput = OIIO::ImageOutput::create( "exr" ); + bool result = imageOutput->open( output_filename, imageSpec ); + result = _imageBuffer.write( imageOutput.get() ); + return result; +} + +void ImageConverter::prepareIDT_spectral( + bool calc_white_balance, bool calc_matrix ) +{ + std::string lower_illuminant( illuminant ); + + if ( lower_illuminant.length() == 0 ) + lower_illuminant = "na"; + else + { + std::transform( + lower_illuminant.begin(), + lower_illuminant.end(), + lower_illuminant.begin(), + []( unsigned char c ) { return std::tolower( c ); } ); + } + + Idt idt; + + auto illum_paths = collectDataFiles( "illuminant" ); + int res = idt.loadIlluminant( illum_paths, lower_illuminant ); + + bool found_camera = false; + auto camera_paths = collectDataFiles( "camera" ); + + for ( auto &path: camera_paths ) + { + if ( idt.loadCameraSpst( + path, _cameraMake.c_str(), _cameraModel.c_str() ) ) + { + found_camera = true; + break; + } + } + + auto training = findFile( "training/training_spectral.json" ); + if ( training.length() ) + { + idt.loadTrainingData( training ); + } + + auto cmf = findFile( "cmf/cmf_1931.json" ); + if ( cmf.length() ) + { + idt.loadCMF( cmf ); + } + + if ( lower_illuminant != "na" ) + { + idt.chooseIllumType( lower_illuminant.c_str(), headroom ); + } + else + { + std::vector cam_mul( 3 ); + for ( int i = 0; i < 3; i++ ) + cam_mul[i] = _inputFull.find_attribute( "raw:cam_mul" ) + ->get_float_indexed( i ); + idt.chooseIllumSrc( cam_mul, headroom ); + } + + if ( idt.calIDT() ) + { + if ( calc_white_balance ) + { + _WB_mults = idt.getWB(); + } + + if ( calc_matrix ) + { + _IDT_matrix = idt.getIDT(); + _CAT_matrix.resize( 0 ); + } + } +} + +void ImageConverter::prepareIDT_DNG() +{ + Metadata metadata; + metadata.neutralRGB.resize( 3 ); + metadata.xyz2rgbMatrix1.resize( 9 ); + metadata.xyz2rgbMatrix2.resize( 9 ); + metadata.cameraCalibration1.resize( 9 ); + metadata.cameraCalibration2.resize( 9 ); + + metadata.baselineExposure = + _inputFull.get_float_attribute( "raw:dng:baseline_exposure" ); + metadata.calibrationIlluminant1 = + _inputFull.get_int_attribute( "raw:dng:calibration_illuminant1" ); + metadata.calibrationIlluminant2 = + _inputFull.get_int_attribute( "raw:dng:calibration_illuminant2" ); + + for ( int i = 0; i < 3; i++ ) + { + metadata.neutralRGB[i] = + 1.0 / + _inputFull.find_attribute( "raw:cam_mul" )->get_float_indexed( i ); + + for ( int j = 0; j < 3; j++ ) + { + metadata.xyz2rgbMatrix1[i * 3 + j] = + _inputFull.find_attribute( "raw:dng:color_matrix1" ) + ->get_float_indexed( i * 3 + j ); + metadata.xyz2rgbMatrix2[i * 3 + j] = + _inputFull.find_attribute( "raw:dng:color_matrix2" ) + ->get_float_indexed( i * 3 + j ); + metadata.cameraCalibration1[i * 3 + j] = + _inputFull.find_attribute( "raw:dng:camera_calibration1" ) + ->get_float_indexed( i * 4 + j ); + metadata.cameraCalibration2[i * 3 + j] = + _inputFull.find_attribute( "raw:dng:camera_calibration2" ) + ->get_float_indexed( i * 4 + j ); + } + } + + DNGIdt *dng = new DNGIdt( metadata ); + + _IDT_matrix = dng->getDNGIDTMatrix(); + + // Do not apply CAT for DNG + _CAT_matrix.resize( 0 ); + // _CAT_matrix = dng->getDNGCATMatrix(); +} + +void ImageConverter::prepareIDT_nonDNG() +{ + _IDT_matrix.resize( 0 ); + + vector dIV( d65, d65 + 3 ); + vector dOV( d60, d60 + 3 ); + _CAT_matrix = getCAT( dIV, dOV ); +} + +} // namespace rta diff --git a/unittest/testDNGIdt.cpp b/unittest/testDNGIdt.cpp index d8858905..b29473bb 100644 --- a/unittest/testDNGIdt.cpp +++ b/unittest/testDNGIdt.cpp @@ -88,9 +88,57 @@ BOOST_AUTO_TEST_CASE( TestIDT_RobertsonLength ) BOOST_CHECK_CLOSE( rLength, 0.060234937, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_LightSourceToColorTemp ) +DNGIdt *openFile( std::string path, LibRaw &rawProcessor ) { + boost::filesystem::path pathToRaw = boost::filesystem::absolute( + "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); + int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); + ret = rawProcessor.unpack(); +#define R rawProcessor.imgdata.rawdata + + Metadata metadata; + metadata.neutralRGB.resize( 3 ); + metadata.xyz2rgbMatrix1.resize( 9 ); + metadata.xyz2rgbMatrix2.resize( 9 ); + metadata.cameraCalibration1.resize( 9 ); + metadata.cameraCalibration2.resize( 9 ); + +#if LIBRAW_VERSION >= LIBRAW_MAKE_VERSION( 0, 20, 0 ) + metadata.baselineExposure = + static_cast( R.color.dng_levels.baseline_exposure ); +#else + metadata.baselineExposure = + static_cast( R.color.baseline_exposure ); +#endif + metadata.calibrationIlluminant1 = + static_cast( R.color.dng_color[0].illuminant ); + metadata.calibrationIlluminant2 = + static_cast( R.color.dng_color[1].illuminant ); + + FORI( 3 ) + { + metadata.neutralRGB[i] = + 1.0 / static_cast( R.color.cam_mul[i] ); + } + + FORIJ( 3, 3 ) + { + metadata.xyz2rgbMatrix1[i * 3 + j] = + static_cast( ( R.color.dng_color[0].colormatrix )[i][j] ); + metadata.xyz2rgbMatrix2[i * 3 + j] = + static_cast( ( R.color.dng_color[1].colormatrix )[i][j] ); + metadata.cameraCalibration1[i * 3 + j] = + static_cast( ( R.color.dng_color[0].calibration )[i][j] ); + metadata.cameraCalibration2[i * 3 + j] = + static_cast( ( R.color.dng_color[1].calibration )[i][j] ); + } + + return new DNGIdt( metadata ); +} + +BOOST_AUTO_TEST_CASE( TestIDT_LightSourceToColorTemp ) +{ DNGIdt *di = new DNGIdt(); unsigned short tag = 17; double ct = di->lightSourceToColorTemp( tag ); @@ -101,13 +149,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_LightSourceToColorTemp ) BOOST_AUTO_TEST_CASE( TestIDT_XYZToColorTemperature ) { - LibRaw rawProcessor; - boost::filesystem::path pathToRaw = boost::filesystem::absolute( - "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); - int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); - ret = rawProcessor.unpack(); - - DNGIdt *di = new DNGIdt( rawProcessor.imgdata.rawdata ); + LibRaw rawProcessor; + DNGIdt *di = openFile( + "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng", + rawProcessor ); double XYZ[3] = { 0.9731171910, 1.0174927152, 0.9498565880 }; vector XYZVector( XYZ, XYZ + 3 ); double cct = di->XYZToColorTemperature( XYZVector ); @@ -120,13 +165,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_XYZToColorTemperature ) BOOST_AUTO_TEST_CASE( TestIDT_XYZtoCameraWeightedMatrix ) { - LibRaw rawProcessor; - boost::filesystem::path pathToRaw = boost::filesystem::absolute( - "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); - int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); - ret = rawProcessor.unpack(); + LibRaw rawProcessor; + DNGIdt *di = openFile( + "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng", + rawProcessor ); - DNGIdt *di = new DNGIdt( rawProcessor.imgdata.rawdata ); double mirs[3] = { 158.8461538462, 350.1400560224, 153.8461538462 }; double matrix[9] = { 1.0165710542, -0.2791973987, -0.0801820653, -0.4881171650, 1.3469051835, 0.1100471308, @@ -142,13 +185,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_XYZtoCameraWeightedMatrix ) BOOST_AUTO_TEST_CASE( TestIDT_FindXYZtoCameraMtx ) { - LibRaw rawProcessor; - boost::filesystem::path pathToRaw = boost::filesystem::absolute( - "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); - int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); - ret = rawProcessor.unpack(); + LibRaw rawProcessor; + DNGIdt *di = openFile( + "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng", + rawProcessor ); - DNGIdt *di = new DNGIdt( rawProcessor.imgdata.rawdata ); double neutralRGB[3] = { 0.6289999865, 1.0000000000, 0.7904000305 }; double matrix[9] = { 1.0616656923, -0.3124143737, -0.0661770211, -0.4772957633, 1.3614785395, 0.1001599918, @@ -192,17 +233,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_MatrixRGBtoXYZ ) BOOST_AUTO_TEST_CASE( TestIDT_GetDNGCATMatrix ) { - - LibRaw rawProcessor; - boost::filesystem::path pathToRaw = boost::filesystem::absolute( - "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); - int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); - ret = rawProcessor.unpack(); - - DNGIdt *di = new DNGIdt( rawProcessor.imgdata.rawdata ); - double matrix[3][3] = { { 0.9907763427, -0.0022862289, 0.0209908807 }, - { -0.0017882434, 0.9941341374, 0.0083008330 }, - { 0.0003777587, 0.0015609315, 1.1063201101 } }; + LibRaw rawProcessor; + DNGIdt *di = openFile( + "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng", + rawProcessor ); + + double matrix[3][3] = { { 0.9907763427, -0.0022862289, 0.0209908807 }, + { -0.0017882434, 0.9941341374, 0.0083008330 }, + { 0.0003777587, 0.0015609315, 1.1063201101 } }; vector> result = di->getDNGCATMatrix(); rawProcessor.recycle(); @@ -214,17 +252,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_GetDNGCATMatrix ) BOOST_AUTO_TEST_CASE( TestIDT_GetDNGIDTMatrix ) { - - LibRaw rawProcessor; - boost::filesystem::path pathToRaw = boost::filesystem::absolute( - "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); - int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); - ret = rawProcessor.unpack(); - - DNGIdt *di = new DNGIdt( rawProcessor.imgdata.rawdata ); - double matrix[3][3] = { { 1.0536466144, 0.0039044182, 0.0049084502 }, - { -0.4899562165, 1.3614787986, 0.1020844728 }, - { -0.0024498461, 0.0060497128, 1.0139159537 } }; + LibRaw rawProcessor; + DNGIdt *di = openFile( + "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng", + rawProcessor ); + + double matrix[3][3] = { { 1.0536466144, 0.0039044182, 0.0049084502 }, + { -0.4899562165, 1.3614787986, 0.1020844728 }, + { -0.0024498461, 0.0060497128, 1.0139159537 } }; vector> result = di->getDNGIDTMatrix(); rawProcessor.recycle(); From 06e616c28cff0d98b6b9fe790b38f85e101f34f5 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Fri, 7 Feb 2025 08:31:13 +1300 Subject: [PATCH 05/20] removed more unnecessary stuff from public headers Signed-off-by: Anton Dukhovnikov --- config/RAWTOACESConfig.cmake.in | 4 ++-- include/rawtoaces/acesrender.h | 6 +++--- include/rawtoaces/define.h | 7 ++++--- include/rawtoaces/rta.h | 12 +++++------- src/rawtoaces_idt/CMakeLists.txt | 1 - src/rawtoaces_util/CMakeLists.txt | 1 + src/rawtoaces_util2/rawtoaces_util.cpp | 14 ++++++-------- unittest/testDNGIdt.cpp | 2 ++ 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/config/RAWTOACESConfig.cmake.in b/config/RAWTOACESConfig.cmake.in index 5df519eb..abcb898f 100644 --- a/config/RAWTOACESConfig.cmake.in +++ b/config/RAWTOACESConfig.cmake.in @@ -12,10 +12,10 @@ if( EXISTS "${RAWTOACES_CMAKE_DIR}/CMakeCache.txt" ) include( "${RAWTOACES_CMAKE_DIR}/RAWTOACESBuildTreeSettings.cmake" ) else() set( RAWTOACES_INCLUDE_DIRS "${RAWTOACES_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@" ) -endif +endif() # setup our library dependencies (i.e. ilmbase) -include( "${RAWTOACES_CMAKE_DIR}/RAWTOACESLibraryDepends.cmake" ) +# include( "${RAWTOACES_CMAKE_DIR}/RAWTOACESLibraryDepends.cmake" ) set( RAWTOACES_LIBRARIES RAWTOACES ) set( RAWTOACES_EXECUTABLE rawtoaces ) diff --git a/include/rawtoaces/acesrender.h b/include/rawtoaces/acesrender.h index 2d8d98ce..823991f4 100644 --- a/include/rawtoaces/acesrender.h +++ b/include/rawtoaces/acesrender.h @@ -56,7 +56,7 @@ #define _ACESRENDER_h__ #include - +#include #include using namespace rta; @@ -67,8 +67,8 @@ void usage( const char *prog ); class LibRawAces : virtual public LibRaw { public: - LibRawAces(){}; - ~LibRawAces(){}; + LibRawAces() {}; + ~LibRawAces() {}; void show() { printf( "I am here with LibRawAces.\n" ); } }; diff --git a/include/rawtoaces/define.h b/include/rawtoaces/define.h index 77794c14..34c8d92c 100644 --- a/include/rawtoaces/define.h +++ b/include/rawtoaces/define.h @@ -55,8 +55,9 @@ #define _DEFINE_h__ #include +#include #include -#include +#include #ifndef WIN32 # include @@ -357,9 +358,9 @@ inline vector openDir( string path = "." ) { vector paths; - for ( auto &i: boost::filesystem::directory_iterator( path ) ) + for ( auto &i: filesystem::directory_iterator( path ) ) { - if ( i.status().type() != boost::filesystem::file_type::directory_file ) + if ( i.status().type() != filesystem::file_type::directory ) paths.push_back( i.path().string() ); } diff --git a/include/rawtoaces/rta.h b/include/rawtoaces/rta.h index 25b42375..0463904c 100644 --- a/include/rawtoaces/rta.h +++ b/include/rawtoaces/rta.h @@ -58,9 +58,7 @@ #include "define.h" #include -#include -#include "mathOps.h" #include "metadata.h" using namespace std; @@ -69,8 +67,8 @@ namespace rta { struct CIEXYZ { - CIEXYZ(){}; - CIEXYZ( double X, double Y, double Z ) : _Xt( X ), _Yt( Y ), _Zt( Z ){}; + CIEXYZ() {}; + CIEXYZ( double X, double Y, double Z ) : _Xt( X ), _Yt( Y ), _Zt( Z ) {}; double _Xt; double _Yt; double _Zt; @@ -92,9 +90,9 @@ struct CMF struct RGBSen { - RGBSen(){}; + RGBSen() {}; RGBSen( double R, double G, double B ) - : _RSen( R ), _GSen( G ), _BSen( B ){}; + : _RSen( R ), _GSen( G ), _BSen( B ) {}; double _RSen; double _GSen; @@ -145,7 +143,7 @@ class Spst : _brand( brand ) , _model( model ) , _increment( increment ) - , _rgbsen( rgbsen ){}; + , _rgbsen( rgbsen ) {}; ~Spst(); void setBrand( const char *brand ); diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index 62f56dfa..222f93c2 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -15,7 +15,6 @@ target_link_libraries( PUBLIC Boost::boost Boost::system - Boost::filesystem Imath::Imath Imath::ImathConfig ) diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index 3cc023c6..bec8c205 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -18,6 +18,7 @@ endif() target_link_libraries ( ${RAWTOACESLIB} PUBLIC ${RAWTOACESIDTLIB} + Boost::filesystem INTERFACE Eigen3::Eigen Imath::Imath diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index 7ce482f3..052307a4 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -296,15 +297,12 @@ bool check_param( return false; } - if ( param_value.size() != correct_size ) - { - std::cerr << "Warning: The parameter \"" << param_name - << "\" must have " << correct_size << " values. " - << default_value_message << std::endl; + std::cerr << "Warning: The parameter \"" << param_name + << "\" must have " << correct_size << " values. " + << default_value_message << std::endl; - on_failure(); - return false; - } + on_failure(); + return false; } } else diff --git a/unittest/testDNGIdt.cpp b/unittest/testDNGIdt.cpp index b29473bb..ef75ed8a 100644 --- a/unittest/testDNGIdt.cpp +++ b/unittest/testDNGIdt.cpp @@ -57,6 +57,8 @@ #include #include +#include + #include using namespace std; From 02d534dff1072d743088b181fa192ec027528cf0 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Fri, 7 Feb 2025 09:06:18 +1300 Subject: [PATCH 06/20] fix formating Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/acesrender.h | 4 ++-- include/rawtoaces/rta.h | 10 +++++----- src/rawtoaces_idt/CMakeLists.txt | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/rawtoaces/acesrender.h b/include/rawtoaces/acesrender.h index 823991f4..686fcd4f 100644 --- a/include/rawtoaces/acesrender.h +++ b/include/rawtoaces/acesrender.h @@ -67,8 +67,8 @@ void usage( const char *prog ); class LibRawAces : virtual public LibRaw { public: - LibRawAces() {}; - ~LibRawAces() {}; + LibRawAces(){}; + ~LibRawAces(){}; void show() { printf( "I am here with LibRawAces.\n" ); } }; diff --git a/include/rawtoaces/rta.h b/include/rawtoaces/rta.h index 0463904c..c2246a94 100644 --- a/include/rawtoaces/rta.h +++ b/include/rawtoaces/rta.h @@ -67,8 +67,8 @@ namespace rta { struct CIEXYZ { - CIEXYZ() {}; - CIEXYZ( double X, double Y, double Z ) : _Xt( X ), _Yt( Y ), _Zt( Z ) {}; + CIEXYZ(){}; + CIEXYZ( double X, double Y, double Z ) : _Xt( X ), _Yt( Y ), _Zt( Z ){}; double _Xt; double _Yt; double _Zt; @@ -90,9 +90,9 @@ struct CMF struct RGBSen { - RGBSen() {}; + RGBSen(){}; RGBSen( double R, double G, double B ) - : _RSen( R ), _GSen( G ), _BSen( B ) {}; + : _RSen( R ), _GSen( G ), _BSen( B ){}; double _RSen; double _GSen; @@ -143,7 +143,7 @@ class Spst : _brand( brand ) , _model( model ) , _increment( increment ) - , _rgbsen( rgbsen ) {}; + , _rgbsen( rgbsen ){}; ~Spst(); void setBrand( const char *brand ); diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index 222f93c2..d159e885 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -10,6 +10,8 @@ add_library( ${RAWTOACESIDTLIB} ${DO_SHARED} ../../include/rawtoaces/rta.h ) +set_property(TARGET ${RAWTOACESIDTLIB} PROPERTY CXX_STANDARD 17) + target_link_libraries( ${RAWTOACESIDTLIB} PUBLIC From 6e18fc71376725192fa5a8fb5b35e7f18690e1bb Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 10 Feb 2025 08:56:03 +1300 Subject: [PATCH 07/20] change the public interfaces to make it easier to use the tool as a library Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/rawtoaces_util.h | 125 ++++--- src/rawtoaces2/main.cpp | 39 +- src/rawtoaces_idt/rta.cpp | 16 +- src/rawtoaces_util2/rawtoaces_util.cpp | 491 ++++++++++++++----------- 4 files changed, 377 insertions(+), 294 deletions(-) diff --git a/include/rawtoaces/rawtoaces_util.h b/include/rawtoaces/rawtoaces_util.h index 618644f0..3e5d512d 100644 --- a/include/rawtoaces/rawtoaces_util.h +++ b/include/rawtoaces/rawtoaces_util.h @@ -17,8 +17,6 @@ namespace rta class ImageConverter { public: - ImageConverter(); - /// The white balancing method to use for conversion can be specified /// enum class WBMethod @@ -83,79 +81,92 @@ class ImageConverter int highlight_mode = 0; int flip = 0; int cropbox[4] = { 0, 0, 0, 0 }; - - int verbosity; - - /// Returns a class which will be used for parsing the command line - /// parameters. Can be used to add additional parameters before calling - /// `parse()`. The additional parameters will be parsed by ignored by this - /// class. - /// @result A non-const reference to an - /// initialised OIIO::ArgParse class. - OIIO::ArgParse &argParse(); - - /// Returns an image buffer, containing the image in the current state - /// after the previous step of processing. The image can be modified before - /// executing the next step if needed. - /// @result A non-const reference to the image buffer. - OIIO::ImageBuf &imageBuffer(); - - /// Parse the command line parameters. This method can be used to - /// configure the converter instead of modifying each conversion parameter - /// individually. Additional command line parameters can be added by - /// modifying the structure returned by `argParse()`. - /// @param argc - /// number of parameters - /// @param argv - /// list of parameters + int verbosity = 0; + + /// Initialise the parser object with all the command line parameters + /// used by this tool. The method also sets the help and usage strings. + /// The parser object can be amended by the calling code afterwards if + /// needed. This method is optional, all of the settings above can be + /// modified directly. + /// @param argParse + /// The command line parser object to be updated. + void init_parser( OIIO::ArgParse &argParse ) const; + + /// Initialise the converter settings from the command line parser object. + /// Prior to calling this, first initialise the object via + /// `ImageConverted::init_parser()`, and call + /// `OIIO::ArgParse::parse_args()`. + /// This method is optional, all of the settings above can be modified + /// directly. + /// @param argParse + /// the command line parser object /// @result /// `true` if parsed successfully - bool parse( int argc, const char *argv[] ); + bool parse_params( const OIIO::ArgParse &argParse ); /// Configures the converter using the requested white balance and colour /// matrix method, and the metadata of the file provided in `input_file`. /// @param input_filename /// A file name of the raw image file to read the metadata from. + /// @param options + /// Conversion hints to be passed to OIIO when reading an image file. + /// The list can be pre- or post- updated with other hints, unrelated to + /// the rawtoaces conversion. /// @result /// `true` if configured successfully. - bool configure( const std::string &input_filename ); - - /// Loads an image to convert. Note that the image file name in - /// `input_filename` can be differnt from the one used in `configure()`. - /// This is useful for configuring the converter using one image, and - /// applying the conversion to a different one, or multiple images. - /// @param input_filename - /// A file name of the raw image file to read the pixels from. + bool configure( + const std::string &input_filename, OIIO::ParamValueList &options ); + + /// Apply the colour space conversion matrix (or matrices) to convert the + /// image buffer from the raw camera colour space to ACES. + /// @param dst + /// Destination image buffer. + /// @param src + /// Source image buffer, can be the same as `dst` for in-place + /// conversion. /// @result - /// `true` if loaded successfully. - bool load( const std::string &input_filename ); - - /// Converts the image from raw camera colour space to ACES. + /// `true` if converted successfully. + bool apply_matrix( + OIIO::ImageBuf &dst, const OIIO::ImageBuf &src, OIIO::ROI roi = {} ); + + /// Apply the headroom scale to image buffer. + /// @param dst + /// Destination image buffer. + /// @param src + /// Source image buffer, can be the same as `dst` for in-place + /// conversion. /// @result /// `true` if converted successfully. - bool process(); + bool apply_scale( + OIIO::ImageBuf &dst, const OIIO::ImageBuf &src, OIIO::ROI roi = {} ); /// Saves the image into ACES Container. + /// @param output_filename + /// Full path to the file to be saved. + /// @param buf + /// Image buffer to be saved. /// @result /// `true` if saved successfully. - bool save( const std::string &output_filename ); + bool save( const std::string &output_filename, const OIIO::ImageBuf &buf ); private: - void initArgParse(); - void prepareIDT_DNG(); - void prepareIDT_nonDNG(); - void prepareIDT_spectral( bool calc_white_balance, bool calc_matrix ); - void applyMatrix( const std::vector> &matrix ); - - bool _is_DNG; - std::string _configFilename; - std::string _cameraMake; - std::string _cameraModel; - - OIIO::ArgParse _argParse; - OIIO::ImageSpec _inputHint; - OIIO::ImageSpec _inputFull; - OIIO::ImageBuf _imageBuffer; + void prepareIDT_DNG( const OIIO::ImageSpec &imageSpec ); + void prepareIDT_nonDNG( const OIIO::ImageSpec &imageSpec ); + void prepareIDT_spectral( + const OIIO::ImageSpec &imageSpec, + bool calc_white_balance, + bool calc_matrix ); + bool applyMatrix( + const std::vector> &matrix, + OIIO::ImageBuf &dst, + const OIIO::ImageBuf &src, + OIIO::ROI roi ); + + bool _is_DNG; + + /// Make libraw read the raw photosites data without any processing. + /// This is set if the requested demosaicing method is set `None`. + bool _read_raw = false; std::vector _WB_mults; std::vector> _IDT_matrix; diff --git a/src/rawtoaces2/main.cpp b/src/rawtoaces2/main.cpp index 3e8d8cf0..75d55337 100644 --- a/src/rawtoaces2/main.cpp +++ b/src/rawtoaces2/main.cpp @@ -10,14 +10,22 @@ using namespace rta; int main( int argc, const char *argv[] ) { + + OIIO::ArgParse argParse; + ImageConverter converter; + converter.init_parser( argParse ); + + if ( argParse.parse_args( argc, argv ) < 0 ) + { + return 1; + } - if ( !converter.parse( argc, argv ) ) + if ( !converter.parse_params( argParse ) ) { return 1; } - auto &argParse = converter.argParse(); auto files = argParse["filename"].as_vec(); std::vector files_to_convert; @@ -69,7 +77,9 @@ int main( int argc, const char *argv[] ) } output_filename += "_oiio.exr"; - if ( !converter.configure( input_filename ) ) + OIIO::ParamValueList options; + + if ( !converter.configure( input_filename, options ) ) { std::cerr << "Failed to configure the reader for the file: " << input_filename << std::endl; @@ -77,7 +87,14 @@ int main( int argc, const char *argv[] ) continue; } - if ( !converter.load( input_filename ) ) + OIIO::ImageSpec imageSpec; + imageSpec.extra_attribs = options; + + OIIO::ImageBuf buffer = OIIO::ImageBuf( + input_filename, 0, 0, nullptr, &imageSpec, nullptr ); + + if ( !buffer.read( + 0, 0, 0, buffer.nchannels(), true, OIIO::TypeDesc::FLOAT ) ) { std::cerr << "Failed to read for the file: " << input_filename << std::endl; @@ -85,15 +102,23 @@ int main( int argc, const char *argv[] ) continue; } - if ( !converter.process() ) + if ( !converter.apply_matrix( buffer, buffer ) ) + { + std::cerr << "Failed to apply colour space conversion to the file: " + << input_filename << std::endl; + result = false; + continue; + } + + if ( !converter.apply_scale( buffer, buffer ) ) { - std::cerr << "Failed to convert the file: " << input_filename + std::cerr << "Failed to apply scale to the file: " << input_filename << std::endl; result = false; continue; } - if ( !converter.save( output_filename ) ) + if ( !converter.save( output_filename, buffer ) ) { std::cerr << "Failed to save the file: " << output_filename << std::endl; diff --git a/src/rawtoaces_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 6582f3ff..17de1a53 100644 --- a/src/rawtoaces_idt/rta.cpp +++ b/src/rawtoaces_idt/rta.cpp @@ -233,13 +233,13 @@ vector Illum::cctToxy( const double &cctd ) const if ( cctd >= 4002.15 && cctd <= 7003.77 ) xy[0] = ( 0.244063 + 99.11 / cctd + - 2.9678 * 1000000 / ( std::pow( cctd, 2 ) ) - - 4.6070 * 1000000000 / ( std::pow( cctd, 3 ) ) ); + 2.9678 * 1000000 / (std::pow( cctd, 2 ))-4.6070 * 1000000000 / + ( std::pow( cctd, 3 ) ) ); else xy[0] = ( 0.237040 + 247.48 / cctd + - 1.9018 * 1000000 / ( std::pow( cctd, 2 ) ) - - 2.0064 * 1000000000 / ( std::pow( cctd, 3 ) ) ); + 1.9018 * 1000000 / (std::pow( cctd, 2 ))-2.0064 * 1000000000 / + ( std::pow( cctd, 3 ) ) ); xy[1] = -3.0 * ( std::pow( xy[0], 2 ) ) + 2.87 * xy[0] - 0.275; @@ -1028,13 +1028,15 @@ void Idt::loadCMF( const string &path ) BOOST_FOREACH ( ptree::value_type &row, pt.get_child( "spectral_data.data.main" ) ) { - _cmf[i]._wl = atoi( ( row.first ).c_str() ); + int wl = atoi( ( row.first ).c_str() ); - if ( _cmf[i]._wl < 380 || _cmf[i]._wl % 5 ) + if ( wl < 380 || wl % 5 ) continue; - else if ( _cmf[i]._wl > 780 ) + else if ( wl > 780 ) break; + _cmf[i]._wl = wl; + vector data; BOOST_FOREACH ( ptree::value_type &cell, row.second ) data.push_back( cell.second.get_value() ); diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index 052307a4..eda61bcf 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -52,11 +52,6 @@ std::vector collectDataFiles( const std::string &type ) return result; } -ImageConverter::ImageConverter() -{ - initArgParse(); -} - const char *HelpString = "Rawtoaces converts raw image files from a digital camera to " "the Academy Colour Encoding System (ACES) compliant images.\n" @@ -112,16 +107,77 @@ const char *UsageString = " rawtoaces --wb-method illuminant --illuminant 3200K --mat-method " "spectral raw_file.cr3\n"; -void ImageConverter::initArgParse() +template +bool check_param( + const std::string &mode_name, + const std::string &mode_value, + const std::string ¶m_name, + const std::vector ¶m_value, + size_t correct_size, + const std::string &default_value_message, + bool is_correct_mode, + F1 on_success, + F2 on_failure ) +{ + if ( is_correct_mode ) + { + if ( param_value.size() == correct_size ) + { + on_success(); + return true; + } + else + { + if ( ( param_value.size() == 0 ) || + ( ( param_value.size() == 1 ) && ( param_value[0] == 0 ) ) ) + { + std::cerr << "Warning: " << mode_name << " was set to \"" + << mode_value << "\", but no \"--" << param_name + << "\" parameter provided. " << default_value_message + << std::endl; + + on_failure(); + return false; + } + + std::cerr << "Warning: The parameter \"" << param_name + << "\" must have " << correct_size << " values. " + << default_value_message << std::endl; + + on_failure(); + return false; + } + } + else + { + if ( ( param_value.size() > 1 ) || + ( ( param_value.size() == 1 ) && ( param_value[0] != 0 ) ) ) + { + std::cerr << "Warning: the \"--" << param_name + << "\" parameter provided, but the " << mode_name + << " is different from \"" << mode_value << "\". " + << default_value_message << std::endl; + + on_failure(); + return false; + } + else + { + return true; + } + } +} + +void ImageConverter::init_parser( OIIO::ArgParse &argParse ) const { - _argParse.intro( HelpString ).usage( UsageString ); - _argParse.print_defaults( true ); - _argParse.add_help( true ); - _argParse.add_version( "VERSION NUMBER" ); + argParse.intro( HelpString ).usage( UsageString ); + argParse.print_defaults( true ); + argParse.add_help( true ); + argParse.add_version( "TODO: VERSION NUMBER" ); - _argParse.arg( "filename" ).action( OIIO::ArgParse::append() ).hidden(); + argParse.arg( "filename" ).action( OIIO::ArgParse::append() ).hidden(); - _argParse.arg( "--wb-method" ) + argParse.arg( "--wb-method" ) .help( "White balance method. Supported options: metadata, illuminant, " "box, custom." ) @@ -129,7 +185,7 @@ void ImageConverter::initArgParse() .defaultval( "metadata" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--mat-method" ) + argParse.arg( "--mat-method" ) .help( "IDT matrix calculation method. Supported options: spectral, " "metadata, Adobe, custom." ) @@ -137,12 +193,12 @@ void ImageConverter::initArgParse() .defaultval( "spectral" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--illuminant" ) + argParse.arg( "--illuminant" ) .help( "Illuminant for white balancing. (default = D55)" ) .metavar( "STR" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--wb-box" ) + argParse.arg( "--wb-box" ) .help( "Box to use for white balancing. (default = (0,0,0,0) - full " "image)" ) @@ -150,31 +206,31 @@ void ImageConverter::initArgParse() .metavar( "X Y W H" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--custom-wb" ) + argParse.arg( "--custom-wb" ) .help( "Custom white balance multipliers." ) .nargs( 4 ) .metavar( "R G B G" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--custom-mat" ) + argParse.arg( "--custom-mat" ) .help( "Custom camera RGB to XYZ matrix." ) .nargs( 9 ) .metavar( "Rr Rg Rb Gr Gg Gb Br Bg Bb" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--headroom" ) + argParse.arg( "--headroom" ) .help( "Highlight headroom factor." ) .metavar( "VAL" ) .defaultval( 6.0f ) .action( OIIO::ArgParse::store() ); - _argParse.separator( "Raw conversion options:" ); + argParse.separator( "Raw conversion options:" ); - _argParse.arg( "--no-auto-bright" ) + argParse.arg( "--no-auto-bright" ) .help( "Disable automatic exposure adjustment." ) .action( OIIO::ArgParse::store_true() ); - _argParse.arg( "--adjust-maximum-threshold" ) + argParse.arg( "--adjust-maximum-threshold" ) .help( "Automatically lower the linearity threshold provided in the " "metadata by this scaling factor." ) @@ -182,13 +238,13 @@ void ImageConverter::initArgParse() .defaultval( 0.75f ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--black-level" ) + argParse.arg( "--black-level" ) .help( "If >= 0, override the black level." ) .metavar( "VAL" ) .defaultval( -1 ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--saturation-level" ) + argParse.arg( "--saturation-level" ) .help( "If not 0, override the level which appears to be saturated " "after normalisation." ) @@ -196,7 +252,7 @@ void ImageConverter::initArgParse() .defaultval( 0 ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--chromatic-aberration" ) + argParse.arg( "--chromatic-aberration" ) .help( "Red and blue scale factors for chromatic aberration correction. " "The value of 1 means no correction." ) @@ -205,17 +261,17 @@ void ImageConverter::initArgParse() .defaultval( 1.0f ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--half-size" ) + argParse.arg( "--half-size" ) .help( "If present, decode image at half size resolution." ) .action( OIIO::ArgParse::store_true() ); - _argParse.arg( "--highlight-mode" ) + argParse.arg( "--highlight-mode" ) .help( "0 = clip, 1 = unclip, 2 = blend, 3..9 = rebuild." ) .metavar( "VAL" ) .defaultval( 0 ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--cropbox" ) + argParse.arg( "--cropbox" ) .help( "Apply custom crop. If not present, the default crop is applied, " "which should match the crop of the in-camera JPEG." ) @@ -223,7 +279,7 @@ void ImageConverter::initArgParse() .metavar( "X Y W H" ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--flip" ) + argParse.arg( "--flip" ) .help( "If not 0, override the orientation specified in the metadata. " "1..8 correspond to EXIF orientation codes " @@ -232,112 +288,36 @@ void ImageConverter::initArgParse() .defaultval( 0 ) .action( OIIO::ArgParse::store() ); - _argParse.arg( "--denoise_threshold" ) + argParse.arg( "--denoise_threshold" ) .help( "Wavelet denoising threshold" ) .metavar( "VAL" ) .defaultval( 0 ) .action( OIIO::ArgParse::store() ); - _argParse.separator( "Benchmarking and debugging:" ); + argParse.separator( "Benchmarking and debugging:" ); - _argParse.arg( "--list-cameras" ) + argParse.arg( "--list-cameras" ) .help( "Shows the list of cameras supported in spectral mode." ) .action( OIIO::ArgParse::store_true() ); - _argParse.arg( "--list-illuminants" ) + argParse.arg( "--list-illuminants" ) .help( "Shows the list of illuminants supported in spectral mode." ) .action( OIIO::ArgParse::store_true() ); - _argParse.arg( "--verbose" ) + argParse.arg( "--verbose" ) .help( "Verbosity level. 0 = off, 1 = info, 2 = debug." ) + .metavar( "VAL" ) .defaultval( 0 ) .action( OIIO::ArgParse::store() ); } -OIIO::ArgParse &ImageConverter::argParse() +bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) { - return _argParse; -} - -OIIO::ImageBuf &ImageConverter::imageBuffer() -{ - return _imageBuffer; -} - -template -bool check_param( - const std::string &mode_name, - const std::string &mode_value, - const std::string ¶m_name, - const std::vector ¶m_value, - size_t correct_size, - const std::string &default_value_message, - bool is_correct_mode, - F1 on_success, - F2 on_failure ) -{ - if ( is_correct_mode ) - { - if ( param_value.size() == correct_size ) - { - on_success(); - return true; - } - else - { - if ( ( param_value.size() == 0 ) || - ( ( param_value.size() == 1 ) && ( param_value[0] == 0 ) ) ) - { - std::cerr << "Warning: " << mode_name << " was set to \"" - << mode_value << "\", but no \"--" << param_name - << "\" parameter provided. " << default_value_message - << std::endl; - - on_failure(); - return false; - } - - std::cerr << "Warning: The parameter \"" << param_name - << "\" must have " << correct_size << " values. " - << default_value_message << std::endl; - - on_failure(); - return false; - } - } - else - { - if ( ( param_value.size() > 1 ) || - ( ( param_value.size() == 1 ) && ( param_value[0] != 0 ) ) ) - { - std::cerr << "Warning: the \"--" << param_name - << "\" parameter provided, but the " << mode_name - << " is different from \"" << mode_value << "\". " - << default_value_message << std::endl; - - on_failure(); - return false; - } - else - { - return true; - } - } -} - -bool ImageConverter::parse( int argc, const char *argv[] ) -{ - if ( _argParse.parse_args( argc, argv ) ) - { - // report error? - return false; - } - - if ( _argParse["list-cameras"].get() ) + if ( argParse["list-cameras"].get() ) { std::cout - << "Spectral sensitivity data are available for the following cameras:" - << std::endl; + << "Spectral sensitivity data are available for the following " + << "cameras:" << std::endl; Idt idt; auto paths = collectDataFiles( "camera" ); @@ -360,7 +340,7 @@ bool ImageConverter::parse( int argc, const char *argv[] ) exit( 0 ); } - if ( _argParse["list-illuminants"].get() ) + if ( argParse["list-illuminants"].get() ) { std::cout << "The following illuminants are supported:" << std::endl; std::cout << "- The standard illuminant series D (e.g., D60, D6025)" @@ -387,9 +367,9 @@ bool ImageConverter::parse( int argc, const char *argv[] ) exit( 0 ); } - verbosity = _argParse["verbose"].get(); + verbosity = argParse["verbose"].get(); - std::string wb_method = _argParse["wb-method"].get(); + std::string wb_method = argParse["wb-method"].get(); if ( wb_method == "metadata" ) { @@ -416,7 +396,7 @@ bool ImageConverter::parse( int argc, const char *argv[] ) return false; } - std::string mat_method = _argParse["mat-method"].get(); + std::string mat_method = argParse["mat-method"].get(); if ( mat_method == "spectral" ) { @@ -443,9 +423,9 @@ bool ImageConverter::parse( int argc, const char *argv[] ) return false; } - headroom = _argParse["headroom"].get(); + headroom = argParse["headroom"].get(); - std::string illum = _argParse["illuminant"].get(); + std::string illum = argParse["illuminant"].get(); if ( wbMethod == WBMethod::Illuminant ) { @@ -469,7 +449,7 @@ bool ImageConverter::parse( int argc, const char *argv[] ) } } - auto box = _argParse["wb-box"].as_vec(); + auto box = argParse["wb-box"].as_vec(); check_param( "white balancing mode", "box", @@ -487,7 +467,7 @@ bool ImageConverter::parse( int argc, const char *argv[] ) wbBox[i] = 0; } ); - auto custom_wb = _argParse["custom-wb"].as_vec(); + auto custom_wb = argParse["custom-wb"].as_vec(); check_param( "white balancing mode", "custom", @@ -505,7 +485,7 @@ bool ImageConverter::parse( int argc, const char *argv[] ) customWB[i] = 1.0; } ); - auto custom_mat = _argParse["custom-mat"].as_vec(); + auto custom_mat = argParse["custom-mat"].as_vec(); check_param( "matrix mode", "custom", @@ -525,56 +505,60 @@ bool ImageConverter::parse( int argc, const char *argv[] ) customMatrix[i][j] = i == j ? 1.0 : 0.0; } ); - auto crop = _argParse["cropbox"].as_vec(); + auto crop = argParse["cropbox"].as_vec(); if ( crop.size() == 4 ) { for ( size_t i = 0; i < 4; i++ ) cropbox[i] = crop[i]; } - no_auto_bright = _argParse["no-auto-bright"].get(); - adjust_maximum_threshold = _argParse["adjust-maximum-threshold"].get(); - black_level = _argParse["black-level"].get(); - saturation_level = _argParse["saturation-level"].get(); - half_size = _argParse["half-size"].get(); - highlight_mode = _argParse["highlight-mode"].get(); - flip = _argParse["flip"].get(); + no_auto_bright = argParse["no-auto-bright"].get(); + adjust_maximum_threshold = argParse["adjust-maximum-threshold"].get(); + black_level = argParse["black-level"].get(); + saturation_level = argParse["saturation-level"].get(); + half_size = argParse["half-size"].get(); + highlight_mode = argParse["highlight-mode"].get(); + flip = argParse["flip"].get(); return true; } -bool ImageConverter::configure( const std::string &input_filename ) +bool ImageConverter::configure( + const std::string &input_filename, OIIO::ParamValueList &options ) { - _configFilename = input_filename; + _read_raw = options.get_string( "raw:Demosaic" ) == "None"; - _inputHint = OIIO::ImageSpec(); + OIIO::ImageSpec imageSpec; - _inputHint["raw:ColorSpace"] = "XYZ"; - _inputHint["raw:use_camera_wb"] = 0; - _inputHint["raw:use_auto_wb"] = 0; + options["raw:ColorSpace"] = "XYZ"; + options["raw:use_camera_wb"] = 0; + options["raw:use_auto_wb"] = 0; - _inputHint["raw:auto_bright"] = no_auto_bright ? 0 : 1; - _inputHint["raw:adjust_maximum_thr"] = adjust_maximum_threshold; - _inputHint["raw:user_black"] = black_level; - _inputHint["raw:user_sat"] = saturation_level; - _inputHint["raw:half_size"] = (int)half_size; - _inputHint["raw:flip"] = flip; - _inputHint["raw:HighlightMode"] = highlight_mode; + options["raw:auto_bright"] = no_auto_bright ? 0 : 1; + options["raw:adjust_maximum_thr"] = adjust_maximum_threshold; + options["raw:user_black"] = black_level; + options["raw:user_sat"] = saturation_level; + options["raw:half_size"] = (int)half_size; + options["raw:flip"] = flip; + options["raw:HighlightMode"] = highlight_mode; if ( cropbox[2] != 0 && cropbox[3] != 0 ) { - _inputHint.attribute( + options.attribute( "raw:cropbox", OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), cropbox ); } - auto imageInput = OIIO::ImageInput::create( "raw", false, &_inputHint ); - bool result = imageInput->open( input_filename, _inputFull, _inputHint ); + OIIO::ImageSpec temp_spec; + temp_spec.extra_attribs = options; + + auto imageInput = OIIO::ImageInput::create( "raw", false, &temp_spec ); + bool result = imageInput->open( input_filename, imageSpec, temp_spec ); if ( !result ) { return false; } - _is_DNG = _inputFull.extra_attribs.find( "raw:dng:version" )->get_int() > 0; + _is_DNG = imageSpec.extra_attribs.find( "raw:dng:version" )->get_int() > 0; switch ( wbMethod ) { @@ -583,15 +567,22 @@ bool ImageConverter::configure( const std::string &input_filename ) for ( int i = 0; i < 4; i++ ) { - user_mul[i] = _inputFull.find_attribute( "raw:cam_mul" ) + user_mul[i] = imageSpec.find_attribute( "raw:cam_mul" ) ->get_float_indexed( i ) / 256.0; } - _inputHint.attribute( + options.attribute( "raw:user_mul", OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), user_mul ); + + if ( _read_raw ) + { + _WB_mults.resize( 4 ); + for ( size_t i = 0; i < 4; i++ ) + _WB_mults[i] = user_mul[i]; + } break; } @@ -617,7 +608,7 @@ bool ImageConverter::configure( const std::string &input_filename ) if ( wbBox[2] == 0 || wbBox[3] == 0 ) { // Empty box, use whole image. - _inputHint["raw:use_auto_wb"] = 1; + options["raw:use_auto_wb"] = 1; } else { @@ -626,7 +617,7 @@ bool ImageConverter::configure( const std::string &input_filename ) { box[i] = wbBox[i]; } - _inputHint.attribute( + options.attribute( "raw:greybox", OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), box ); @@ -634,7 +625,7 @@ bool ImageConverter::configure( const std::string &input_filename ) break; case WBMethod::Custom: - _inputHint.attribute( + options.attribute( "raw:user_mul", OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), customWB ); @@ -646,18 +637,16 @@ bool ImageConverter::configure( const std::string &input_filename ) switch ( matrixMethod ) { case MatrixMethod::Spectral: - _inputHint["raw:ColorSpace"] = "raw"; - _inputHint["raw:use_camera_matrix"] = 0; + options["raw:ColorSpace"] = "raw"; + options["raw:use_camera_matrix"] = 0; break; case MatrixMethod::Metadata: - _inputHint["raw:use_camera_matrix"] = _is_DNG ? 1 : 3; - break; - case MatrixMethod::Adobe: - _inputHint["raw:use_camera_matrix"] = 1; + options["raw:use_camera_matrix"] = _is_DNG ? 1 : 3; break; + case MatrixMethod::Adobe: options["raw:use_camera_matrix"] = 1; break; case MatrixMethod::Custom: - _inputHint["raw:use_camera_matrix"] = 0; - _inputHint["raw:ColorSpace"] = "raw"; + options["raw:use_camera_matrix"] = 0; + options["raw:ColorSpace"] = "raw"; _IDT_matrix.resize( 3 ); for ( int i = 0; i < 3; i++ ) @@ -682,14 +671,12 @@ bool ImageConverter::configure( const std::string &input_filename ) for ( int i = 0; i < 4; i++ ) { - pre_mul[i] = _inputFull.find_attribute( "raw:pre_mul" ) + pre_mul[i] = imageSpec.find_attribute( "raw:pre_mul" ) ->get_float_indexed( i ); } - _cameraMake = _inputFull["Make"]; - _cameraModel = _inputFull["Model"]; - - prepareIDT_spectral( spectral_white_balance, spectral_matrix ); + prepareIDT_spectral( + imageSpec, spectral_white_balance, spectral_matrix ); if ( spectral_white_balance ) { @@ -702,7 +689,7 @@ bool ImageConverter::configure( const std::string &input_filename ) if ( _WB_mults.size() == 3 ) user_mul[3] = _WB_mults[1]; - _inputHint.attribute( + options.attribute( "raw:user_mul", OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), user_mul ); @@ -714,43 +701,25 @@ bool ImageConverter::configure( const std::string &input_filename ) { if ( _is_DNG ) { - _inputHint["raw:use_camera_matrix"] = 1; - _inputHint["raw:use_camera_wb"] = 1; + options["raw:use_camera_matrix"] = 1; + options["raw:use_camera_wb"] = 1; - prepareIDT_DNG(); + prepareIDT_DNG( imageSpec ); } else { - prepareIDT_nonDNG(); + prepareIDT_nonDNG( imageSpec ); } } return true; } -bool ImageConverter::load( const std::string &input_filename ) -{ - if ( _configFilename != input_filename ) - { - auto imageInput = OIIO::ImageInput::create( "raw", false, &_inputHint ); - imageInput->open( input_filename, _inputFull, _inputHint ); - } - - _imageBuffer = - OIIO::ImageBuf( input_filename, 0, 0, nullptr, &_inputHint, nullptr ); - bool result = _imageBuffer.init_spec( input_filename, 0, 0 ); - if ( result ) - { - auto &spec = _imageBuffer.spec(); - auto channels = spec.nchannels; - result = - _imageBuffer.read( 0, 0, 0, channels, true, OIIO::TypeDesc::FLOAT ); - } - return result; -} - -void ImageConverter::applyMatrix( - const std::vector> &matrix ) +bool ImageConverter::applyMatrix( + const std::vector> &matrix, + OIIO::ImageBuf &dst, + const OIIO::ImageBuf &src, + OIIO::ROI roi ) { float M[4][4]; @@ -780,34 +749,52 @@ void ImageConverter::applyMatrix( } } - _imageBuffer = OIIO::ImageBufAlgo::colormatrixtransform( _imageBuffer, M ); + return OIIO::ImageBufAlgo::colormatrixtransform( dst, src, M, false, roi ); } -bool ImageConverter::process() +bool ImageConverter::apply_matrix( + OIIO::ImageBuf &dst, const OIIO::ImageBuf &src, OIIO::ROI roi ) { + bool success = true; + + if ( !roi.defined() ) + roi = dst.roi(); + if ( _IDT_matrix.size() ) { - applyMatrix( _IDT_matrix ); + success = applyMatrix( _IDT_matrix, dst, src, roi ); + if ( !success ) + return false; } if ( _CAT_matrix.size() ) { - applyMatrix( _CAT_matrix ); + success = applyMatrix( _CAT_matrix, dst, dst, roi ); + if ( !success ) + return false; - _imageBuffer = OIIO::ImageBufAlgo::colormatrixtransform( - _imageBuffer, XYZ_acesrgb_transposed_4 ); + success = OIIO::ImageBufAlgo::colormatrixtransform( + dst, dst, XYZ_acesrgb_transposed_4, false, roi ); + if ( !success ) + return false; } - _imageBuffer = OIIO::ImageBufAlgo::mul( _imageBuffer, headroom ); - return true; + return success; } -bool ImageConverter::save( const std::string &output_filename ) +bool ImageConverter::apply_scale( + OIIO::ImageBuf &dst, const OIIO::ImageBuf &src, OIIO::ROI roi ) +{ + return OIIO::ImageBufAlgo::mul( dst, src, headroom ); +} + +bool ImageConverter::save( + const std::string &output_filename, const OIIO::ImageBuf &buf ) { const float chromaticities[] = { 0.7347, 0.2653, 0, 1, 0.0001, -0.077, 0.32168, 0.33767 }; - OIIO::ImageSpec imageSpec = _inputFull; + OIIO::ImageSpec imageSpec = buf.spec(); imageSpec.set_format( OIIO::TypeDesc::HALF ); imageSpec["acesImageContainerFlag"] = 1; imageSpec["compression"] = "none"; @@ -818,12 +805,14 @@ bool ImageConverter::save( const std::string &output_filename ) auto imageOutput = OIIO::ImageOutput::create( "exr" ); bool result = imageOutput->open( output_filename, imageSpec ); - result = _imageBuffer.write( imageOutput.get() ); + result = buf.write( imageOutput.get() ); return result; } void ImageConverter::prepareIDT_spectral( - bool calc_white_balance, bool calc_matrix ) + const OIIO::ImageSpec &imageSpec, + bool calc_white_balance, + bool calc_matrix ) { std::string lower_illuminant( illuminant ); @@ -839,17 +828,20 @@ void ImageConverter::prepareIDT_spectral( } Idt idt; + idt.setVerbosity( verbosity ); auto illum_paths = collectDataFiles( "illuminant" ); int res = idt.loadIlluminant( illum_paths, lower_illuminant ); - bool found_camera = false; - auto camera_paths = collectDataFiles( "camera" ); + bool found_camera = false; + auto camera_paths = collectDataFiles( "camera" ); + std::string cameraMake = imageSpec["Make"]; + std::string cameraModel = imageSpec["Model"]; for ( auto &path: camera_paths ) { if ( idt.loadCameraSpst( - path, _cameraMake.c_str(), _cameraModel.c_str() ) ) + path, cameraMake.c_str(), cameraModel.c_str() ) ) { found_camera = true; break; @@ -874,11 +866,22 @@ void ImageConverter::prepareIDT_spectral( } else { + auto attr = imageSpec.find_attribute( "raw:cam_mul" ); + float min_val = std::numeric_limits::max(); std::vector cam_mul( 3 ); for ( int i = 0; i < 3; i++ ) - cam_mul[i] = _inputFull.find_attribute( "raw:cam_mul" ) - ->get_float_indexed( i ); - idt.chooseIllumSrc( cam_mul, headroom ); + { + float v = attr->get_float_indexed( i ); + cam_mul[i] = v; + if ( v < min_val ) + min_val = v; + } + for ( int i = 0; i < 3; i++ ) + { + cam_mul[i] /= min_val; + std::cerr << "cam_mul[" << i << "]=" << cam_mul[i] << std::endl; + } + idt.chooseIllumSrc( cam_mul, 0 ); } if ( idt.calIDT() ) @@ -896,7 +899,7 @@ void ImageConverter::prepareIDT_spectral( } } -void ImageConverter::prepareIDT_DNG() +void ImageConverter::prepareIDT_DNG( const OIIO::ImageSpec &imageSpec ) { Metadata metadata; metadata.neutralRGB.resize( 3 ); @@ -906,31 +909,31 @@ void ImageConverter::prepareIDT_DNG() metadata.cameraCalibration2.resize( 9 ); metadata.baselineExposure = - _inputFull.get_float_attribute( "raw:dng:baseline_exposure" ); + imageSpec.get_float_attribute( "raw:dng:baseline_exposure" ); metadata.calibrationIlluminant1 = - _inputFull.get_int_attribute( "raw:dng:calibration_illuminant1" ); + imageSpec.get_int_attribute( "raw:dng:calibration_illuminant1" ); metadata.calibrationIlluminant2 = - _inputFull.get_int_attribute( "raw:dng:calibration_illuminant2" ); + imageSpec.get_int_attribute( "raw:dng:calibration_illuminant2" ); for ( int i = 0; i < 3; i++ ) { metadata.neutralRGB[i] = 1.0 / - _inputFull.find_attribute( "raw:cam_mul" )->get_float_indexed( i ); + imageSpec.find_attribute( "raw:cam_mul" )->get_float_indexed( i ); for ( int j = 0; j < 3; j++ ) { metadata.xyz2rgbMatrix1[i * 3 + j] = - _inputFull.find_attribute( "raw:dng:color_matrix1" ) + imageSpec.find_attribute( "raw:dng:color_matrix1" ) ->get_float_indexed( i * 3 + j ); metadata.xyz2rgbMatrix2[i * 3 + j] = - _inputFull.find_attribute( "raw:dng:color_matrix2" ) + imageSpec.find_attribute( "raw:dng:color_matrix2" ) ->get_float_indexed( i * 3 + j ); metadata.cameraCalibration1[i * 3 + j] = - _inputFull.find_attribute( "raw:dng:camera_calibration1" ) + imageSpec.find_attribute( "raw:dng:camera_calibration1" ) ->get_float_indexed( i * 4 + j ); metadata.cameraCalibration2[i * 3 + j] = - _inputFull.find_attribute( "raw:dng:camera_calibration2" ) + imageSpec.find_attribute( "raw:dng:camera_calibration2" ) ->get_float_indexed( i * 4 + j ); } } @@ -944,9 +947,51 @@ void ImageConverter::prepareIDT_DNG() // _CAT_matrix = dng->getDNGCATMatrix(); } -void ImageConverter::prepareIDT_nonDNG() +void ImageConverter::prepareIDT_nonDNG( const OIIO::ImageSpec &imageSpec ) { - _IDT_matrix.resize( 0 ); + if ( _read_raw ) + { + auto mat = imageSpec.find_attribute( "raw:cam_xyz" ); + size_t size = mat->type().arraylen; + + if ( size == 12 ) + { + std::vector> xyz2cam; + + int idx = 0; + xyz2cam.resize( 4 ); + for ( size_t row = 0; row < 4; row++ ) + { + xyz2cam[row].resize( 4 ); + + for ( size_t col = 0; col < 3; col++ ) + { + xyz2cam[row][col] = mat->get_float_indexed( idx++ ); + } + xyz2cam[row][3] = 0; + } + xyz2cam[3][0] = 0; + xyz2cam[3][1] = 0; + xyz2cam[3][2] = 0; + xyz2cam[3][3] = 1; + + auto cam2xyz = invertVM( xyz2cam ); + + for ( size_t row = 0; row < 3; row++ ) + { + for ( size_t col = 0; col < 3; col++ ) + { + cam2xyz[row][col] /= _WB_mults[row]; + } + } + + _IDT_matrix = cam2xyz; //transposeVec(cam2xyz); + } + } + else + { + _IDT_matrix.resize( 0 ); + } vector dIV( d65, d65 + 3 ); vector dOV( d60, d60 + 3 ); From 4f33dc54a3c1a618fd00d363b35c087ca328e163 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 10 Feb 2025 09:12:40 +1300 Subject: [PATCH 08/20] fix formatting and clang build Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/define.h | 1 + src/rawtoaces/CMakeLists.txt | 2 ++ src/rawtoaces_idt/rta.cpp | 4 ++-- src/rawtoaces_util/CMakeLists.txt | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/rawtoaces/define.h b/include/rawtoaces/define.h index 34c8d92c..302f51be 100644 --- a/include/rawtoaces/define.h +++ b/include/rawtoaces/define.h @@ -58,6 +58,7 @@ #include #include #include +#include #ifndef WIN32 # include diff --git a/src/rawtoaces/CMakeLists.txt b/src/rawtoaces/CMakeLists.txt index abc97ec1..7a26f97a 100644 --- a/src/rawtoaces/CMakeLists.txt +++ b/src/rawtoaces/CMakeLists.txt @@ -5,6 +5,8 @@ add_executable( rawtoaces main.cpp ) +set_property(TARGET rawtoaces PROPERTY CXX_STANDARD 17) + target_include_directories( rawtoaces PUBLIC ${AcesContainer_INCLUDE_DIRS} diff --git a/src/rawtoaces_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 17de1a53..85e221da 100644 --- a/src/rawtoaces_idt/rta.cpp +++ b/src/rawtoaces_idt/rta.cpp @@ -233,12 +233,12 @@ vector Illum::cctToxy( const double &cctd ) const if ( cctd >= 4002.15 && cctd <= 7003.77 ) xy[0] = ( 0.244063 + 99.11 / cctd + - 2.9678 * 1000000 / (std::pow( cctd, 2 ))-4.6070 * 1000000000 / + 2.9678 * 1000000 / (std::pow( cctd, 2 ) )-4.6070 * 1000000000 / ( std::pow( cctd, 3 ) ) ); else xy[0] = ( 0.237040 + 247.48 / cctd + - 1.9018 * 1000000 / (std::pow( cctd, 2 ))-2.0064 * 1000000000 / + 1.9018 * 1000000 / (std::pow( cctd, 2 ) )-2.0064 * 1000000000 / ( std::pow( cctd, 3 ) ) ); xy[1] = -3.0 * ( std::pow( xy[0], 2 ) ) + 2.87 * xy[0] - 0.275; diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index bec8c205..b53bb329 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -5,6 +5,8 @@ add_library ( ${RAWTOACESLIB} ${DO_SHARED} acesrender.cpp ) +set_property(TARGET ${RAWTOACESLIB} PROPERTY CXX_STANDARD 17) + if ( AcesContainer_FOUND ) target_include_directories ( ${RAWTOACESLIB} PRIVATE ${AcesContainer_INCLUDE_DIRS} ) target_link_directories ( ${RAWTOACESLIB} PUBLIC ${AcesContainer_LIBRARY_DIRS} ) From 0fcced4f7a9d7ced4cf5e655b6d98d82c395e47f Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 10 Feb 2025 09:29:37 +1300 Subject: [PATCH 09/20] fix formatting and clang build Signed-off-by: Anton Dukhovnikov --- src/rawtoaces_idt/rta.cpp | 8 ++++---- unittest/CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/rawtoaces_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 85e221da..7957e9af 100644 --- a/src/rawtoaces_idt/rta.cpp +++ b/src/rawtoaces_idt/rta.cpp @@ -233,13 +233,13 @@ vector Illum::cctToxy( const double &cctd ) const if ( cctd >= 4002.15 && cctd <= 7003.77 ) xy[0] = ( 0.244063 + 99.11 / cctd + - 2.9678 * 1000000 / (std::pow( cctd, 2 ) )-4.6070 * 1000000000 / - ( std::pow( cctd, 3 ) ) ); + 2.9678 * 1000000 / ( std::pow( cctd, 2 ) ) + -4.6070 * 1000000000 / ( std::pow( cctd, 3 ) ) ); else xy[0] = ( 0.237040 + 247.48 / cctd + - 1.9018 * 1000000 / (std::pow( cctd, 2 ) )-2.0064 * 1000000000 / - ( std::pow( cctd, 3 ) ) ); + 1.9018 * 1000000 / ( std::pow( cctd, 2 ) ) + -2.0064 * 1000000000 / ( std::pow( cctd, 3 ) ) ); xy[1] = -3.0 * ( std::pow( xy[0], 2 ) ) + 2.87 * xy[0] - 0.275; diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index f8ca8d96..313d183b 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -7,6 +7,8 @@ add_executable ( testSpst.cpp ) +set_property(TARGET Test_Spst PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Spst PUBLIC @@ -21,6 +23,8 @@ add_executable ( testIDT.cpp ) +set_property(TARGET Test_IDT PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_IDT PUBLIC @@ -37,6 +41,8 @@ add_executable ( testIllum.cpp ) +set_property(TARGET Test_Illum PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Illum PUBLIC @@ -51,6 +57,8 @@ add_executable ( testDNGIdt.cpp ) +set_property(TARGET Test_DNGIdt PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_DNGIdt PUBLIC @@ -65,6 +73,8 @@ add_executable ( testMath.cpp ) +set_property(TARGET Test_Math PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Math PUBLIC @@ -79,6 +89,8 @@ add_executable ( testLogic.cpp ) +set_property(TARGET Test_Logic PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Logic PUBLIC @@ -93,6 +105,8 @@ add_executable ( testMisc.cpp ) +set_property(TARGET Test_Misc PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Misc PUBLIC From 4773a20fe550ec727f2238762297fd0766ccbe4d Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Mon, 10 Feb 2025 09:49:55 +1300 Subject: [PATCH 10/20] fix formatting Signed-off-by: Anton Dukhovnikov --- src/rawtoaces_idt/rta.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rawtoaces_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 7957e9af..30bcf0c5 100644 --- a/src/rawtoaces_idt/rta.cpp +++ b/src/rawtoaces_idt/rta.cpp @@ -233,13 +233,13 @@ vector Illum::cctToxy( const double &cctd ) const if ( cctd >= 4002.15 && cctd <= 7003.77 ) xy[0] = ( 0.244063 + 99.11 / cctd + - 2.9678 * 1000000 / ( std::pow( cctd, 2 ) ) - -4.6070 * 1000000000 / ( std::pow( cctd, 3 ) ) ); + 2.9678 * 1000000 / ( std::pow( cctd, 2 ) ) - + 4.6070 * 1000000000 / ( std::pow( cctd, 3 ) ) ); else xy[0] = ( 0.237040 + 247.48 / cctd + - 1.9018 * 1000000 / ( std::pow( cctd, 2 ) ) - -2.0064 * 1000000000 / ( std::pow( cctd, 3 ) ) ); + 1.9018 * 1000000 / ( std::pow( cctd, 2 ) ) - + 2.0064 * 1000000000 / ( std::pow( cctd, 3 ) ) ); xy[1] = -3.0 * ( std::pow( xy[0], 2 ) ) + 2.87 * xy[0] - 0.275; From 808b2e987853003b0f960792b869fff04a6882bc Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Wed, 12 Feb 2025 09:42:37 +1300 Subject: [PATCH 11/20] add RAWTOACES_DATA_PATH env var; clean up public headers Signed-off-by: Anton Dukhovnikov --- CMakeLists.txt | 30 +++++++- include/rawtoaces/acesrender.h | 1 + include/rawtoaces/define.h | 38 ++++++--- include/rawtoaces/rta.h | 4 +- src/rawtoaces/CMakeLists.txt | 2 +- src/rawtoaces2/CMakeLists.txt | 2 +- src/rawtoaces2/main.cpp | 2 +- src/rawtoaces_idt/CMakeLists.txt | 5 +- src/rawtoaces_util/CMakeLists.txt | 7 +- src/rawtoaces_util2/CMakeLists.txt | 5 +- src/rawtoaces_util2/rawtoaces_util.cpp | 102 +++++++++++++++---------- unittest/CMakeLists.txt | 10 ++- unittest/testDNGIdt.cpp | 1 + 13 files changed, 142 insertions(+), 67 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d6f761d..fa46fac2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) project( RAWTOACES ) set( RAWTOACES_MAJOR_VERSION 1 ) @@ -64,6 +64,7 @@ else () set ( DO_SHARED STATIC ) endif () +include ( GNUInstallDirs ) include ( configure.cmake ) @@ -95,13 +96,38 @@ install( FILES "${PROJECT_BINARY_DIR}/RAWTOACESConfigVersion.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) + + +install( + TARGETS rawtoaces_idt rawtoaces_util rawtoaces_util2 rawtoaces + EXPORT RawToAcesConfig + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +export( + TARGETS rawtoaces_idt rawtoaces_util rawtoaces_util2 rawtoaces + NAMESPACE RawToAces:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/RawToAcesConfig.cmake" +) + +install( + EXPORT RawToAcesConfig + DESTINATION "${CMAKE_INSTALL_LIBDIR}/CMake/RawToAces" + NAMESPACE RawToAces:: +) + + + + if ( WIN32 AND NOT CYGWIN ) install( FILES "${PROJECT_BINARY_DIR}/RAWTOACESLibraryDepends.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev ) endif( ) if ( APPLE OR UNIX ) - install (DIRECTORY data DESTINATION include/rawtoaces) + install (DIRECTORY data DESTINATION ${CMAKE_INSTALL_DATADIR}/rawtoaces) endif() enable_testing() diff --git a/include/rawtoaces/acesrender.h b/include/rawtoaces/acesrender.h index 686fcd4f..7a9cfdd0 100644 --- a/include/rawtoaces/acesrender.h +++ b/include/rawtoaces/acesrender.h @@ -56,6 +56,7 @@ #define _ACESRENDER_h__ #include +#include #include #include diff --git a/include/rawtoaces/define.h b/include/rawtoaces/define.h index 302f51be..a3e4f2fd 100644 --- a/include/rawtoaces/define.h +++ b/include/rawtoaces/define.h @@ -460,16 +460,36 @@ inline dataPath &pathsFinder() if ( firstTime ) { - string path; - const char *env; +#if defined( WIN32 ) || defined( WIN64 ) + char separator = ';'; +#else + char separator = ':'; +#endif + string path; vector &PATHs = cdp.paths; - env = getenv( "AMPAS_DATA_PATH" ); - if ( env ) - path = env; + { + const char *env = getenv( "AMPAS_DATA_PATH" ); + if ( env != nullptr ) + { + if ( !path.empty() ) + path += separator; + path += env; + } + } - if ( path == "" ) + { + const char *env = getenv( "RAWTOACES_DATA_PATH" ); + if ( env != nullptr ) + { + if ( !path.empty() ) + path += separator; + path += env; + } + } + + if ( path.empty() ) { #if defined( WIN32 ) || defined( WIN64 ) path = "."; @@ -486,11 +506,7 @@ inline dataPath &pathsFinder() while ( pos < path.size() ) { -#if defined( WIN32 ) || defined( WIN64 ) - size_t end = path.find( ';', pos ); -#else - size_t end = path.find( ':', pos ); -#endif + size_t end = path.find( separator, pos ); if ( end == string::npos ) end = path.size(); diff --git a/include/rawtoaces/rta.h b/include/rawtoaces/rta.h index c2246a94..aabfc45d 100644 --- a/include/rawtoaces/rta.h +++ b/include/rawtoaces/rta.h @@ -55,8 +55,8 @@ #ifndef _RTA_h__ #define _RTA_h__ -#include "define.h" - +#include +#include #include #include "metadata.h" diff --git a/src/rawtoaces/CMakeLists.txt b/src/rawtoaces/CMakeLists.txt index 7a26f97a..44bfe6d3 100644 --- a/src/rawtoaces/CMakeLists.txt +++ b/src/rawtoaces/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_executable( rawtoaces diff --git a/src/rawtoaces2/CMakeLists.txt b/src/rawtoaces2/CMakeLists.txt index 4f6c0922..a9d2ef5f 100644 --- a/src/rawtoaces2/CMakeLists.txt +++ b/src/rawtoaces2/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_executable( rawtoaces2 diff --git a/src/rawtoaces2/main.cpp b/src/rawtoaces2/main.cpp index 75d55337..10e59232 100644 --- a/src/rawtoaces2/main.cpp +++ b/src/rawtoaces2/main.cpp @@ -10,8 +10,8 @@ using namespace rta; int main( int argc, const char *argv[] ) { - OIIO::ArgParse argParse; + argParse.arg( "filename" ).action( OIIO::ArgParse::append() ).hidden(); ImageConverter converter; converter.init_parser( argParse ); diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index d159e885..fc3d48fe 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_library( ${RAWTOACESIDTLIB} ${DO_SHARED} @@ -8,13 +8,14 @@ add_library( ${RAWTOACESIDTLIB} ${DO_SHARED} ../../include/rawtoaces/define.h ../../include/rawtoaces/mathOps.h ../../include/rawtoaces/rta.h + ../../include/rawtoaces/metadata.h ) set_property(TARGET ${RAWTOACESIDTLIB} PROPERTY CXX_STANDARD 17) target_link_libraries( ${RAWTOACESIDTLIB} - PUBLIC + PRIVATE Boost::boost Boost::system Imath::Imath diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index b53bb329..ebce7e32 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -1,8 +1,11 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_library ( ${RAWTOACESLIB} ${DO_SHARED} acesrender.cpp + + # Make the headers visible in IDEs. This should not affect the builds. + ../../include/rawtoaces/acesrender.h ) set_property(TARGET ${RAWTOACESLIB} PROPERTY CXX_STANDARD 17) @@ -11,7 +14,7 @@ if ( AcesContainer_FOUND ) target_include_directories ( ${RAWTOACESLIB} PRIVATE ${AcesContainer_INCLUDE_DIRS} ) target_link_directories ( ${RAWTOACESLIB} PUBLIC ${AcesContainer_LIBRARY_DIRS} ) target_link_libraries ( ${RAWTOACESLIB} - PUBLIC + PRIVATE ${AcesContainer_LIBRARIES} ${AcesContainer_LDFLAGS_OTHER} ) diff --git a/src/rawtoaces_util2/CMakeLists.txt b/src/rawtoaces_util2/CMakeLists.txt index 1265985b..b66f8002 100644 --- a/src/rawtoaces_util2/CMakeLists.txt +++ b/src/rawtoaces_util2/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_library ( rawtoaces_util2 ${DO_SHARED} @@ -19,8 +19,9 @@ if ( OIIO_FOUND ) endif() target_link_libraries ( rawtoaces_util2 - PUBLIC + PRIVATE ${RAWTOACESIDTLIB} + PUBLIC OpenImageIO::OpenImageIO ) diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index eda61bcf..188e0ec7 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -38,14 +38,20 @@ std::vector collectDataFiles( const std::string &type ) for ( auto &path: paths.paths ) { - auto it = std::filesystem::directory_iterator( path + "/" + type ); - - for ( auto filename2: it ) + if ( std::filesystem::is_directory( path ) ) { - auto p = filename2.path(); - if ( filename2.path().extension() == ".json" ) + auto type_path = path + "/" + type; + if ( std::filesystem::exists( type_path ) ) { - result.push_back( filename2.path().string() ); + auto it = std::filesystem::directory_iterator( type_path ); + for ( auto filename2: it ) + { + auto p = filename2.path(); + if ( filename2.path().extension() == ".json" ) + { + result.push_back( filename2.path().string() ); + } + } } } } @@ -95,7 +101,7 @@ const char *HelpString = "A matrix can be specified using the \"--custom-mat\" parameter.\n" "\n" "The paths rawtoaces uses to search for the spectral sensitivity " - "data can be specified in the AMPAS_DATA_PATH environment " + "data can be specified in the RAWTOACES_DATA_PATH environment " "variable.\n"; const char *UsageString = @@ -170,13 +176,12 @@ bool check_param( void ImageConverter::init_parser( OIIO::ArgParse &argParse ) const { - argParse.intro( HelpString ).usage( UsageString ); + argParse.intro( HelpString ); + argParse.usage( UsageString ); argParse.print_defaults( true ); argParse.add_help( true ); argParse.add_version( "TODO: VERSION NUMBER" ); - argParse.arg( "filename" ).action( OIIO::ArgParse::append() ).hidden(); - argParse.arg( "--wb-method" ) .help( "White balance method. Supported options: metadata, illuminant, " @@ -526,7 +531,7 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) bool ImageConverter::configure( const std::string &input_filename, OIIO::ParamValueList &options ) { - _read_raw = options.get_string( "raw:Demosaic" ) == "None"; + _read_raw = options.get_string( "raw:Demosaic" ) == "none"; OIIO::ImageSpec imageSpec; @@ -539,7 +544,7 @@ bool ImageConverter::configure( options["raw:user_black"] = black_level; options["raw:user_sat"] = saturation_level; options["raw:half_size"] = (int)half_size; - options["raw:flip"] = flip; + options["raw:user_flip"] = flip; options["raw:HighlightMode"] = highlight_mode; if ( cropbox[2] != 0 && cropbox[3] != 0 ) @@ -568,8 +573,7 @@ bool ImageConverter::configure( for ( int i = 0; i < 4; i++ ) { user_mul[i] = imageSpec.find_attribute( "raw:cam_mul" ) - ->get_float_indexed( i ) / - 256.0; + ->get_float_indexed( i ); } options.attribute( @@ -585,15 +589,8 @@ bool ImageConverter::configure( } break; } - case WBMethod::Illuminant: { - std::string lower_illuminant( illuminant ); - std::transform( - lower_illuminant.begin(), - lower_illuminant.end(), - lower_illuminant.begin(), - []( unsigned char c ) { return std::tolower( c ); } ); - + std::string lower_illuminant = OIIO::Strutil::lower( illuminant ); if ( !isValidCT( lower_illuminant ) ) { std::cerr << "Unrecognised illuminant \'" << illuminant << "\'" @@ -629,6 +626,13 @@ bool ImageConverter::configure( "raw:user_mul", OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), customWB ); + + if ( _read_raw ) + { + _WB_mults.resize( 4 ); + for ( size_t i = 0; i < 4; i++ ) + _WB_mults[i] = customWB[i]; + } break; default: break; @@ -667,14 +671,6 @@ bool ImageConverter::configure( if ( spectral_white_balance || spectral_matrix ) { - float pre_mul[4]; - - for ( int i = 0; i < 4; i++ ) - { - pre_mul[i] = imageSpec.find_attribute( "raw:pre_mul" ) - ->get_float_indexed( i ); - } - prepareIDT_spectral( imageSpec, spectral_white_balance, spectral_matrix ); @@ -848,6 +844,16 @@ void ImageConverter::prepareIDT_spectral( } } + if ( !found_camera ) + { + std::cerr << "Camera spectral sensitivity data not found for " + << cameraMake << " " << cameraModel << ". " + << "Please check that the data is available " + << "at the location(s) specified in RAWTOACES_DATA_PATH" + << std::endl; + exit( 1 ); + } + auto training = findFile( "training/training_spectral.json" ); if ( training.length() ) { @@ -866,22 +872,34 @@ void ImageConverter::prepareIDT_spectral( } else { - auto attr = imageSpec.find_attribute( "raw:cam_mul" ); - float min_val = std::numeric_limits::max(); - std::vector cam_mul( 3 ); - for ( int i = 0; i < 3; i++ ) + std::vector wb_multipliers( 4 ); + + if ( _WB_mults.size() == 4 ) { - float v = attr->get_float_indexed( i ); - cam_mul[i] = v; - if ( v < min_val ) - min_val = v; + for ( int i = 0; i < 3; i++ ) + wb_multipliers[i] = _WB_mults[i]; } - for ( int i = 0; i < 3; i++ ) + else { - cam_mul[i] /= min_val; - std::cerr << "cam_mul[" << i << "]=" << cam_mul[i] << std::endl; + auto attr = imageSpec.find_attribute( "raw:pre_mul" ); + for ( int i = 0; i < 4; i++ ) + wb_multipliers[i] = attr->get_float_indexed( i ); } - idt.chooseIllumSrc( cam_mul, 0 ); + + if ( wb_multipliers[3] != 0 ) + wb_multipliers[1] = ( wb_multipliers[1] + wb_multipliers[3] ) / 2.0; + wb_multipliers.resize( 3 ); + + float min_val = std::numeric_limits::max(); + for ( int i = 0; i < 3; i++ ) + if ( min_val > wb_multipliers[i] ) + min_val = wb_multipliers[i]; + + if ( min_val > 0 && min_val != 1 ) + for ( int i = 0; i < 3; i++ ) + wb_multipliers[i] /= min_val; + + idt.chooseIllumSrc( wb_multipliers, 0 ); } if ( idt.calIDT() ) diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 313d183b..6743a305 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) add_definitions (-DBOOST_TEST_DYN_LINK) @@ -68,6 +68,14 @@ target_link_libraries( Boost::unit_test_framework ) +if ( LIBRAW_CONFIG_FOUND ) + target_link_libraries ( Test_DNGIdt PUBLIC libraw::raw ) +else () + target_include_directories( Test_DNGIdt PUBLIC ${libraw_INCLUDE_DIR}/..) + target_link_directories( Test_DNGIdt PUBLIC ${libraw_LIBRARY_DIRS} ) + target_link_libraries( Test_DNGIdt PUBLIC ${libraw_LIBRARIES} ${libraw_LDFLAGS_OTHER} ) +endif () + add_executable ( Test_Math testMath.cpp diff --git a/unittest/testDNGIdt.cpp b/unittest/testDNGIdt.cpp index ef75ed8a..0d001398 100644 --- a/unittest/testDNGIdt.cpp +++ b/unittest/testDNGIdt.cpp @@ -60,6 +60,7 @@ #include #include +#include using namespace std; using namespace rta; From f51dbffdfc363ec2b9acd7aa3f91e420f9c5675c Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Wed, 12 Feb 2025 19:33:01 +1300 Subject: [PATCH 12/20] fix build Signed-off-by: Anton Dukhovnikov --- .github/workflows/ci.yml | 3 ++ CMakeLists.txt | 42 ++++++++++++----------- build_scripts/install_aces_container.bash | 20 +++++------ configure.cmake | 2 +- src/rawtoaces/CMakeLists.txt | 7 ---- src/rawtoaces_idt/CMakeLists.txt | 4 +++ src/rawtoaces_util/CMakeLists.txt | 20 +++++------ 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fda874ed..c02fc34b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,15 +100,18 @@ jobs: c_compiler: gcc cpp_compiler: g++ install_deps: install_deps_linux + build_shared_libs: ON - title: ubuntu os: ubuntu-24.04 cpp_compiler: clang++ install_deps: install_deps_linux + build_shared_libs: ON - title: macos os: macos-latest c_compiler: clang cpp_compiler: clang++ install_deps: install_deps_mac + build_shared_libs: ON exclude: - title: windows c_compiler: gcc diff --git a/CMakeLists.txt b/CMakeLists.txt index fa46fac2..329b957b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,6 @@ else () set ( DO_SHARED STATIC ) endif () -include ( GNUInstallDirs ) include ( configure.cmake ) @@ -98,25 +97,6 @@ install( FILES -install( - TARGETS rawtoaces_idt rawtoaces_util rawtoaces_util2 rawtoaces - EXPORT RawToAcesConfig - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) - -export( - TARGETS rawtoaces_idt rawtoaces_util rawtoaces_util2 rawtoaces - NAMESPACE RawToAces:: - FILE "${CMAKE_CURRENT_BINARY_DIR}/RawToAcesConfig.cmake" -) - -install( - EXPORT RawToAcesConfig - DESTINATION "${CMAKE_INSTALL_LIBDIR}/CMake/RawToAces" - NAMESPACE RawToAces:: -) @@ -127,6 +107,28 @@ install( FILES "${PROJECT_BINARY_DIR}/RAWTOACESLibraryDepends.cmake" DESTINATION endif( ) if ( APPLE OR UNIX ) + include ( GNUInstallDirs ) + + install( + TARGETS rawtoaces_idt rawtoaces_util rawtoaces_util2 rawtoaces + EXPORT RawToAcesConfig + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + + export( + TARGETS rawtoaces_idt rawtoaces_util rawtoaces_util2 rawtoaces + NAMESPACE RawToAces:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/RawToAcesConfig.cmake" + ) + + install( + EXPORT RawToAcesConfig + DESTINATION "${CMAKE_INSTALL_LIBDIR}/CMake/RawToAces" + NAMESPACE RawToAces:: + ) + install (DIRECTORY data DESTINATION ${CMAKE_INSTALL_DATADIR}/rawtoaces) endif() diff --git a/build_scripts/install_aces_container.bash b/build_scripts/install_aces_container.bash index 69e6e050..beb0c62d 100755 --- a/build_scripts/install_aces_container.bash +++ b/build_scripts/install_aces_container.bash @@ -2,23 +2,23 @@ set -ex -git clone https://github.com/ampas/aces_container.git aces_container +git clone https://github.com/ampas/aces_container.git ../aces_container if [[ "$OSTYPE" == "linux-gnu"* ]] || [[ "$OSTYPE" == "darwin"* ]]; then cmake \ - -S aces_container \ - -B aces_container/build \ + -S ../aces_container \ + -B ../aces_container/build \ -DCMAKE_CXX_FLAGS="-Wno-c++11-narrowing" - cmake --build aces_container/build - sudo cmake --install aces_container/build + cmake --build ../aces_container/build + sudo cmake --install ../aces_container/build else cmake \ - -S aces_container \ - -B aces_container/build \ - -DCMAKE_INSTALL_PREFIX="." \ + -S ../aces_container \ + -B ../aces_container/build \ + -DCMAKE_INSTALL_PREFIX="../AcesContainer" \ -DBUILD_SHARED_LIBS=OFF - cmake --build aces_container/build --config Release - cmake --install aces_container/build --config Release + cmake --build ../aces_container/build --config Release + cmake --install ../aces_container/build --config Release fi cd ../.. diff --git a/configure.cmake b/configure.cmake index 51b9cec5..f37d02fb 100644 --- a/configure.cmake +++ b/configure.cmake @@ -1,7 +1,7 @@ # Until we get some of these modules into the upstream packages, put them here set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_INSTALL_PREFIX}/share/CMake") - +set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${CMAKE_SOURCE_DIR}/../") find_package ( OpenImageIO CONFIG REQUIRED ) find_package ( AcesContainer CONFIG REQUIRED ) diff --git a/src/rawtoaces/CMakeLists.txt b/src/rawtoaces/CMakeLists.txt index 44bfe6d3..cc23c5fc 100644 --- a/src/rawtoaces/CMakeLists.txt +++ b/src/rawtoaces/CMakeLists.txt @@ -7,16 +7,9 @@ add_executable( rawtoaces set_property(TARGET rawtoaces PROPERTY CXX_STANDARD 17) -target_include_directories( rawtoaces - PUBLIC - ${AcesContainer_INCLUDE_DIRS} -) - target_link_libraries ( rawtoaces PUBLIC ${RAWTOACESLIB} - INTERFACE - Boost::headers ) if ( LIBRAW_CONFIG_FOUND ) diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index fc3d48fe..2591c433 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -13,8 +13,11 @@ add_library( ${RAWTOACESIDTLIB} ${DO_SHARED} set_property(TARGET ${RAWTOACESIDTLIB} PROPERTY CXX_STANDARD 17) +# Eigen is also used in rawtoaces_util and rawtoaces_util2, so setting it public here target_link_libraries( ${RAWTOACESIDTLIB} + PUBLIC + Eigen3::Eigen PRIVATE Boost::boost Boost::system @@ -22,6 +25,7 @@ target_link_libraries( Imath::ImathConfig ) +# Ceres is also used in rawtoaces_util and rawtoaces_util2, so setting it public here if ( ${Ceres_VERSION_MAJOR} GREATER 1 ) target_link_libraries( ${RAWTOACESIDTLIB} PUBLIC Ceres::ceres ) else () diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index ebce7e32..50e1e031 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -10,22 +10,19 @@ add_library ( ${RAWTOACESLIB} ${DO_SHARED} set_property(TARGET ${RAWTOACESLIB} PROPERTY CXX_STANDARD 17) -if ( AcesContainer_FOUND ) - target_include_directories ( ${RAWTOACESLIB} PRIVATE ${AcesContainer_INCLUDE_DIRS} ) - target_link_directories ( ${RAWTOACESLIB} PUBLIC ${AcesContainer_LIBRARY_DIRS} ) - target_link_libraries ( ${RAWTOACESLIB} - PRIVATE - ${AcesContainer_LIBRARIES} - ${AcesContainer_LDFLAGS_OTHER} - ) -endif() +target_include_directories ( ${RAWTOACESLIB} PRIVATE ${AcesContainer_INCLUDE_DIRS} ) +target_link_directories ( ${RAWTOACESLIB} PUBLIC ${AcesContainer_LIBRARY_DIRS} ) +target_link_libraries ( ${RAWTOACESLIB} + PUBLIC + ${AcesContainer_LIBRARIES} + ${AcesContainer_LDFLAGS_OTHER} +) target_link_libraries ( ${RAWTOACESLIB} PUBLIC ${RAWTOACESIDTLIB} + PRIVATE Boost::filesystem - INTERFACE - Eigen3::Eigen Imath::Imath Imath::ImathConfig ) @@ -33,6 +30,7 @@ target_link_libraries ( ${RAWTOACESLIB} if ( LIBRAW_CONFIG_FOUND ) target_link_libraries ( ${RAWTOACESLIB} PUBLIC libraw::raw ) else () + target_include_directories(${RAWTOACESLIB} PUBLIC ${libraw_INCLUDE_DIR}/..) target_link_directories(${RAWTOACESLIB} PUBLIC ${libraw_LIBRARY_DIRS} ) target_link_libraries(${RAWTOACESLIB} PUBLIC ${libraw_LIBRARIES} ${libraw_LDFLAGS_OTHER} ) endif () From 7e7f39e5a2386bed040e7a44fe9272b84090ea5e Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Fri, 14 Feb 2025 08:52:08 +1300 Subject: [PATCH 13/20] add another configure method; more error checking Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/rawtoaces_util.h | 18 +++++++ src/rawtoaces_util2/rawtoaces_util.cpp | 68 +++++++++++++++++--------- 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/include/rawtoaces/rawtoaces_util.h b/include/rawtoaces/rawtoaces_util.h index 3e5d512d..1733a814 100644 --- a/include/rawtoaces/rawtoaces_util.h +++ b/include/rawtoaces/rawtoaces_util.h @@ -106,6 +106,9 @@ class ImageConverter /// Configures the converter using the requested white balance and colour /// matrix method, and the metadata of the file provided in `input_file`. + /// This method loads the metadata from the given image file and + /// initialises the options to give the OIIO raw image reader to + /// decode the pixels. /// @param input_filename /// A file name of the raw image file to read the metadata from. /// @param options @@ -117,6 +120,21 @@ class ImageConverter bool configure( const std::string &input_filename, OIIO::ParamValueList &options ); + /// Configures the converter using the requested white balance and colour + /// matrix method, and the metadata of the given OIIO::ImageSpec object. + /// Use this method if you already have an image read from file to save + /// on disk operations. + /// @param imageSpec + /// An image spec obtained from OIIO::ImageInput or OIIO::ImageBuf. + /// @param options + /// Conversion hints to be passed to OIIO when reading an image file. + /// The list can be pre- or post- updated with other hints, unrelated to + /// the rawtoaces conversion. + /// @result + /// `true` if configured successfully. + bool configure( + const OIIO::ImageSpec &imageSpec, OIIO::ParamValueList &options ); + /// Apply the colour space conversion matrix (or matrices) to convert the /// image buffer from the raw camera colour space to ACES. /// @param dst diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index 188e0ec7..555d2b8c 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -430,11 +430,11 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) headroom = argParse["headroom"].get(); - std::string illum = argParse["illuminant"].get(); + illuminant = argParse["illuminant"].get(); if ( wbMethod == WBMethod::Illuminant ) { - if ( illum.size() == 0 ) + if ( illuminant.empty() ) { std::cerr << "Warning: the white balancing method was set to " << "\"illuminant\", but no \"--illuminant\" parameter " @@ -444,7 +444,7 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) } else { - if ( illum.size() != 0 ) + if ( !illuminant.empty() ) { std::cerr << "Warning: the \"--illuminant\" parameter provided " << "but the white balancing mode different from " @@ -529,13 +529,8 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) } bool ImageConverter::configure( - const std::string &input_filename, OIIO::ParamValueList &options ) + const OIIO::ImageSpec &imageSpec, OIIO::ParamValueList &options ) { - _read_raw = options.get_string( "raw:Demosaic" ) == "none"; - - OIIO::ImageSpec imageSpec; - - options["raw:ColorSpace"] = "XYZ"; options["raw:use_camera_wb"] = 0; options["raw:use_auto_wb"] = 0; @@ -553,16 +548,6 @@ bool ImageConverter::configure( "raw:cropbox", OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), cropbox ); } - OIIO::ImageSpec temp_spec; - temp_spec.extra_attribs = options; - - auto imageInput = OIIO::ImageInput::create( "raw", false, &temp_spec ); - bool result = imageInput->open( input_filename, imageSpec, temp_spec ); - if ( !result ) - { - return false; - } - _is_DNG = imageSpec.extra_attribs.find( "raw:dng:version" )->get_int() > 0; switch ( wbMethod ) @@ -635,7 +620,11 @@ bool ImageConverter::configure( } break; - default: break; + default: + std::cerr + << "ERROR: This white balancing method has not been configured " + << "properly." << std::endl; + exit( 1 ); } switch ( matrixMethod ) @@ -645,12 +634,16 @@ bool ImageConverter::configure( options["raw:use_camera_matrix"] = 0; break; case MatrixMethod::Metadata: + options["raw:ColorSpace"] = "XYZ"; options["raw:use_camera_matrix"] = _is_DNG ? 1 : 3; break; - case MatrixMethod::Adobe: options["raw:use_camera_matrix"] = 1; break; + case MatrixMethod::Adobe: + options["raw:ColorSpace"] = "XYZ"; + options["raw:use_camera_matrix"] = 1; + break; case MatrixMethod::Custom: - options["raw:use_camera_matrix"] = 0; options["raw:ColorSpace"] = "raw"; + options["raw:use_camera_matrix"] = 0; _IDT_matrix.resize( 3 ); for ( int i = 0; i < 3; i++ ) @@ -661,9 +654,12 @@ bool ImageConverter::configure( _IDT_matrix[i][j] = customMatrix[i][j]; } } - break; - default: break; + default: + std::cerr + << "ERROR: This matrix method has not been configured properly." + << std::endl; + exit( 1 ); } bool spectral_white_balance = wbMethod == WBMethod::Illuminant; @@ -711,6 +707,30 @@ bool ImageConverter::configure( return true; } +bool ImageConverter::configure( + const std::string &input_filename, OIIO::ParamValueList &options ) +{ + _read_raw = options.get_string( "raw:Demosaic" ) == "none"; + + OIIO::ImageSpec imageSpec; + + options["raw:ColorSpace"] = "XYZ"; + options["raw:use_camera_wb"] = 0; + options["raw:use_auto_wb"] = 0; + + OIIO::ImageSpec temp_spec; + temp_spec.extra_attribs = options; + + auto imageInput = OIIO::ImageInput::create( "raw", false, &temp_spec ); + bool result = imageInput->open( input_filename, imageSpec, temp_spec ); + if ( !result ) + { + return false; + } + + return configure( imageSpec, options ); +} + bool ImageConverter::applyMatrix( const std::vector> &matrix, OIIO::ImageBuf &dst, From 8cca7d6a9b3be360104f46c10f33c10c547e7288 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Tue, 18 Feb 2025 17:57:55 +1300 Subject: [PATCH 14/20] implement colour transform cache Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/cache_base.h | 95 ++++++++ include/rawtoaces/metadata.h | 29 +++ src/rawtoaces2/CMakeLists.txt | 3 + src/rawtoaces_idt/CMakeLists.txt | 4 +- src/rawtoaces_util2/CMakeLists.txt | 6 +- src/rawtoaces_util2/rawtoaces_util.cpp | 232 ++++++++---------- src/rawtoaces_util2/transform_cache.cpp | 303 ++++++++++++++++++++++++ src/rawtoaces_util2/transform_cache.h | 104 ++++++++ 8 files changed, 638 insertions(+), 138 deletions(-) create mode 100644 include/rawtoaces/cache_base.h create mode 100644 src/rawtoaces_util2/transform_cache.cpp create mode 100644 src/rawtoaces_util2/transform_cache.h diff --git a/include/rawtoaces/cache_base.h b/include/rawtoaces/cache_base.h new file mode 100644 index 00000000..58655831 --- /dev/null +++ b/include/rawtoaces/cache_base.h @@ -0,0 +1,95 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include +#include + +#include +#include +#include + +#include + +namespace rta +{ +namespace cache +{ + +template class CacheEntryDescriptor +{ +public: + virtual size_t map_index() const = 0; + virtual bool fetch( CacheEntryData &data, int verbosity = 0 ) const = 0; + virtual bool operator==( const CacheEntryDescriptor &other ) const = 0; + + // Each subclass must also implement the folowing 2 methods. + // Not sure how to declare them here. + + // friend std::ostream& operator<< (std::ostream& stream, const DescriptorBase& descriptor); + // std::tuple construct_entry() const +}; + +template class CacheBase +{ +public: + const CacheEntryData &fetch( const Descriptor &descriptor ) + { + size_t map_index = descriptor.map_index(); + + std::list> &map = + _maps[map_index]; + + if ( verbosity > 0 ) + { + std::cerr << name << ": searching for a " << descriptor; + } + + for ( auto iter = map.begin(); iter != map.end(); ++iter ) + { + if ( iter->first == descriptor ) + { + if ( iter != map.begin() ) + { + map.splice( map.begin(), map, iter, std::next( iter ) ); + } + + if ( verbosity > 0 ) + { + std::cerr << name << ": found in cache!" << std::endl; + } + return map.front().second; + } + } + + if ( map.size() == capacity ) + { + map.pop_back(); + } + + if ( verbosity > 0 ) + { + std::cerr << name << ": not found. Calculating a new entry." + << std::endl; + } + + map.emplace_front( + std::piecewise_construct, + std::forward_as_tuple( descriptor ), + descriptor.construct_entry() ); + + CacheEntryData &data = map.front().second; + descriptor.fetch( data, verbosity ); + return data; + }; + + int capacity = 10; + int verbosity = 0; + std::string name = "Cache"; + +private: + std::list> _maps[size]; +}; + +} // namespace cache +} // namespace rta diff --git a/include/rawtoaces/metadata.h b/include/rawtoaces/metadata.h index 3abd5741..3e77f526 100644 --- a/include/rawtoaces/metadata.h +++ b/include/rawtoaces/metadata.h @@ -22,6 +22,35 @@ struct Metadata std::vector neutralRGB; double baselineExposure; + + friend bool operator==( const Metadata &m1, const Metadata &m2 ) + { + if ( m1.calibrationIlluminant1 != m2.calibrationIlluminant1 ) + return false; + if ( m1.calibrationIlluminant2 != m2.calibrationIlluminant2 ) + return false; + if ( m1.baselineExposure != m2.baselineExposure ) + return false; + if ( m1.analogBalance != m2.analogBalance ) + return false; + if ( m1.neutralRGB != m2.neutralRGB ) + return false; + if ( m1.cameraCalibration1 != m2.cameraCalibration1 ) + return false; + if ( m1.cameraCalibration2 != m2.cameraCalibration2 ) + return false; + if ( m1.xyz2rgbMatrix1 != m2.xyz2rgbMatrix1 ) + return false; + if ( m1.xyz2rgbMatrix2 != m2.xyz2rgbMatrix2 ) + return false; + + return true; + } + + friend bool operator!=( const Metadata &m1, const Metadata &m2 ) + { + return !( m1 == m2 ); + } }; } // namespace rta diff --git a/src/rawtoaces2/CMakeLists.txt b/src/rawtoaces2/CMakeLists.txt index a9d2ef5f..7571fd7b 100644 --- a/src/rawtoaces2/CMakeLists.txt +++ b/src/rawtoaces2/CMakeLists.txt @@ -18,4 +18,7 @@ target_link_libraries ( rawtoaces2 rawtoaces_util2 ) + +set_target_properties(rawtoaces2 PROPERTIES XCODE_SCHEME_ARGUMENTS "${CMAKE_XCODE_SCHEME_ARGUMENTS}" ) + install( TARGETS rawtoaces2 DESTINATION bin ) diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index 2591c433..f93c1092 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -43,8 +43,8 @@ install(FILES ${PROJECT_SOURCE_DIR}/include/rawtoaces/define.h ${PROJECT_SOURCE_DIR}/include/rawtoaces/mathOps.h ${PROJECT_SOURCE_DIR}/include/rawtoaces/rta.h - - DESTINATION include/rawtoaces + ${PROJECT_SOURCE_DIR}/include/rawtoaces/metadata.h + DESTINATION include/rawtoaces ) install( TARGETS ${RAWTOACESIDTLIB} DESTINATION lib ) diff --git a/src/rawtoaces_util2/CMakeLists.txt b/src/rawtoaces_util2/CMakeLists.txt index b66f8002..ee7b140a 100644 --- a/src/rawtoaces_util2/CMakeLists.txt +++ b/src/rawtoaces_util2/CMakeLists.txt @@ -2,8 +2,11 @@ cmake_minimum_required(VERSION 3.10) include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) add_library ( rawtoaces_util2 ${DO_SHARED} + transform_cache.cpp + transform_cache.h rawtoaces_util.cpp ${PROJECT_SOURCE_DIR}/include/rawtoaces/rawtoaces_util.h + ${PROJECT_SOURCE_DIR}/include/rawtoaces/cache_base.h ) set_property(TARGET rawtoaces_util2 PROPERTY CXX_STANDARD 17) @@ -31,7 +34,8 @@ set_target_properties( rawtoaces_util2 PROPERTIES install( FILES - ${PROJECT_SOURCE_DIR}/include/rawtoaces/rawtoaces_util.h + ${PROJECT_SOURCE_DIR}/include/rawtoaces/rawtoaces_util.h + ${PROJECT_SOURCE_DIR}/include/rawtoaces/cache_base.h DESTINATION include/rawtoaces ) diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index 555d2b8c..d98fa81d 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -8,6 +8,8 @@ #include #include +#include "transform_cache.h" + #include #include #include @@ -17,46 +19,7 @@ namespace rta { -std::string findFile( const std::string &filename ) -{ - auto paths = pathsFinder(); - - for ( auto &path: paths.paths ) - { - std::string full_path = path + "/" + filename; - if ( std::filesystem::exists( full_path ) ) - return full_path; - } - return ""; -} - -std::vector collectDataFiles( const std::string &type ) -{ - std::vector result; - - auto paths = pathsFinder(); - - for ( auto &path: paths.paths ) - { - if ( std::filesystem::is_directory( path ) ) - { - auto type_path = path + "/" + type; - if ( std::filesystem::exists( type_path ) ) - { - auto it = std::filesystem::directory_iterator( type_path ); - for ( auto filename2: it ) - { - auto p = filename2.path(); - if ( filename2.path().extension() == ".json" ) - { - result.push_back( filename2.path().string() ); - } - } - } - } - } - return result; -} +cache::TransformCache transform_cache; const char *HelpString = "Rawtoaces converts raw image files from a digital camera to " @@ -325,7 +288,7 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) << "cameras:" << std::endl; Idt idt; - auto paths = collectDataFiles( "camera" ); + auto paths = cache::collectDataFiles( "camera" ); std::vector cameras; for ( auto path: paths ) { @@ -352,8 +315,8 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) << std::endl; std::cout << "- Black-body radiation (e.g., 3200K)" << std::endl; - Idt idt; - auto paths = collectDataFiles( "illuminant" ); + Idt idt; + auto paths = cache::collectDataFiles( "illuminant" ); std::vector illuminants; for ( auto path: paths ) { @@ -566,7 +529,7 @@ bool ImageConverter::configure( OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), user_mul ); - if ( _read_raw ) + // if ( _read_raw ) { _WB_mults.resize( 4 ); for ( size_t i = 0; i < 4; i++ ) @@ -612,7 +575,7 @@ bool ImageConverter::configure( OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), customWB ); - if ( _read_raw ) + // if ( _read_raw ) { _WB_mults.resize( 4 ); for ( size_t i = 0; i < 4; i++ ) @@ -830,67 +793,15 @@ void ImageConverter::prepareIDT_spectral( bool calc_white_balance, bool calc_matrix ) { - std::string lower_illuminant( illuminant ); - - if ( lower_illuminant.length() == 0 ) + std::string lower_illuminant = OIIO::Strutil::lower( illuminant ); + if ( lower_illuminant.empty() ) lower_illuminant = "na"; - else - { - std::transform( - lower_illuminant.begin(), - lower_illuminant.end(), - lower_illuminant.begin(), - []( unsigned char c ) { return std::tolower( c ); } ); - } - - Idt idt; - idt.setVerbosity( verbosity ); - - auto illum_paths = collectDataFiles( "illuminant" ); - int res = idt.loadIlluminant( illum_paths, lower_illuminant ); - - bool found_camera = false; - auto camera_paths = collectDataFiles( "camera" ); - std::string cameraMake = imageSpec["Make"]; - std::string cameraModel = imageSpec["Model"]; - - for ( auto &path: camera_paths ) - { - if ( idt.loadCameraSpst( - path, cameraMake.c_str(), cameraModel.c_str() ) ) - { - found_camera = true; - break; - } - } - - if ( !found_camera ) - { - std::cerr << "Camera spectral sensitivity data not found for " - << cameraMake << " " << cameraModel << ". " - << "Please check that the data is available " - << "at the location(s) specified in RAWTOACES_DATA_PATH" - << std::endl; - exit( 1 ); - } - auto training = findFile( "training/training_spectral.json" ); - if ( training.length() ) - { - idt.loadTrainingData( training ); - } - - auto cmf = findFile( "cmf/cmf_1931.json" ); - if ( cmf.length() ) - { - idt.loadCMF( cmf ); - } + cache::TransformDescriptor descriptor; + descriptor.camera_make = imageSpec["Make"]; + descriptor.camera_model = imageSpec["Model"]; - if ( lower_illuminant != "na" ) - { - idt.chooseIllumType( lower_illuminant.c_str(), headroom ); - } - else + if ( lower_illuminant == "na" ) { std::vector wb_multipliers( 4 ); @@ -919,27 +830,89 @@ void ImageConverter::prepareIDT_spectral( for ( int i = 0; i < 3; i++ ) wb_multipliers[i] /= min_val; - idt.chooseIllumSrc( wb_multipliers, 0 ); + descriptor.type = cache::TransformEntryType::Illum_from_WB; + cache::WB &wb = descriptor.value.emplace(); + wb.value[0] = wb_multipliers[0]; + wb.value[1] = wb_multipliers[1]; + wb.value[2] = wb_multipliers[2]; } + else + { + descriptor.type = cache::TransformEntryType::WB_from_Illum; + descriptor.value = lower_illuminant; + } + + transform_cache.verbosity = verbosity; + const cache::TransformCacheEntryData &wb_data = + transform_cache.fetch( descriptor ); - if ( idt.calIDT() ) + if ( calc_white_balance ) { - if ( calc_white_balance ) + auto p = std::get>( wb_data.value ); + const cache::WB &wb = p.first; + _WB_mults.resize( 3 ); + _WB_mults[0] = wb.value[0]; + _WB_mults[1] = wb.value[1]; + _WB_mults[2] = wb.value[2]; + } + + if ( calc_matrix ) + { + auto &p = std::get>( wb_data.value ); + std::string illum = p.second; + + cache::TransformDescriptor descriptor; + descriptor.camera_make = imageSpec["Make"]; + descriptor.camera_model = imageSpec["Model"]; + descriptor.type = cache::TransformEntryType::Mat_from_Illum; + descriptor.value = illum; + + const cache::TransformCacheEntryData &mat_data = + transform_cache.fetch( descriptor ); + const cache::Matrix33 &mat = + std::get( mat_data.value ); + + _IDT_matrix.resize( 3 ); + for ( size_t i = 0; i < 3; i++ ) { - _WB_mults = idt.getWB(); + _IDT_matrix[i].resize( 3 ); + for ( size_t j = 0; j < 3; j++ ) + { + _IDT_matrix[i][j] = mat.value[i][j]; + } } - if ( calc_matrix ) + _CAT_matrix.resize( 0 ); + } +} + +void fetch_matrix( + cache::TransformDescriptor &descriptor, + std::vector> &matrix ) +{ + const cache::TransformCacheEntryData &mat_data = + transform_cache.fetch( descriptor ); + const cache::Matrix33 &mat = std::get( mat_data.value ); + + matrix.resize( 3 ); + for ( size_t i = 0; i < 3; i++ ) + { + matrix[i].resize( 3 ); + for ( size_t j = 0; j < 3; j++ ) { - _IDT_matrix = idt.getIDT(); - _CAT_matrix.resize( 0 ); + matrix[i][j] = mat.value[i][j]; } } } void ImageConverter::prepareIDT_DNG( const OIIO::ImageSpec &imageSpec ) { - Metadata metadata; + cache::TransformDescriptor descriptor; + descriptor.type = cache::TransformEntryType::Mat_from_DNG; + descriptor.camera_make = imageSpec["Make"]; + descriptor.camera_model = imageSpec["Model"]; + Metadata &metadata = descriptor.value.emplace(); + metadata.neutralRGB.resize( 3 ); metadata.xyz2rgbMatrix1.resize( 9 ); metadata.xyz2rgbMatrix2.resize( 9 ); @@ -976,13 +949,10 @@ void ImageConverter::prepareIDT_DNG( const OIIO::ImageSpec &imageSpec ) } } - DNGIdt *dng = new DNGIdt( metadata ); - - _IDT_matrix = dng->getDNGIDTMatrix(); + fetch_matrix( descriptor, _IDT_matrix ); // Do not apply CAT for DNG _CAT_matrix.resize( 0 ); - // _CAT_matrix = dng->getDNGCATMatrix(); } void ImageConverter::prepareIDT_nonDNG( const OIIO::ImageSpec &imageSpec ) @@ -994,36 +964,28 @@ void ImageConverter::prepareIDT_nonDNG( const OIIO::ImageSpec &imageSpec ) if ( size == 12 ) { - std::vector> xyz2cam; + cache::TransformDescriptor descriptor; + descriptor.type = cache::TransformEntryType::Mat_from_nonDNG; + descriptor.camera_make = imageSpec["Make"]; + descriptor.camera_model = imageSpec["Model"]; - int idx = 0; - xyz2cam.resize( 4 ); - for ( size_t row = 0; row < 4; row++ ) - { - xyz2cam[row].resize( 4 ); + auto &p = + descriptor.value + .emplace>(); - for ( size_t col = 0; col < 3; col++ ) - { - xyz2cam[row][col] = mat->get_float_indexed( idx++ ); - } - xyz2cam[row][3] = 0; - } - xyz2cam[3][0] = 0; - xyz2cam[3][1] = 0; - xyz2cam[3][2] = 0; - xyz2cam[3][3] = 1; - - auto cam2xyz = invertVM( xyz2cam ); + cache::Vector3 &wb = p.first; + cache::Matrix33 &mat2 = p.second; + int idx = 0; for ( size_t row = 0; row < 3; row++ ) { for ( size_t col = 0; col < 3; col++ ) { - cam2xyz[row][col] /= _WB_mults[row]; + mat2.value[row][col] = mat->get_float_indexed( idx++ ); } } - _IDT_matrix = cam2xyz; //transposeVec(cam2xyz); + fetch_matrix( descriptor, _IDT_matrix ); } } else diff --git a/src/rawtoaces_util2/transform_cache.cpp b/src/rawtoaces_util2/transform_cache.cpp new file mode 100644 index 00000000..8b8addc0 --- /dev/null +++ b/src/rawtoaces_util2/transform_cache.cpp @@ -0,0 +1,303 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include "transform_cache.h" + +#include +#include + +namespace rta +{ +namespace cache +{ + +std::ostream & +operator<<( std::ostream &stream, const TransformDescriptor &descriptor ) +{ + switch ( descriptor.type ) + { + case TransformEntryType::Illum_from_WB: + stream << "illuminant from WB weights:"; + break; + case TransformEntryType::WB_from_Illum: + stream << "WB weights from illuminant:"; + break; + case TransformEntryType::Mat_from_Illum: + stream << "IDT matrix from illuminant:"; + break; + case TransformEntryType::Mat_from_DNG: + stream << "IDT matrix from DNG metadata:"; + break; + case TransformEntryType::Mat_from_nonDNG: + stream << "IDT matrix from non-DNG metadata:"; + break; + } + + stream << std::endl; + stream << " camera make: " << descriptor.camera_make << std::endl; + stream << " camera model: " << descriptor.camera_model << std::endl; + + switch ( descriptor.type ) + { + case TransformEntryType::Illum_from_WB: { + auto &wb = std::get( descriptor.value ); + + stream << " white balance: ("; + stream << wb.value[0] << ", "; + stream << wb.value[1] << ", "; + stream << wb.value[2] << ")"; + break; + } + case TransformEntryType::WB_from_Illum: + case TransformEntryType::Mat_from_Illum: { + auto &illum = std::get( descriptor.value ); + stream << " illuminant: " << illum; + } + case TransformEntryType::Mat_from_DNG: + case TransformEntryType::Mat_from_nonDNG: break; + } + + stream << std::endl; + return stream; +} + +bool TransformDescriptor::operator==( const TransformDescriptor &other ) const +{ + if ( camera_make != other.camera_make ) + return false; + if ( camera_model != other.camera_model ) + return false; + if ( value != other.value ) + return false; + return true; +} + +bool TransformDescriptor::operator==( const CacheEntryDescriptor &other ) const +{ + return false; +} + +size_t TransformDescriptor::map_index() const +{ + return (size_t)type; +} + +std::vector collectDataFiles( const std::string &type ) +{ + std::vector result; + + auto paths = pathsFinder(); + + for ( auto &path: paths.paths ) + { + if ( std::filesystem::is_directory( path ) ) + { + auto type_path = path + "/" + type; + if ( std::filesystem::exists( type_path ) ) + { + auto it = std::filesystem::directory_iterator( type_path ); + for ( auto filename2: it ) + { + auto p = filename2.path(); + if ( filename2.path().extension() == ".json" ) + { + result.push_back( filename2.path().string() ); + } + } + } + } + } + return result; +} + +std::string findFile( const std::string &filename ) +{ + auto paths = pathsFinder(); + + for ( auto &path: paths.paths ) + { + std::string full_path = path + "/" + filename; + if ( std::filesystem::exists( full_path ) ) + return full_path; + } + return ""; +} + +void prepare_solver( + Idt &idt, + const std::string camera_make, + const std::string camera_model, + const std::string illuminant_name, + int verbosity ) +{ + idt.setVerbosity( verbosity ); + + bool found_camera = false; + auto camera_paths = collectDataFiles( "camera" ); + + for ( auto &path: camera_paths ) + { + if ( idt.loadCameraSpst( + path, camera_make.c_str(), camera_model.c_str() ) ) + { + found_camera = true; + break; + } + } + + if ( !found_camera ) + { + std::cerr << "Camera spectral sensitivity data not found for " + << camera_make << " " << camera_model << ". " + << "Please check that the data is available " + << "at the location(s) specified in RAWTOACES_DATA_PATH" + << std::endl; + exit( 1 ); + } + + auto training = findFile( "training/training_spectral.json" ); + if ( training.length() ) + { + idt.loadTrainingData( training ); + } + + auto cmf = findFile( "cmf/cmf_1931.json" ); + if ( cmf.length() ) + { + idt.loadCMF( cmf ); + } + + auto illum_paths = collectDataFiles( "illuminant" ); + int res = idt.loadIlluminant( illum_paths, illuminant_name ); +} + +bool TransformDescriptor::fetch( + TransformCacheEntryData &data, int verbosity ) const +{ + switch ( type ) + { + case TransformEntryType::Illum_from_WB: { + auto &wb1 = std::get( value ); + std::vector wb2( 3 ); + wb2[0] = wb1.value[0]; + wb2[1] = wb1.value[1]; + wb2[2] = wb1.value[2]; + + Idt idt; + prepare_solver( idt, camera_make, camera_model, "na", verbosity ); + idt.chooseIllumSrc( wb2, 0 ); + + WB wb; + auto wb3 = idt.getWB(); + wb.value[0] = wb3[0]; + wb.value[1] = wb3[1]; + wb.value[2] = wb3[2]; + auto illum = idt.getBestIllum(); + + data.value = std::pair( wb, illum.getIllumType() ); + break; + } + case TransformEntryType::WB_from_Illum: { + auto &illum = std::get( value ); + + Idt idt; + prepare_solver( idt, camera_make, camera_model, illum, verbosity ); + idt.chooseIllumType( illum.c_str(), 0 ); + + WB wb; + auto wb2 = idt.getWB(); + wb.value[0] = wb2[0]; + wb.value[1] = wb2[1]; + wb.value[2] = wb2[2]; + auto illum2 = idt.getBestIllum(); + + data.value = + std::pair( wb, illum2.getIllumType() ); + break; + } + case TransformEntryType::Mat_from_Illum: { + auto &illum = std::get( value ); + + Idt idt; + prepare_solver( idt, camera_make, camera_model, illum, verbosity ); + + // TODO: this also calculates the WB mults, which are not needed + // here. This creates a bit of overhead, we may want to decouple + // the selection of illuminant and WB calculation in the core + // library. But this is still faster than running the matrix solver + // everytime. + idt.chooseIllumType( illum.c_str(), 0 ); + + if ( idt.calIDT() ) + { + auto mat1 = idt.getIDT(); + Matrix33 &mat2 = data.value.emplace(); + + for ( size_t i = 0; i < 3; i++ ) + for ( size_t j = 0; j < 3; j++ ) + mat2.value[i][j] = mat1[i][j]; + } + else + return false; + + break; + } + case TransformEntryType::Mat_from_DNG: { + auto &metadata = std::get( value ); + + DNGIdt *dng = new DNGIdt( metadata ); + auto mat1 = dng->getDNGIDTMatrix(); + Matrix33 &mat2 = data.value.emplace(); + + for ( size_t i = 0; i < 3; i++ ) + for ( size_t j = 0; j < 3; j++ ) + mat2.value[i][j] = mat1[i][j]; + break; + } + case TransformEntryType::Mat_from_nonDNG: { + auto p = std::get>( value ); + + Vector3 &wb = p.first; + Matrix33 &mat1 = p.second; + std::vector> xyz2cam; + + xyz2cam.resize( 3 ); + for ( size_t row = 0; row < 3; row++ ) + { + xyz2cam[row].resize( 3 ); + + for ( size_t col = 0; col < 3; col++ ) + { + xyz2cam[row][col] = mat1.value[row][col]; + } + } + + auto cam2xyz = invertVM( xyz2cam ); + + for ( size_t row = 0; row < 3; row++ ) + { + for ( size_t col = 0; col < 3; col++ ) + { + cam2xyz[row][col] /= wb.value[row]; + } + } + + Matrix33 &mat2 = data.value.emplace(); + + for ( size_t i = 0; i < 3; i++ ) + for ( size_t j = 0; j < 3; j++ ) + mat2.value[i][j] = cam2xyz[i][j]; + + break; + } + } + + return true; +} + +template class cache:: + CacheBase; + +} // namespace cache +} // namespace rta diff --git a/src/rawtoaces_util2/transform_cache.h b/src/rawtoaces_util2/transform_cache.h new file mode 100644 index 00000000..fb7b4047 --- /dev/null +++ b/src/rawtoaces_util2/transform_cache.h @@ -0,0 +1,104 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include + +namespace rta +{ +namespace cache +{ + +enum TransformEntryType +{ + Illum_from_WB, + WB_from_Illum, + Mat_from_Illum, + Mat_from_DNG, + Mat_from_nonDNG +}; + +struct Vector3 +{ + double value[3]; + + friend bool operator==( const Vector3 &v1, const Vector3 &v2 ) + { + for ( size_t i = 0; i < 3; i++ ) + if ( v1.value[i] != v2.value[i] ) + return false; + return true; + } + + friend bool operator!=( const Vector3 &v1, const Vector3 &v2 ) + { + return !( v1 == v2 ); + } +}; + +struct Matrix33 +{ + double value[3][3]; + + friend bool operator==( const Matrix33 &m1, const Matrix33 &m2 ) + { + for ( size_t i = 0; i < 3; i++ ) + for ( size_t j = 0; j < 3; j++ ) + if ( m1.value[i][j] != m2.value[i][j] ) + return false; + return true; + } + + friend bool operator!=( const Matrix33 &m1, const Matrix33 &m2 ) + { + return !( m1 == m2 ); + } +}; + +using WB = Vector3; +using Illuminant = std::string; + +class TransformCacheEntryData +{ +public: + std::variant, Matrix33> value; +}; + +class TransformDescriptor : public CacheEntryDescriptor +{ +public: + TransformEntryType type; + std::string camera_make; + std::string camera_model; + std::variant< + WB, // for Illum_from_WB + Illuminant, // for WB_from_Illum and Mat_from_Illum + Metadata, // for Mat_from_DNG + std::pair // for Mat_from_nonDNG + > + value; + + bool operator==( const TransformDescriptor &other ) const; + bool operator==( const CacheEntryDescriptor &other ) const override; + size_t map_index() const override; + bool + fetch( TransformCacheEntryData &data, int verbosity = 0 ) const override; + + friend std::ostream & + operator<<( std::ostream &stream, const TransformDescriptor &descriptor ); + + std::tuple<> construct_entry() const { return std::tuple<>(); }; +}; + +class TransformCache + : public CacheBase +{ +public: + TransformCache() : CacheBase() { name = "RTA Transform cache"; } +}; + +std::vector collectDataFiles( const std::string &type ); +std::string findFile( const std::string &filename ); + +} // namespace cache +} // namespace rta From 1847d454d9dd53092e8e4168f0e42156cde07493 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Tue, 18 Feb 2025 18:07:42 +1300 Subject: [PATCH 15/20] fix build Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/metadata.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/rawtoaces/metadata.h b/include/rawtoaces/metadata.h index 3e77f526..49204b3d 100644 --- a/include/rawtoaces/metadata.h +++ b/include/rawtoaces/metadata.h @@ -5,6 +5,8 @@ #ifndef RTA_METADATA_H_ #define RTA_METADATA_H_ +include + namespace rta { From 29a7f59e3507ea5d14e6b22e1008d8cf45e1268d Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Tue, 18 Feb 2025 18:09:51 +1300 Subject: [PATCH 16/20] fix build Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/metadata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rawtoaces/metadata.h b/include/rawtoaces/metadata.h index 49204b3d..704d0ce3 100644 --- a/include/rawtoaces/metadata.h +++ b/include/rawtoaces/metadata.h @@ -5,7 +5,7 @@ #ifndef RTA_METADATA_H_ #define RTA_METADATA_H_ -include +#include namespace rta { From c64bffdaca6e4e51cc698bc46d4130899f0e2afe Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Tue, 18 Feb 2025 21:45:08 +1300 Subject: [PATCH 17/20] replace boost::json with nlohmann_json Signed-off-by: Anton Dukhovnikov --- .github/workflows/ci.yml | 2 +- build_scripts/install_deps.bash | 2 +- build_scripts/install_deps_linux.bash | 3 +- build_scripts/install_deps_mac.bash | 2 +- build_scripts/install_deps_windows.bash | 3 +- configure.cmake | 1 + include/rawtoaces/define.h | 9 ++- src/rawtoaces_idt/CMakeLists.txt | 3 +- src/rawtoaces_idt/rta.cpp | 95 +++++++++++++------------ 9 files changed, 66 insertions(+), 54 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c02fc34b..071a852e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: shell: bash run: | build_scripts/install_aces_container.bash - sudo yum install --setopt=tsflags=nodocs -y eigen3-devel ceres-solver-devel LibRaw-devel + sudo yum install --setopt=tsflags=nodocs -y eigen3-devel ceres-solver-devel LibRaw-devel json-devel - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. diff --git a/build_scripts/install_deps.bash b/build_scripts/install_deps.bash index d9519954..68b1b245 100755 --- a/build_scripts/install_deps.bash +++ b/build_scripts/install_deps.bash @@ -11,4 +11,4 @@ time sudo apt-get -q -f install -y \ libopenimageio-dev \ libboost-dev libboost-thread-dev libboost-filesystem-dev \ libboost-test-dev \ - libraw-dev libceres-dev + libraw-dev libceres-dev nlohmann-json-dev diff --git a/build_scripts/install_deps_linux.bash b/build_scripts/install_deps_linux.bash index a72b1d8c..0a4e726b 100755 --- a/build_scripts/install_deps_linux.bash +++ b/build_scripts/install_deps_linux.bash @@ -12,4 +12,5 @@ time sudo apt-get -q -f install -y \ libraw-dev libceres-dev \ libopencv-dev \ openimageio-tools \ - libopenimageio-dev + libopenimageio-dev \ + nlohmann-json3-dev diff --git a/build_scripts/install_deps_mac.bash b/build_scripts/install_deps_mac.bash index 15d4f440..f24b2a33 100755 --- a/build_scripts/install_deps_mac.bash +++ b/build_scripts/install_deps_mac.bash @@ -2,4 +2,4 @@ set -ex -brew install ceres-solver imath openexr libraw boost openimageio +brew install ceres-solver imath openexr libraw boost openimageio nlohmann-json diff --git a/build_scripts/install_deps_windows.bash b/build_scripts/install_deps_windows.bash index 9743b622..1de21736 100755 --- a/build_scripts/install_deps_windows.bash +++ b/build_scripts/install_deps_windows.bash @@ -11,4 +11,5 @@ vcpkg install \ boost-foreach:x64-windows \ boost-filesystem:x64-windows \ boost-test:x64-windows \ - boost-property-tree:x64-windows + boost-property-tree:x64-windows \ + nlohmann-json:x64-windows diff --git a/configure.cmake b/configure.cmake index f37d02fb..7086845c 100644 --- a/configure.cmake +++ b/configure.cmake @@ -7,6 +7,7 @@ find_package ( OpenImageIO CONFIG REQUIRED ) find_package ( AcesContainer CONFIG REQUIRED ) find_package ( Eigen3 CONFIG REQUIRED ) find_package ( Imath CONFIG REQUIRED ) +find_package ( nlohmann_json CONFIG REQUIRED ) find_package ( Ceres REQUIRED ) find_package ( Boost REQUIRED COMPONENTS diff --git a/include/rawtoaces/define.h b/include/rawtoaces/define.h index a3e4f2fd..ab7e3182 100644 --- a/include/rawtoaces/define.h +++ b/include/rawtoaces/define.h @@ -359,10 +359,13 @@ inline vector openDir( string path = "." ) { vector paths; - for ( auto &i: filesystem::directory_iterator( path ) ) + if ( filesystem::exists( path ) ) { - if ( i.status().type() != filesystem::file_type::directory ) - paths.push_back( i.path().string() ); + for ( auto &i: filesystem::directory_iterator( path ) ) + { + if ( i.status().type() != filesystem::file_type::directory ) + paths.push_back( i.path().string() ); + } } return paths; diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index f93c1092..6ea3d722 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -21,8 +21,7 @@ target_link_libraries( PRIVATE Boost::boost Boost::system - Imath::Imath - Imath::ImathConfig + nlohmann_json::nlohmann_json ) # Ceres is also used in rawtoaces_util and rawtoaces_util2, so setting it public here diff --git a/src/rawtoaces_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 30bcf0c5..b1e3dd3c 100644 --- a/src/rawtoaces_idt/rta.cpp +++ b/src/rawtoaces_idt/rta.cpp @@ -55,15 +55,14 @@ #include #include -#include -#include -#include +#include +#include -using namespace boost::property_tree; using namespace ceres; namespace rta { + Illum::Illum() { _inc = 5; @@ -146,12 +145,10 @@ int Illum::readSPD( const string &path, const string &type ) try { - // using libraries from boost::property_tree - ptree pt; - read_json( path, pt ); - - const string stype = pt.get( "header.illuminant" ); - if ( type.compare( stype ) != 0 && type.compare( "na" ) != 0 ) + std::ifstream i( path ); + nlohmann::json data = nlohmann::json::parse( i ); + const string stype = data["header"]["illuminant"]; + if ( type != stype && type != "na" ) return 0; _type = stype; @@ -159,10 +156,11 @@ int Illum::readSPD( const string &path, const string &type ) vector wavs; int dis; - BOOST_FOREACH ( - ptree::value_type &row, pt.get_child( "spectral_data.data.main" ) ) + nlohmann::json main_data = data["spectral_data"]["data"]["main"]; + for ( auto &[index, values]: main_data.items() ) { - wavs.push_back( atoi( ( row.first ).c_str() ) ); + std::string row = index; + wavs.push_back( stoi( row ) ); if ( wavs.size() == 2 ) dis = wavs[1] - wavs[0]; @@ -183,11 +181,11 @@ int Illum::readSPD( const string &path, const string &type ) else if ( wavs[wavs.size() - 1] > 780 ) break; - BOOST_FOREACH ( ptree::value_type &cell, row.second ) + for ( auto j: values ) { - _data.push_back( cell.second.get_value() ); + _data.push_back( (double)j ); if ( wavs[wavs.size() - 1] == 550 ) - _index = cell.second.get_value(); + _index = (double)j; } // printf ( "\"%i\": [ %18.13f ], \n", @@ -599,26 +597,30 @@ int Spst::loadSpst( const string &path, const char *maker, const char *model ) try { - ptree pt; - read_json( path, pt ); + std::ifstream i( path ); + nlohmann::json data = nlohmann::json::parse( i ); - string cmaker = pt.get( "header.manufacturer" ); - if ( maker != nullptr && cmp_str( maker, cmaker.c_str() ) ) + const string camera_make = data["header"]["manufacturer"]; + if ( camera_make.empty() || cmp_str( camera_make.c_str(), maker ) != 0 ) return 0; - setBrand( cmaker.c_str() ); - string cmodel = pt.get( "header.model" ); - if ( model != nullptr && cmp_str( model, cmodel.c_str() ) ) + setBrand( camera_make.c_str() ); + + const string camera_model = data["header"]["model"]; + if ( camera_model.empty() || + cmp_str( camera_model.c_str(), model ) != 0 ) return 0; - setModel( cmodel.c_str() ); + + setModel( camera_model.c_str() ); vector wavs; int inc; - BOOST_FOREACH ( - ptree::value_type &row, pt.get_child( "spectral_data.data.main" ) ) + nlohmann::json main_data = data["spectral_data"]["data"]["main"]; + for ( auto &[index, values]: main_data.items() ) { - wavs.push_back( atoi( ( row.first ).c_str() ) ); + std::string row = index; + wavs.push_back( stoi( row ) ); if ( wavs.size() == 2 ) inc = wavs[1] - wavs[0]; @@ -640,8 +642,8 @@ int Spst::loadSpst( const string &path, const char *maker, const char *model ) break; vector data; - BOOST_FOREACH ( ptree::value_type &cell, row.second ) - data.push_back( cell.second.get_value() ); + for ( auto j: values ) + data.push_back( (double)j ); // ensure there are three components assert( data.size() == 3 ); @@ -980,19 +982,22 @@ void Idt::loadTrainingData( const string &path ) try { - ptree pt; - read_json( path, pt ); + std::ifstream stream( path ); + nlohmann::json data = nlohmann::json::parse( stream ); int i = 0; - BOOST_FOREACH ( - ptree::value_type &row, pt.get_child( "spectral_data.data.main" ) ) + nlohmann::json main_data = data["spectral_data"]["data"]["main"]; + for ( auto &[index, values]: main_data.items() ) { - _trainingSpec[i]._wl = atoi( ( row.first ).c_str() ); + std::string row = index; + _trainingSpec[i]._wl = stoi( row ); - BOOST_FOREACH ( ptree::value_type &cell, row.second ) - _trainingSpec[i]._data.push_back( - cell.second.get_value() ); + for ( auto j: values ) + { + double d = j; + _trainingSpec[i]._data.push_back( d ); + } assert( _trainingSpec[i]._data.size() == 190 ); @@ -1021,14 +1026,16 @@ void Idt::loadCMF( const string &path ) try { - ptree pt; - read_json( path, pt ); + std::ifstream stream( path ); + nlohmann::json data = nlohmann::json::parse( stream ); int i = 0; - BOOST_FOREACH ( - ptree::value_type &row, pt.get_child( "spectral_data.data.main" ) ) + + nlohmann::json main_data = data["spectral_data"]["data"]["main"]; + for ( auto &[index, values]: main_data.items() ) { - int wl = atoi( ( row.first ).c_str() ); + std::string row = index; + int wl = stoi( row ); if ( wl < 380 || wl % 5 ) continue; @@ -1038,8 +1045,8 @@ void Idt::loadCMF( const string &path ) _cmf[i]._wl = wl; vector data; - BOOST_FOREACH ( ptree::value_type &cell, row.second ) - data.push_back( cell.second.get_value() ); + for ( auto j: values ) + data.push_back( (double)j ); assert( data.size() == 3 ); _cmf[i]._xbar = data[0]; From 72466a0bbcc2f691a655d8128df9449cebea7cc6 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Wed, 19 Feb 2025 13:26:54 +1300 Subject: [PATCH 18/20] replace boost::unittest with OIIO::unittest Signed-off-by: Anton Dukhovnikov --- build_scripts/install_deps.bash | 2 - build_scripts/install_deps_linux.bash | 2 - build_scripts/install_deps_mac.bash | 2 +- build_scripts/install_deps_windows.bash | 5 - configure.cmake | 6 - src/rawtoaces_idt/CMakeLists.txt | 2 - src/rawtoaces_util/CMakeLists.txt | 1 - src/rawtoaces_util/acesrender.cpp | 25 +- unittest/CMakeLists.txt | 31 +-- unittest/testDNGIdt.cpp | 63 +++-- unittest/testIDT.cpp | 295 ++++++++++++++---------- unittest/testIllum.cpp | 68 +++--- unittest/testLogic.cpp | 27 ++- unittest/testMath.cpp | 184 +++++++++------ unittest/testMisc.cpp | 75 +++--- unittest/testSpst.cpp | 140 ++++++----- 16 files changed, 515 insertions(+), 413 deletions(-) diff --git a/build_scripts/install_deps.bash b/build_scripts/install_deps.bash index 68b1b245..a3444ae3 100755 --- a/build_scripts/install_deps.bash +++ b/build_scripts/install_deps.bash @@ -9,6 +9,4 @@ time sudo apt-get update time sudo apt-get -q -f install -y \ libunwind-dev libilmbase-dev libopenexr-dev \ libopenimageio-dev \ - libboost-dev libboost-thread-dev libboost-filesystem-dev \ - libboost-test-dev \ libraw-dev libceres-dev nlohmann-json-dev diff --git a/build_scripts/install_deps_linux.bash b/build_scripts/install_deps_linux.bash index 0a4e726b..a79ea705 100755 --- a/build_scripts/install_deps_linux.bash +++ b/build_scripts/install_deps_linux.bash @@ -7,8 +7,6 @@ time sudo apt-get update time sudo apt-get -q -f install -y \ libunwind-dev \ libimath-dev libopenexr-dev \ - libboost-dev libboost-filesystem-dev \ - libboost-test-dev \ libraw-dev libceres-dev \ libopencv-dev \ openimageio-tools \ diff --git a/build_scripts/install_deps_mac.bash b/build_scripts/install_deps_mac.bash index f24b2a33..3d695c2d 100755 --- a/build_scripts/install_deps_mac.bash +++ b/build_scripts/install_deps_mac.bash @@ -2,4 +2,4 @@ set -ex -brew install ceres-solver imath openexr libraw boost openimageio nlohmann-json +brew install ceres-solver imath openexr libraw openimageio nlohmann-json diff --git a/build_scripts/install_deps_windows.bash b/build_scripts/install_deps_windows.bash index 1de21736..8c59b371 100755 --- a/build_scripts/install_deps_windows.bash +++ b/build_scripts/install_deps_windows.bash @@ -7,9 +7,4 @@ vcpkg install \ ceres:x64-windows \ imath:x64-windows \ openimageio:x64-windows \ - boost-system:x64-windows \ - boost-foreach:x64-windows \ - boost-filesystem:x64-windows \ - boost-test:x64-windows \ - boost-property-tree:x64-windows \ nlohmann-json:x64-windows diff --git a/configure.cmake b/configure.cmake index 7086845c..1b8d4716 100644 --- a/configure.cmake +++ b/configure.cmake @@ -9,12 +9,6 @@ find_package ( Eigen3 CONFIG REQUIRED ) find_package ( Imath CONFIG REQUIRED ) find_package ( nlohmann_json CONFIG REQUIRED ) find_package ( Ceres REQUIRED ) -find_package ( Boost REQUIRED - COMPONENTS - system - filesystem - unit_test_framework -) find_package (libraw CONFIG QUIET ) diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index 6ea3d722..54895feb 100644 --- a/src/rawtoaces_idt/CMakeLists.txt +++ b/src/rawtoaces_idt/CMakeLists.txt @@ -19,8 +19,6 @@ target_link_libraries( PUBLIC Eigen3::Eigen PRIVATE - Boost::boost - Boost::system nlohmann_json::nlohmann_json ) diff --git a/src/rawtoaces_util/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index 50e1e031..1c337b70 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -22,7 +22,6 @@ target_link_libraries ( ${RAWTOACESLIB} PUBLIC ${RAWTOACESIDTLIB} PRIVATE - Boost::filesystem Imath::Imath Imath::ImathConfig ) diff --git a/src/rawtoaces_util/acesrender.cpp b/src/rawtoaces_util/acesrender.cpp index c7a2a0ed..efb03c75 100644 --- a/src/rawtoaces_util/acesrender.cpp +++ b/src/rawtoaces_util/acesrender.cpp @@ -56,9 +56,7 @@ #include #include -#include -#include -#include +#include #include @@ -68,9 +66,9 @@ #endif using namespace std; -using namespace boost::property_tree; -#include +#include +#include // ===================================================================== // Prepare the matching between string flags and single character flag @@ -732,9 +730,9 @@ void AcesRender::gatherSupportedIllums() string path( *file ); try { - ptree pt; - read_json( path, pt ); - string tmp = pt.get( "header.illuminant" ); + std::ifstream i( path ); + nlohmann::json data = nlohmann::json::parse( i ); + const string tmp = data["header"]["illuminant"]; if ( record.find( tmp ) != record.end() ) continue; @@ -780,10 +778,11 @@ void AcesRender::gatherSupportedCameras() string path( *file ); try { - ptree pt; - read_json( path, pt ); - string tmp = pt.get( "header.manufacturer" ); - tmp += ( " / " + pt.get( "header.model" ) ); + std::ifstream i( path ); + nlohmann::json data = nlohmann::json::parse( i ); + const string make = data["header"]["manufacturer"]; + const string model = data["header"]["model"]; + string tmp = make + "/" + model; if ( record.find( tmp ) != record.end() ) continue; @@ -1004,7 +1003,7 @@ vector findFiles( string filePath, vector searchPaths ) { string path = i + "/" + filePath; - if ( boost::filesystem::exists( path ) ) + if ( std::filesystem::exists( path ) ) foundFiles.push_back( path ); } diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index 6743a305..77e093c6 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 3.10) -add_definitions (-DBOOST_TEST_DYN_LINK) add_executable ( Test_Spst @@ -13,9 +12,7 @@ target_link_libraries( Test_Spst PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -29,11 +26,7 @@ target_link_libraries( Test_IDT PUBLIC ${RAWTOACESLIB} - Imath::Imath - Imath::ImathConfig - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -47,9 +40,7 @@ target_link_libraries( Test_Illum PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -63,9 +54,7 @@ target_link_libraries( Test_DNGIdt PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) if ( LIBRAW_CONFIG_FOUND ) @@ -87,9 +76,7 @@ target_link_libraries( Test_Math PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -103,9 +90,7 @@ target_link_libraries( Test_Logic PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -119,9 +104,7 @@ target_link_libraries( Test_Misc PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) diff --git a/unittest/testDNGIdt.cpp b/unittest/testDNGIdt.cpp index 0d001398..2a076c35 100644 --- a/unittest/testDNGIdt.cpp +++ b/unittest/testDNGIdt.cpp @@ -52,10 +52,7 @@ // THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. /////////////////////////////////////////////////////////////////////////// -#define BOOST_TEST_MAIN -#include -#include -#include +#include #include @@ -65,7 +62,7 @@ using namespace std; using namespace rta; -BOOST_AUTO_TEST_CASE( TestIDT_CcttoMired ) +void testIDT_CcttoMired() { DNGIdt *di = new DNGIdt(); @@ -73,10 +70,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_CcttoMired ) double mired = di->ccttoMired( cct ); delete di; - BOOST_CHECK_CLOSE( mired, 153.8461538462, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( mired, 153.8461538462, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_RobertsonLength ) +void testIDT_RobertsonLength() { DNGIdt *di = new DNGIdt(); @@ -88,12 +85,12 @@ BOOST_AUTO_TEST_CASE( TestIDT_RobertsonLength ) double rLength = di->robertsonLength( uvVector, uvtVector ); delete di; - BOOST_CHECK_CLOSE( rLength, 0.060234937, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rLength, 0.060234937, 1e-5 ); }; DNGIdt *openFile( std::string path, LibRaw &rawProcessor ) { - boost::filesystem::path pathToRaw = boost::filesystem::absolute( + std::filesystem::path pathToRaw = std::filesystem::absolute( "../../unittest/materials/blackmagic_cinema_camera_cinemadng.dng" ); int ret = rawProcessor.open_file( ( pathToRaw.string() ).c_str() ); ret = rawProcessor.unpack(); @@ -140,17 +137,17 @@ DNGIdt *openFile( std::string path, LibRaw &rawProcessor ) return new DNGIdt( metadata ); } -BOOST_AUTO_TEST_CASE( TestIDT_LightSourceToColorTemp ) +void testIDT_LightSourceToColorTemp() { DNGIdt *di = new DNGIdt(); unsigned short tag = 17; double ct = di->lightSourceToColorTemp( tag ); delete di; - BOOST_CHECK_CLOSE( ct, 2856.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( ct, 2856.0, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_XYZToColorTemperature ) +void testIDT_XYZToColorTemperature() { LibRaw rawProcessor; DNGIdt *di = openFile( @@ -163,10 +160,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_XYZToColorTemperature ) rawProcessor.recycle(); delete di; - BOOST_CHECK_CLOSE( cct, 5564.6648479019, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( cct, 5564.6648479019, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_XYZtoCameraWeightedMatrix ) +void testIDT_XYZtoCameraWeightedMatrix() { LibRaw rawProcessor; DNGIdt *di = openFile( @@ -183,10 +180,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_XYZtoCameraWeightedMatrix ) delete di; FORI( countSize( matrix ) ) - BOOST_CHECK_CLOSE( result[i], matrix[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( result[i], matrix[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_FindXYZtoCameraMtx ) +void testIDT_FindXYZtoCameraMtx() { LibRaw rawProcessor; DNGIdt *di = openFile( @@ -204,10 +201,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_FindXYZtoCameraMtx ) delete di; FORI( countSize( matrix ) ) - BOOST_CHECK_CLOSE( result[i], matrix[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( result[i], matrix[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_ColorTemperatureToXYZ ) +void testIDT_ColorTemperatureToXYZ() { DNGIdt *di = new DNGIdt(); @@ -217,10 +214,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_ColorTemperatureToXYZ ) delete di; FORI( countSize( XYZ ) ) - BOOST_CHECK_CLOSE( result[i], XYZ[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( result[i], XYZ[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_MatrixRGBtoXYZ ) +void testIDT_MatrixRGBtoXYZ() { DNGIdt *di = new DNGIdt(); @@ -231,10 +228,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_MatrixRGBtoXYZ ) delete di; FORI( countSize( XYZ ) ) - BOOST_CHECK_CLOSE( result[i], XYZ[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( result[i], XYZ[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_GetDNGCATMatrix ) +void testIDT_GetDNGCATMatrix() { LibRaw rawProcessor; DNGIdt *di = openFile( @@ -250,10 +247,10 @@ BOOST_AUTO_TEST_CASE( TestIDT_GetDNGCATMatrix ) delete di; FORIJ( 3, 3 ) - BOOST_CHECK_CLOSE( result[i][j], matrix[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( result[i][j], matrix[i][j], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_GetDNGIDTMatrix ) +void testIDT_GetDNGIDTMatrix() { LibRaw rawProcessor; DNGIdt *di = openFile( @@ -269,5 +266,21 @@ BOOST_AUTO_TEST_CASE( TestIDT_GetDNGIDTMatrix ) delete di; FORIJ( 3, 3 ) - BOOST_CHECK_CLOSE( result[i][j], matrix[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( result[i][j], matrix[i][j], 1e-5 ); }; + +int main( int, char ** ) +{ + testIDT_CcttoMired(); + testIDT_RobertsonLength(); + testIDT_LightSourceToColorTemp(); + testIDT_XYZToColorTemperature(); + testIDT_XYZtoCameraWeightedMatrix(); + testIDT_FindXYZtoCameraMtx(); + testIDT_ColorTemperatureToXYZ(); + testIDT_MatrixRGBtoXYZ(); + testIDT_GetDNGCATMatrix(); + testIDT_GetDNGIDTMatrix(); + + return unit_test_failures; +} diff --git a/unittest/testIDT.cpp b/unittest/testIDT.cpp index 96923a5e..aa6f1f8c 100644 --- a/unittest/testIDT.cpp +++ b/unittest/testIDT.cpp @@ -57,10 +57,7 @@ # include #endif -#define BOOST_TEST_MAIN -#include -#include -#include +#include #include #include @@ -68,7 +65,7 @@ using namespace std; using namespace rta; -BOOST_AUTO_TEST_CASE( TestIDT_DataAccess ) +void testIDT_DataAccess() { char *brand1, *brand2, *brand3; char *model1, *model2, *model3; @@ -119,33 +116,33 @@ BOOST_AUTO_TEST_CASE( TestIDT_DataAccess ) spstobject1->setWLIncrement( 5 ); spstobject1->setSensitivity( rgbsen1 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject1->getBrand(), "" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject1->getModel(), "" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject1->getWLIncrement() ), 5 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject1->getBrand(), "" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject1->getModel(), "" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject1->getWLIncrement() ), 5 ); vector rgbsen_cp = spstobject1->getSensitivity(); FORI( 81 ) { - BOOST_CHECK_CLOSE( rgbsen_cp[i]._RSen, 1.00000001, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._BSen, 0.999999999, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._RSen, 1.00000001, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._BSen, 0.999999999, 1e-5 ); } Spst spstobject2( brand2, model2, 10, rgbsen2 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject2.getBrand(), "b2" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject2.getModel(), "m2" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject2.getWLIncrement() ), 10 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject2.getBrand(), "b2" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject2.getModel(), "m2" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject2.getWLIncrement() ), 10 ); rgbsen_cp.clear(); rgbsen_cp = spstobject2.getSensitivity(); FORI( 81 ) { - BOOST_CHECK_CLOSE( rgbsen_cp[i]._RSen, 1.0, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._BSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._RSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._BSen, 1.0, 1e-5 ); } Spst spstobject3( spstobject2 ); @@ -155,18 +152,18 @@ BOOST_AUTO_TEST_CASE( TestIDT_DataAccess ) spstobject3.setWLIncrement( 20 ); spstobject3.setSensitivity( rgbsen3 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject3.getBrand(), "brand3" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject3.getModel(), "model3" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject3.getWLIncrement() ), 20 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject3.getBrand(), "brand3" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject3.getModel(), "model3" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject3.getWLIncrement() ), 20 ); rgbsen_cp.clear(); rgbsen_cp = spstobject3.getSensitivity(); FORI( 81 ) { - BOOST_CHECK_CLOSE( rgbsen_cp[i]._RSen, -0.9999999999999, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._GSen, 1e-3, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._BSen, 1.0000000000001, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._RSen, -0.9999999999999, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._GSen, 1e-3, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._BSen, 1.0000000000001, 1e-5 ); } // free ( model1 ); @@ -177,7 +174,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_DataAccess ) // free ( brand3 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_LoadCameraSpst ) +void testIDT_LoadCameraSpst() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -191,8 +188,8 @@ BOOST_AUTO_TEST_CASE( TestIDT_LoadCameraSpst ) memcpy( model, "d21", len ); model[len] = '\0'; - Idt *idtTest = new Idt(); - boost::filesystem::path absolutePath = boost::filesystem::absolute( + Idt *idtTest = new Idt(); + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/camera/arri_d21_380_780_5.json" ); idtTest->loadCameraSpst( absolutePath.string(), brand, model ); @@ -282,29 +279,39 @@ BOOST_AUTO_TEST_CASE( TestIDT_LoadCameraSpst ) { 0.000149065, 7.26E-05, 5.84E-05 }, { 3.71E-05, 0.0, 2.70E-06 } }; - BOOST_CHECK_EQUAL( int( rgbsenTest.size() ), 81 ); - BOOST_CHECK_EQUAL( std::strcmp( spstTest.getBrand(), "arri" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstTest.getModel(), "d21" ), 0 ); - BOOST_CHECK_EQUAL( int( spstTest.getWLIncrement() ), 5 ); + OIIO_CHECK_EQUAL( int( rgbsenTest.size() ), 81 ); + OIIO_CHECK_EQUAL( std::strcmp( spstTest.getBrand(), "arri" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstTest.getModel(), "d21" ), 0 ); + OIIO_CHECK_EQUAL( int( spstTest.getWLIncrement() ), 5 ); FORI( 81 ) { - BOOST_CHECK_CLOSE( double( rgbsenTest[i]._RSen ), rgb[i][0], 1e-5 ); - BOOST_CHECK_CLOSE( double( rgbsenTest[i]._GSen ), rgb[i][1], 1e-5 ); - BOOST_CHECK_CLOSE( double( rgbsenTest[i]._BSen ), rgb[i][2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + double( rgbsenTest[i]._RSen ), rgb[i][0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + double( rgbsenTest[i]._GSen ), rgb[i][1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + double( rgbsenTest[i]._BSen ), rgb[i][2], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( TestIDT_LoadIlluminant ) +void testIDT_LoadIlluminant() { Idt *idtTest = new Idt(); - vector illumPaths; - boost::filesystem::path absolutePath = boost::filesystem::absolute( + vector illumPaths; + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); illumPaths.push_back( absolutePath.string() ); - BOOST_CHECK_NO_THROW( idtTest->loadIlluminant( illumPaths, "iso7589" ) ); + try + { + idtTest->loadIlluminant( illumPaths, "iso7589" ); + } + catch ( ... ) + { + OIIO_CHECK_ASSERT( 0 ); + } Illum illumTest = ( idtTest->getIlluminants() )[0]; @@ -332,24 +339,31 @@ BOOST_AUTO_TEST_CASE( TestIDT_LoadIlluminant ) 1.0000000000000 }; - BOOST_CHECK_EQUAL( illumTest.getIllumType(), "iso7589" ); - BOOST_CHECK_EQUAL( illumTest.getIllumInc(), 5 ); + OIIO_CHECK_EQUAL( illumTest.getIllumType(), "iso7589" ); + OIIO_CHECK_EQUAL( illumTest.getIllumInc(), 5 ); vector illumTestData = illumTest.getIllumData(); - BOOST_CHECK_EQUAL( int( illumTestData.size() ), 81 ); - FORI( 81 ) BOOST_CHECK_CLOSE( illumTestData[i], iso7589[i], 1e-5 ); + OIIO_CHECK_EQUAL( int( illumTestData.size() ), 81 ); + FORI( 81 ) OIIO_CHECK_EQUAL_THRESH( illumTestData[i], iso7589[i], 1e-5 ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_LoadTrainingData ) +void testIDT_LoadTrainingData() { Idt *idtTest = new Idt(); - boost::filesystem::path absolutePath = boost::filesystem::absolute( + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/training/training_spectral.json" ); - BOOST_CHECK_NO_THROW( idtTest->loadTrainingData( absolutePath.string() ) ); + try + { + idtTest->loadTrainingData( absolutePath.string() ); + } + catch ( ... ) + { + OIIO_CHECK_ASSERT( 0 ); + } const vector TS_test = idtTest->getTrainingSpec(); @@ -437,22 +451,30 @@ BOOST_AUTO_TEST_CASE( TestIDT_LoadTrainingData ) FORI( 81 ) { - BOOST_CHECK_CLOSE( TS[i][0], TS_test[i]._data[0], 1e-5 ); - BOOST_CHECK_CLOSE( TS[i][1], TS_test[i]._data[1], 1e-5 ); - BOOST_CHECK_CLOSE( TS[i][2], TS_test[i]._data[2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( TS[i][0], TS_test[i]._data[0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( TS[i][1], TS_test[i]._data[1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( TS[i][2], TS_test[i]._data[2], 1e-5 ); } delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_LoadCMF ) +void testIDT_LoadCMF() { Idt *idtTest = new Idt(); - boost::filesystem::path absolutePath = - boost::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); + std::filesystem::path absolutePath = + std::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); + + try + { + idtTest->loadCMF( absolutePath.string() ); + } + catch ( ... ) + { + OIIO_CHECK_ASSERT( 0 ); + } - BOOST_CHECK_NO_THROW( idtTest->loadCMF( absolutePath.string() ) ); vector cmfTest = idtTest->getCMF(); double cmf[401][3] = { { 0.001368, 3.90E-05, 0.006450001 }, @@ -859,28 +881,28 @@ BOOST_AUTO_TEST_CASE( TestIDT_LoadCMF ) FORI( 81 ) { - BOOST_CHECK_CLOSE( cmfTest[i]._xbar, cmf[i * 5][0], 1e-5 ); - BOOST_CHECK_CLOSE( cmfTest[i]._ybar, cmf[i * 5][1], 1e-5 ); - BOOST_CHECK_CLOSE( cmfTest[i]._zbar, cmf[i * 5][2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( cmfTest[i]._xbar, cmf[i * 5][0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( cmfTest[i]._ybar, cmf[i * 5][1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( cmfTest[i]._zbar, cmf[i * 5][2], 1e-5 ); } delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_Verbose ) +void testIDT_Verbose() { Idt *idtTest = new Idt(); idtTest->setVerbosity( 1 ); - BOOST_CHECK_EQUAL( idtTest->getVerbosity(), 1 ); + OIIO_CHECK_EQUAL( idtTest->getVerbosity(), 1 ); idtTest->setVerbosity( 3 ); - BOOST_CHECK_EQUAL( idtTest->getVerbosity(), 3 ); + OIIO_CHECK_EQUAL( idtTest->getVerbosity(), 3 ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_scaleLSC ) +void testIDT_scaleLSC() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -897,11 +919,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_scaleLSC ) Idt *idtTest = new Idt(); Illum *illumTest = new Illum(); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); illumTest->readSPD( pathIllum.string(), "iso7589" ); - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); @@ -933,10 +955,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_scaleLSC ) const vector illumDataScaled = illumTest->getIllumData(); - BOOST_CHECK_EQUAL( illumDataScaled.size(), 81 ); - BOOST_CHECK_EQUAL( illumTest->getIllumType(), "iso7589" ); - BOOST_CHECK_EQUAL( illumTest->getIllumInc(), 5 ); - FORI( 81 ) BOOST_CHECK_CLOSE( illumDataScaled[i], scaledIllum[i], 1e-5 ); + OIIO_CHECK_EQUAL( illumDataScaled.size(), 81 ); + OIIO_CHECK_EQUAL( illumTest->getIllumType(), "iso7589" ); + OIIO_CHECK_EQUAL( illumTest->getIllumInc(), 5 ); + FORI( 81 ) + OIIO_CHECK_EQUAL_THRESH( illumDataScaled[i], scaledIllum[i], 1e-5 ); free( model ); free( brand ); @@ -944,7 +967,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_scaleLSC ) delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CalCM ) +void testIDT_CalCM() { Idt *idtTest = new Idt(); @@ -960,11 +983,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalCM ) memcpy( model, "d21", len ); model[len] = '\0'; - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/arri_d21_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); @@ -996,7 +1019,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalCM ) FORI( 81 ) { - FORI( 3 ) BOOST_CHECK_CLOSE( CM[i], CM_test[i], 1e-5 ); + FORI( 3 ) OIIO_CHECK_EQUAL_THRESH( CM[i], CM_test[i], 1e-5 ); } free( model ); @@ -1004,7 +1027,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalCM ) delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CalWB ) +void testIDT_CalWB() { Idt *idtTest = new Idt(); @@ -1020,11 +1043,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalWB ) memcpy( model, "d200", len ); model[len] = '\0'; - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); @@ -1036,7 +1059,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalWB ) double WB[3] = { 1.1397265, 1.0000000, 2.3240151 }; FORI( WB_test.size() ) { - BOOST_CHECK_CLOSE( WB[i], WB_test[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( WB[i], WB_test[i], 1e-5 ); } free( model ); @@ -1044,14 +1067,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalWB ) delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_SetIlluminants ) +void testIDT_SetIlluminants() { Idt *idtTest = new Idt(); Illum *illumTest1 = new Illum(); Illum *illumTest2 = new Illum( "d50" ); Illum *illumTest3 = new Illum( "3200k" ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); illumTest1->readSPD( pathIllum.string(), "iso7589" ); @@ -1064,9 +1087,9 @@ BOOST_AUTO_TEST_CASE( TestIDT_SetIlluminants ) vector illumTests = idtTest->getIlluminants(); - BOOST_CHECK_EQUAL( illumTests[0].getIllumType(), "iso7589" ); - BOOST_CHECK_EQUAL( illumTests[1].getIllumType(), "d50" ); - BOOST_CHECK_EQUAL( illumTests[2].getIllumType(), "3200k" ); + OIIO_CHECK_EQUAL( illumTests[0].getIllumType(), "iso7589" ); + OIIO_CHECK_EQUAL( illumTests[1].getIllumType(), "d50" ); + OIIO_CHECK_EQUAL( illumTests[2].getIllumType(), "3200k" ); const double daylight[81] = { 24.4978949755877, 27.1891380970612, 29.8803812185346, @@ -1123,8 +1146,9 @@ BOOST_AUTO_TEST_CASE( TestIDT_SetIlluminants ) FORI( blackbody_Test.size() ) { - BOOST_CHECK_CLOSE( daylight[i], daylight_Test[i], 1e-5 ); - BOOST_CHECK_CLOSE( blackbody[i], blackbody_Test[i] * 1e-12, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( daylight[i], daylight_Test[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + blackbody[i], blackbody_Test[i] * 1e-12, 1e-5 ); } delete idtTest; @@ -1133,7 +1157,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_SetIlluminants ) delete illumTest3; }; -BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumSrc ) +void testIDT_ChooseIllumSrc() { Idt *idtTest = new Idt(); @@ -1148,12 +1172,12 @@ BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumSrc ) memcpy( model, "d200", len ); model[len] = '\0'; - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = - boost::filesystem::absolute( "../../data/illuminant" ); + std::filesystem::path pathIllum = + std::filesystem::absolute( "../../data/illuminant" ); vector iFiles = openDir( pathIllum.string() ); vector illumPaths; @@ -1167,7 +1191,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumSrc ) } idtTest->loadIlluminant( illumPaths, "na" ); - boost::filesystem::path absolutePath = boost::filesystem::absolute( + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( absolutePath.string() ); @@ -1199,16 +1223,16 @@ BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumSrc ) 0.0523097995 }; - BOOST_CHECK_EQUAL( illumType_Test, "d45" ); + OIIO_CHECK_EQUAL( illumType_Test, "d45" ); FORI( illumData_Test.size() ) - BOOST_CHECK_CLOSE( illumData[i], illumData_Test[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( illumData[i], illumData_Test[i], 1e-5 ); free( model ); free( brand ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumType ) +void testIDT_ChooseIllumType() { Idt *idtTest = new Idt(); @@ -1223,12 +1247,12 @@ BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumType ) memcpy( model, "d200", len ); model[len] = '\0'; - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = - boost::filesystem::absolute( "../../data/illuminant" ); + std::filesystem::path pathIllum = + std::filesystem::absolute( "../../data/illuminant" ); vector iFiles = openDir( pathIllum.string() ); vector illumPaths; @@ -1242,7 +1266,7 @@ BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumType ) } idtTest->loadIlluminant( illumPaths, "iso7589" ); - boost::filesystem::path absolutePath = boost::filesystem::absolute( + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( absolutePath.string() ); @@ -1274,16 +1298,16 @@ BOOST_AUTO_TEST_CASE( TestIDT_ChooseIllumType ) 0.1365548815 }; - BOOST_CHECK_EQUAL( illumType_Test, "iso7589" ); + OIIO_CHECK_EQUAL( illumType_Test, "iso7589" ); FORI( illumData_Test.size() ) - BOOST_CHECK_CLOSE( illumData[i], illumData_Test[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( illumData[i], illumData_Test[i], 1e-5 ); free( model ); free( brand ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CalTI ) +void testIDT_CalTI() { Idt *idtTest = new Idt(); @@ -1298,17 +1322,17 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalTI ) memcpy( model, "d200", len ); model[len] = '\0'; - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); idtTest->loadIlluminant( illumPaths, "iso7589" ); - boost::filesystem::path absolutePath = boost::filesystem::absolute( + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( absolutePath.string() ); @@ -5207,14 +5231,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalTI ) 0.0989613226, 0.0936083713 } }; FORIJ( 81, 190 ) - BOOST_CHECK_CLOSE( TI[i][j], TI_test[i][j], 1e-4 ); + OIIO_CHECK_EQUAL_THRESH( TI[i][j], TI_test[i][j], 1e-4 ); free( model ); free( brand ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CalXYZ ) +void testIDT_CalXYZ() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -5230,21 +5254,21 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalXYZ ) Idt *idtTest = new Idt(); - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); idtTest->loadIlluminant( illumPaths, "iso7589" ); - boost::filesystem::path pathCMF = - boost::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); + std::filesystem::path pathCMF = + std::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); idtTest->loadCMF( pathCMF.string() ); - boost::filesystem::path pathTS = boost::filesystem::absolute( + std::filesystem::path pathTS = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( pathTS.string() ); @@ -5444,14 +5468,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalXYZ ) { 0.4603248290, 0.3206987361, 0.3960834297 } }; FORIJ( 190, 3 ) - BOOST_CHECK_CLOSE( XYZ[i][j], XYZ_test[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( XYZ[i][j], XYZ_test[i][j], 1e-5 ); free( model ); free( brand ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CalRGB ) +void testIDT_CalRGB() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -5467,17 +5491,17 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalRGB ) Idt *idtTest = new Idt(); - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); idtTest->loadIlluminant( illumPaths, "iso7589" ); - boost::filesystem::path pathTS = boost::filesystem::absolute( + std::filesystem::path pathTS = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( pathTS.string() ); @@ -5677,14 +5701,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalRGB ) { 0.5608623445, 0.2394587589, 0.3637261707 } }; FORIJ( 190, 3 ) - BOOST_CHECK_CLOSE( RGB[i][j], RGB_test[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( RGB[i][j], RGB_test[i][j], 1e-5 ); free( model ); free( brand ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CurveFit ) +void testIDT_CurveFit() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -5700,22 +5724,22 @@ BOOST_AUTO_TEST_CASE( TestIDT_CurveFit ) Idt *idtTest = new Idt(); - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/nikon_d200_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); idtTest->loadIlluminant( illumPaths, "iso7589" ); - boost::filesystem::path pathTS = boost::filesystem::absolute( + std::filesystem::path pathTS = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( pathTS.string() ); - boost::filesystem::path absolutePath = - boost::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); + std::filesystem::path absolutePath = + std::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); idtTest->loadCMF( absolutePath.string() ); idtTest->chooseIllumType( "iso7589", 0 ); @@ -5734,14 +5758,14 @@ BOOST_AUTO_TEST_CASE( TestIDT_CurveFit ) { 0.0247144012, -0.1245524896, 1.0998380884 } }; FORIJ( 3, 3 ) - BOOST_CHECK_CLOSE( IDT[i][j], IDT_test[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( IDT[i][j], IDT_test[i][j], 1e-5 ); free( model ); free( brand ); delete idtTest; }; -BOOST_AUTO_TEST_CASE( TestIDT_CalIDT ) +void testIDT_CalIDT() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -5757,22 +5781,22 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalIDT ) Idt *idtTest = new Idt(); - boost::filesystem::path pathSpst = boost::filesystem::absolute( + std::filesystem::path pathSpst = std::filesystem::absolute( "../../data/camera/arri_d21_380_780_5.json" ); idtTest->loadCameraSpst( pathSpst.string(), brand, model ); - boost::filesystem::path pathIllum = boost::filesystem::absolute( + std::filesystem::path pathIllum = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector illumPaths; illumPaths.push_back( pathIllum.string() ); idtTest->loadIlluminant( illumPaths, "iso7589" ); - boost::filesystem::path pathTS = boost::filesystem::absolute( + std::filesystem::path pathTS = std::filesystem::absolute( "../../data/training/training_spectral.json" ); idtTest->loadTrainingData( pathTS.string() ); - boost::filesystem::path absolutePath = - boost::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); + std::filesystem::path absolutePath = + std::filesystem::absolute( "../../data/cmf/cmf_1931.json" ); idtTest->loadCMF( absolutePath.string() ); idtTest->chooseIllumType( "iso7589", 0 ); @@ -5786,9 +5810,32 @@ BOOST_AUTO_TEST_CASE( TestIDT_CalIDT ) { -0.1312667887, -0.7361633199, 1.8674301085 } }; FORIJ( 3, 3 ) - BOOST_CHECK_CLOSE( IDT[i][j], IDT_test[i][j], 1e-4 ); + OIIO_CHECK_EQUAL_THRESH( IDT[i][j], IDT_test[i][j], 1e-4 ); free( model ); free( brand ); delete idtTest; }; + +int main( int, char ** ) +{ + testIDT_DataAccess(); + testIDT_LoadCameraSpst(); + testIDT_LoadIlluminant(); + testIDT_LoadTrainingData(); + testIDT_LoadCMF(); + testIDT_Verbose(); + testIDT_scaleLSC(); + testIDT_CalCM(); + testIDT_CalWB(); + testIDT_SetIlluminants(); + testIDT_ChooseIllumSrc(); + testIDT_ChooseIllumType(); + testIDT_CalTI(); + testIDT_CalXYZ(); + testIDT_CalRGB(); + testIDT_CurveFit(); + testIDT_CalIDT(); + + return unit_test_failures; +} diff --git a/unittest/testIllum.cpp b/unittest/testIllum.cpp index 61468f4d..3e02cfde 100644 --- a/unittest/testIllum.cpp +++ b/unittest/testIllum.cpp @@ -57,10 +57,7 @@ # include #endif -#define BOOST_TEST_MAIN -#include -#include -#include +#include #include #include @@ -68,58 +65,58 @@ using namespace std; using namespace rta; -BOOST_AUTO_TEST_CASE( TestIllum_DefaultConstructor ) +void testIllum_DefaultConstructor() { Illum *illumObject = new Illum(); - BOOST_CHECK_EQUAL( illumObject->getIllumInc(), 5 ); + OIIO_CHECK_EQUAL( illumObject->getIllumInc(), 5 ); delete illumObject; }; -BOOST_AUTO_TEST_CASE( TestIllum_DefaultConstructor2 ) +void testIllum_DefaultConstructor2() { Illum *illumObject = new Illum( "d50" ); - BOOST_CHECK_EQUAL( illumObject->getIllumType(), "d50" ); - BOOST_CHECK_EQUAL( illumObject->getIllumInc(), 5 ); + OIIO_CHECK_EQUAL( illumObject->getIllumType(), "d50" ); + OIIO_CHECK_EQUAL( illumObject->getIllumInc(), 5 ); delete illumObject; }; -BOOST_AUTO_TEST_CASE( TestIllum_IllumType ) +void testIllum_IllumType() { Illum *illumObject = new Illum( "d50" ); illumObject->setIllumType( "3200k" ); - BOOST_CHECK_EQUAL( + OIIO_CHECK_EQUAL( std::strcmp( illumObject->getIllumType().c_str(), "3200k" ), 0 ); delete illumObject; }; -BOOST_AUTO_TEST_CASE( TestIllum_IllumInc ) +void testIllum_IllumInc() { Illum *illumObject = new Illum(); illumObject->setIllumInc( 10 ); - BOOST_CHECK_EQUAL( illumObject->getIllumInc(), 10 ); + OIIO_CHECK_EQUAL( illumObject->getIllumInc(), 10 ); delete illumObject; }; -BOOST_AUTO_TEST_CASE( TestIllum_IllumIndex ) +void testIllum_IllumIndex() { Illum *illumObject = new Illum(); illumObject->setIllumIndex( 10.99999 ); - BOOST_CHECK_CLOSE( illumObject->getIllumIndex(), 10.99999, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( illumObject->getIllumIndex(), 10.99999, 1e-5 ); delete illumObject; }; -BOOST_AUTO_TEST_CASE( TestIllum_cctToxy ) +void testIllum_cctToxy() { Illum illumObject; @@ -127,15 +124,15 @@ BOOST_AUTO_TEST_CASE( TestIllum_cctToxy ) vector xy = illumObject.cctToxy( 5000 * 1.4387752 / 1.438 ); - BOOST_CHECK_CLOSE( xy[0], 0.3456619734948, 1e-9 ); - BOOST_CHECK_CLOSE( xy[1], 0.3586032641691, 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( xy[0], 0.3456619734948, 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( xy[1], 0.3586032641691, 1e-9 ); }; -BOOST_AUTO_TEST_CASE( TestIllum_readSPD ) +void testIllum_readSPD() { Illum illumObject; - boost::filesystem::path illumPath = boost::filesystem::absolute( + std::filesystem::path illumPath = std::filesystem::absolute( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); illumObject.readSPD( illumPath.string(), "iso7589" ); @@ -163,15 +160,15 @@ BOOST_AUTO_TEST_CASE( TestIllum_readSPD ) 1.0000000000000 }; - BOOST_CHECK_EQUAL( illumObject.getIllumType(), "iso7589" ); - BOOST_CHECK_EQUAL( illumObject.getIllumInc(), 5 ); + OIIO_CHECK_EQUAL( illumObject.getIllumType(), "iso7589" ); + OIIO_CHECK_EQUAL( illumObject.getIllumInc(), 5 ); vector illumTestData = illumObject.getIllumData(); - BOOST_CHECK_EQUAL( illumTestData.size(), 81 ); - FORI( 81 ) BOOST_CHECK_CLOSE( illumTestData[i], iso7589[i], 1e-5 ); + OIIO_CHECK_EQUAL( illumTestData.size(), 81 ); + FORI( 81 ) OIIO_CHECK_EQUAL_THRESH( illumTestData[i], iso7589[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIllum_calDayLightSPD ) +void testIllum_calDayLightSPD() { Illum illumObject; @@ -212,10 +209,10 @@ BOOST_AUTO_TEST_CASE( TestIllum_calDayLightSPD ) vector data = illumObject.getIllumData(); FORI( data.size() ) - BOOST_CHECK_CLOSE( data[i], spd[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( data[i], spd[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIllum_calBlackBodySPD ) +void testIllum_calBlackBodySPD() { Illum illumObject; @@ -246,5 +243,20 @@ BOOST_AUTO_TEST_CASE( TestIllum_calBlackBodySPD ) vector data = illumObject.getIllumData(); FORI( data.size() ) - BOOST_CHECK_CLOSE( data[i] * 1e-12, spd[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( data[i] * 1e-12, spd[i], 1e-5 ); }; + +int main( int, char ** ) +{ + testIllum_DefaultConstructor(); + testIllum_DefaultConstructor2(); + testIllum_IllumType(); + testIllum_IllumInc(); + testIllum_IllumIndex(); + testIllum_cctToxy(); + testIllum_readSPD(); + testIllum_calDayLightSPD(); + testIllum_calBlackBodySPD(); + + return unit_test_failures; +} diff --git a/unittest/testLogic.cpp b/unittest/testLogic.cpp index 28ffede6..3ee3f48c 100644 --- a/unittest/testLogic.cpp +++ b/unittest/testLogic.cpp @@ -52,9 +52,7 @@ // THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. /////////////////////////////////////////////////////////////////////////// -#define BOOST_TEST_MAIN -#include -#include +#include #include @@ -63,7 +61,7 @@ using namespace std; // This is a unit test to check the proper functioning of different logic in different functions. // To test the validity of getCAT function -BOOST_AUTO_TEST_CASE( Test_getCAT ) +void test_getCAT() { double D60[3] = { 0.952646074569846, 1.0000, 1.00882518435159 }; @@ -87,14 +85,23 @@ BOOST_AUTO_TEST_CASE( Test_getCAT ) final_Output_getCAT[i][1] * src[1] + final_Output_getCAT[i][2] * src[2]; - BOOST_CHECK_CLOSE( destination[0], des[0], 1e-9 ); - BOOST_CHECK_CLOSE( destination[1], des[1], 1e-9 ); - BOOST_CHECK_CLOSE( destination[2], des[2], 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( destination[0], des[0], 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( destination[1], des[1], 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( destination[2], des[2], 1e-9 ); FORI( 3 ) { - BOOST_CHECK_CLOSE( final_Output_getCAT[i][0], final_matrix[i][0], 5 ); - BOOST_CHECK_CLOSE( final_Output_getCAT[i][1], final_matrix[i][1], 5 ); - BOOST_CHECK_CLOSE( final_Output_getCAT[i][2], final_matrix[i][2], 5 ); + OIIO_CHECK_EQUAL_THRESH( + final_Output_getCAT[i][0], final_matrix[i][0], 5 ); + OIIO_CHECK_EQUAL_THRESH( + final_Output_getCAT[i][1], final_matrix[i][1], 5 ); + OIIO_CHECK_EQUAL_THRESH( + final_Output_getCAT[i][2], final_matrix[i][2], 5 ); } }; + +int main( int, char ** ) +{ + test_getCAT(); + return unit_test_failures; +} diff --git a/unittest/testMath.cpp b/unittest/testMath.cpp index b9c16cbc..299de81e 100644 --- a/unittest/testMath.cpp +++ b/unittest/testMath.cpp @@ -58,50 +58,48 @@ # undef RGB #endif -#define BOOST_TEST_MAIN -#include -#include +#include #include using namespace std; -BOOST_AUTO_TEST_CASE( Test_InvertD ) +void test_InvertD() { double a = 1.0; - BOOST_CHECK_CLOSE( invertD( a ), 1.0, 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( invertD( a ), 1.0, 1e-9 ); double b = 1000.0; - BOOST_CHECK_CLOSE( invertD( b ), 0.001, 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( invertD( b ), 0.001, 1e-9 ); double c = 1000000.0; - BOOST_CHECK_CLOSE( invertD( c ), 0.000001, 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( invertD( c ), 0.000001, 1e-9 ); }; -BOOST_AUTO_TEST_CASE( Test_Clip ) +void test_Clip() { double a = 254.9; - BOOST_CHECK_CLOSE( clip( a, 255.0 ), a, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( clip( a, 255.0 ), a, 1e-5 ); double b = 255.1; - BOOST_CHECK_CLOSE( clip( b, 255.0 ), 255.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( clip( b, 255.0 ), 255.0, 1e-5 ); double c = 63355.0; - BOOST_CHECK_CLOSE( clip( c, 63355.0 ), c, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( clip( c, 63355.0 ), c, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_IsSquare ) +void test_IsSquare() { vector> a; a.resize( 2 ); FORI( 2 ) a[i].resize( 2 ); - BOOST_CHECK_EQUAL( isSquare( a ), 1 ); + OIIO_CHECK_EQUAL( isSquare( a ), 1 ); FORI( 2 ) a[i].resize( 1 ); - BOOST_CHECK_EQUAL( isSquare( a ), 0 ); + OIIO_CHECK_EQUAL( isSquare( a ), 0 ); }; -BOOST_AUTO_TEST_CASE( Test_AddVectors ) +void test_AddVectors() { double a[5] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; @@ -113,10 +111,10 @@ BOOST_AUTO_TEST_CASE( Test_AddVectors ) vector cv = addVectors( av, bv ); FORI( 5 ) - BOOST_CHECK_CLOSE( cv[i], c[i], 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( cv[i], c[i], 1e-9 ); }; -BOOST_AUTO_TEST_CASE( Test_SubVectors ) +void test_SubVectors() { double a[5] = { 5.0, 4.0, 3.0, 2.0, 1.0 }; @@ -128,10 +126,10 @@ BOOST_AUTO_TEST_CASE( Test_SubVectors ) vector cv = subVectors( av, bv ); FORI( 5 ) - BOOST_CHECK_CLOSE( cv[i], c[i], 1e-9 ); + OIIO_CHECK_EQUAL_THRESH( cv[i], c[i], 1e-9 ); }; -BOOST_AUTO_TEST_CASE( Test_Cross2 ) +void test_Cross2() { double a[2] = { 1.0, 3.0 }; double b[2] = { 1.0, 6.5 }; @@ -140,10 +138,10 @@ BOOST_AUTO_TEST_CASE( Test_Cross2 ) vector bv( b, b + 2 ); double cross2_test = cross2( av, bv ); - BOOST_CHECK_CLOSE( cross2_test, 3.50, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( cross2_test, 3.50, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_InvertVM ) +void test_InvertVM() { double M[3][3] = { { 0.0188205, 8.59E-03, 9.58E-03 }, { 0.0440222, 0.0166118, 0.0258734 }, @@ -159,13 +157,13 @@ BOOST_AUTO_TEST_CASE( Test_InvertVM ) FORI( 3 ) { - BOOST_CHECK_CLOSE( MV_Inverse[i][0], M_Inverse[i][0], 1e-5 ); - BOOST_CHECK_CLOSE( MV_Inverse[i][1], M_Inverse[i][1], 1e-5 ); - BOOST_CHECK_CLOSE( MV_Inverse[i][2], M_Inverse[i][2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV_Inverse[i][0], M_Inverse[i][0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV_Inverse[i][1], M_Inverse[i][1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV_Inverse[i][2], M_Inverse[i][2], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( Test_InvertV ) +void test_InvertV() { double V[9] = { 0.0188205, 8.59E-03, 9.58E-03, 0.0440222, 0.0166118, 0.0258734, 0.1561591, 0.046321, 0.1181466 }; @@ -176,10 +174,10 @@ BOOST_AUTO_TEST_CASE( Test_InvertV ) vector MV( V, V + 9 ); vector MV_Inverse = invertV( MV ); - FORI( 9 ) BOOST_CHECK_CLOSE( V_Inverse[i], MV_Inverse[i], 1e-5 ); + FORI( 9 ) OIIO_CHECK_EQUAL_THRESH( V_Inverse[i], MV_Inverse[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_DiagVM ) +void test_DiagVM() { double M[3][3] = { { 1.0, 0.0, 0.0 }, { 0.0, 2.0, 0.0 }, @@ -191,13 +189,13 @@ BOOST_AUTO_TEST_CASE( Test_DiagVM ) FORI( 3 ) { - BOOST_CHECK_CLOSE( MVD[i][0], M[i][0], 1e-5 ); - BOOST_CHECK_CLOSE( MVD[i][1], M[i][1], 1e-5 ); - BOOST_CHECK_CLOSE( MVD[i][2], M[i][2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MVD[i][0], M[i][0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MVD[i][1], M[i][1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MVD[i][2], M[i][2], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( Test_DiagV ) +void test_DiagV() { double v[3] = { 1.0, 2.0, 3.0 }; double vd[9] = { 1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0 }; @@ -206,11 +204,11 @@ BOOST_AUTO_TEST_CASE( Test_DiagV ) FORI( 9 ) { - BOOST_CHECK_CLOSE( DV[i], vd[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( DV[i], vd[i], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( Test_TransposeVec ) +void test_TransposeVec() { double M[6][3] = { { 1.0, 0.0, 0.0 }, { 0.0, 2.0, 0.0 }, { 0.0, 0.0, 3.0 }, @@ -241,19 +239,19 @@ BOOST_AUTO_TEST_CASE( Test_TransposeVec ) vector> MVT = transposeVec( MV ); FORIJ( 3, 6 ) - BOOST_CHECK_CLOSE( MVT[i][j], MT[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MVT[i][j], MT[i][j], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_SumVector ) +void test_SumVector() { double M[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; vector MV( M, M + 10 ); double sum = sumVector( MV ); - BOOST_CHECK_CLOSE( sum, 55.0000, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( sum, 55.0000, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_ScaleVectorMax ) +void test_ScaleVectorMax() { double M[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; double M_Scaled[10] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 }; @@ -261,20 +259,20 @@ BOOST_AUTO_TEST_CASE( Test_ScaleVectorMax ) scaleVectorMax( MV ); FORI( MV.size() ) - BOOST_CHECK_CLOSE( M_Scaled[i], MV[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( M_Scaled[i], MV[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_ScaleVectorMin ) +void test_ScaleVectorMin() { double M[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; vector MV( M, M + 10 ); scaleVectorMin( MV ); FORI( MV.size() ) - BOOST_CHECK_CLOSE( M[i], MV[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( M[i], MV[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_scaleVectorD ) +void test_scaleVectorD() { double M[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; double M_Scaled[10] = { 10.0000000000, 5.0000000000, 3.3333333333, @@ -285,10 +283,10 @@ BOOST_AUTO_TEST_CASE( Test_scaleVectorD ) scaleVectorD( MV ); FORI( MV.size() ) - BOOST_CHECK_CLOSE( MV[i], M_Scaled[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV[i], M_Scaled[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_MulVectorElement ) +void test_MulVectorElement() { double M1[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; double M2[10] = { 10.0000000000, 5.0000000000, 3.3333333333, 2.5000000000, @@ -299,10 +297,10 @@ BOOST_AUTO_TEST_CASE( Test_MulVectorElement ) vector MV3 = mulVectorElement( MV1, MV2 ); FORI( MV3.size() ) - BOOST_CHECK_CLOSE( MV3[i], 10.0000000000, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV3[i], 10.0000000000, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_DivVectorElement ) +void test_DivVectorElement() { double M1[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; double M2[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 }; @@ -312,10 +310,10 @@ BOOST_AUTO_TEST_CASE( Test_DivVectorElement ) vector MV3 = divVectorElement( MV1, MV2 ); FORI( MV3.size() ) - BOOST_CHECK_CLOSE( MV3[i], 1.0000000000, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV3[i], 1.0000000000, 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_MulVector1 ) +void test_MulVector1() { double M1[3][3] = { { 1.0, 0.0, 0.0 }, { 0.0, 2.0, 0.0 }, @@ -341,10 +339,10 @@ BOOST_AUTO_TEST_CASE( Test_MulVector1 ) vector> MV3 = mulVector( MV1, MV2 ); FORIJ( 3, 3 ) - BOOST_CHECK_CLOSE( MV3[i][j], M3[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV3[i][j], M3[i][j], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_MulVector2 ) +void test_MulVector2() { double M1[3][3] = { { 1.0000000000, 0.0000000000, 0.0000000000 }, { 0.0000000000, 0.5000000000, 0.0000000000 }, @@ -362,10 +360,10 @@ BOOST_AUTO_TEST_CASE( Test_MulVector2 ) vector MV3 = mulVector( MV1, MV2 ); FORI( 3 ) - BOOST_CHECK_CLOSE( MV3[i], M2[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV3[i], M2[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_MulVectorArray ) +void test_MulVectorArray() { double data[9] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; double M[3][3] = { { 1.0000000000, 0.1000000000, 0.0100000000 }, @@ -384,10 +382,10 @@ BOOST_AUTO_TEST_CASE( Test_MulVectorArray ) mulVectorArray( data, 9, 3, MV ); FORI( 9 ) - BOOST_CHECK_CLOSE( data[i], data_test[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( data[i], data_test[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_SolveVM ) +void test_SolveVM() { double M1[3][3] = { { 1.0000000000, 0.0000000000, 0.0000000000 }, { 0.0000000000, 2.0000000000, 0.0000000000 }, @@ -417,10 +415,10 @@ BOOST_AUTO_TEST_CASE( Test_SolveVM ) vector> MV3 = solveVM( MV1, MV2 ); FORIJ( 3, 3 ) - BOOST_CHECK_CLOSE( MV3[i][j], M3_test[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( MV3[i][j], M3_test[i][j], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( Test_FindIndexInterp1 ) +void test_FindIndexInterp1() { int M[100]; FORI( sizeof( M ) / sizeof( int ) ) @@ -429,10 +427,10 @@ BOOST_AUTO_TEST_CASE( Test_FindIndexInterp1 ) vector MV( M, M + 100 ); int index = findIndexInterp1( 100, MV, (int)MV.size() ); - BOOST_CHECK_EQUAL( index, 50 ); + OIIO_CHECK_EQUAL( index, 50 ); }; -BOOST_AUTO_TEST_CASE( Test_Interp1DLinear ) +void test_Interp1DLinear() { int X0[100], X1[100]; double Y0[100]; @@ -479,10 +477,10 @@ BOOST_AUTO_TEST_CASE( Test_Interp1DLinear ) vector YV1 = interp1DLinear( XV0, XV1, YV0 ); FORI( YV1.size() ) - BOOST_CHECK_CLOSE( YV1[i], Y1[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( YV1[i], Y1[i], 1e-5 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_XytoXYZ ) +void testIDT_XytoXYZ() { double xy[3] = { 0.7347, 0.2653 }; double XYZ[3] = { 0.7347, 0.2653, 0.0 }; @@ -490,11 +488,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_XytoXYZ ) FORI( 3 ) { - BOOST_CHECK_CLOSE( XYZV[i], XYZV[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( XYZV[i], XYZV[i], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( TestIDT_Uvtoxy ) +void testIDT_Uvtoxy() { double uv[2] = { 0.7347, 0.2653 }; double xy[2] = { 0.658530026, 0.158530026 }; @@ -502,11 +500,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_Uvtoxy ) FORI( 2 ) { - BOOST_CHECK_CLOSE( xy[i], xyV[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( xy[i], xyV[i], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( TestIDT_UvtoXYZ ) +void testIDT_UvtoXYZ() { double uv[2] = { 0.7347, 0.2653 }; double XYZ[3] = { 0.658530026, 0.158530026, 0.18293995 }; @@ -514,11 +512,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_UvtoXYZ ) FORI( 3 ) { - BOOST_CHECK_CLOSE( XYZ[i], XYZV[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( XYZ[i], XYZV[i], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( TestIDT_XYZTouv ) +void testIDT_XYZTouv() { double XYZ[3] = { 0.658530026, 0.158530026, 0.18293995 }; double uv[2] = { 0.7347, 0.2653 }; @@ -526,11 +524,11 @@ BOOST_AUTO_TEST_CASE( TestIDT_XYZTouv ) FORI( 2 ) { - BOOST_CHECK_CLOSE( uv[i], uvV[i], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( uv[i], uvV[i], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( TestIDT_GetCAT ) +void testIDT_GetCAT() { vector dIV( d50, d50 + 3 ); vector dOV( d60, d60 + 3 ); @@ -543,13 +541,13 @@ BOOST_AUTO_TEST_CASE( TestIDT_GetCAT ) FORI( 3 ) { - BOOST_CHECK_CLOSE( CAT[i][0], CAT_test[i][0], 1e-5 ); - BOOST_CHECK_CLOSE( CAT[i][1], CAT_test[i][1], 1e-5 ); - BOOST_CHECK_CLOSE( CAT[i][2], CAT_test[i][2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( CAT[i][0], CAT_test[i][0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( CAT[i][1], CAT_test[i][1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( CAT[i][2], CAT_test[i][2], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( Test_XYZtoLAB ) +void test_XYZtoLAB() { vector> XYZ( 190, ( vector( 3 ) ) ); FORIJ( 190, 3 ) @@ -750,13 +748,13 @@ BOOST_AUTO_TEST_CASE( Test_XYZtoLAB ) FORIJ( 190, 3 ) { if ( LAB[i][j] == 0 ) - BOOST_CHECK_SMALL( LAB_test[i][j], 1e-7 ); + OIIO_CHECK_LE( abs( LAB_test[i][j] ), 1e-15 ); else - BOOST_CHECK_CLOSE( LAB_test[i][j], LAB[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( LAB_test[i][j], LAB[i][j], 1e-5 ); } }; -BOOST_AUTO_TEST_CASE( Test_GetCalcXYZt ) +void test_GetCalcXYZt() { vector> RGB( 190, ( vector( 3 ) ) ); const double BStart[6] = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; @@ -957,5 +955,41 @@ BOOST_AUTO_TEST_CASE( Test_GetCalcXYZt ) { 9.5255239594, 3.4396644977, 0.0000000000 } }; FORIJ( 190, 3 ) - BOOST_CHECK_CLOSE( XYZ_test[i][j], XYZ[i][j], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( XYZ_test[i][j], XYZ[i][j], 1e-5 ); }; + +int main( int, char ** ) +{ + test_InvertD(); + test_Clip(); + test_IsSquare(); + test_AddVectors(); + test_SubVectors(); + test_Cross2(); + test_InvertVM(); + test_InvertV(); + test_DiagVM(); + test_DiagV(); + test_TransposeVec(); + test_SumVector(); + test_ScaleVectorMax(); + test_ScaleVectorMin(); + test_scaleVectorD(); + test_MulVectorElement(); + test_DivVectorElement(); + test_MulVector1(); + test_MulVector2(); + test_MulVectorArray(); + test_SolveVM(); + test_FindIndexInterp1(); + test_Interp1DLinear(); + testIDT_XytoXYZ(); + testIDT_Uvtoxy(); + testIDT_UvtoXYZ(); + testIDT_XYZTouv(); + testIDT_GetCAT(); + test_XYZtoLAB(); + test_GetCalcXYZt(); + + return unit_test_failures; +} diff --git a/unittest/testMisc.cpp b/unittest/testMisc.cpp index 278056c4..8ccf0a8b 100644 --- a/unittest/testMisc.cpp +++ b/unittest/testMisc.cpp @@ -52,97 +52,94 @@ // THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. /////////////////////////////////////////////////////////////////////////// -#define BOOST_TEST_MAIN -#include -#include +#include #include using namespace std; -BOOST_AUTO_TEST_CASE( Test_OpenDir ) +void test_OpenDir() { - boost::filesystem::path absolutePath = - boost::filesystem::canonical( "../../data/illuminant" ); + std::filesystem::path absolutePath = + std::filesystem::canonical( "../../data/illuminant" ); - boost::filesystem::path absolutePath_test = boost::filesystem::canonical( + std::filesystem::path absolutePath_test = std::filesystem::canonical( "../../data/illuminant/iso7589_stutung_380_780_5.json" ); vector fPaths = openDir( absolutePath.string() ); - BOOST_CHECK_EQUAL( fPaths.size(), 1 ); + OIIO_CHECK_EQUAL( fPaths.size(), 1 ); vector::iterator it = fPaths.begin(); - BOOST_CHECK_EQUAL( absolutePath_test.string(), *it ); + OIIO_CHECK_EQUAL( absolutePath_test.string(), *it ); }; -BOOST_AUTO_TEST_CASE( Test_LowerCase ) +void test_LowerCase() { char text[] = "RAWTOACES"; char text_test[] = "rawtoaces"; lowerCase( text ); FORI( strlen( text ) - 1 ) - BOOST_CHECK_EQUAL( text[i], text_test[i] ); + OIIO_CHECK_EQUAL( text[i], text_test[i] ); }; -BOOST_AUTO_TEST_CASE( Test_IsNumeric ) +void test_IsNumeric() { const char val1[] = "1234567890"; - BOOST_CHECK_EQUAL( true, isNumeric( val1 ) ); - + OIIO_CHECK_EQUAL( true, isNumeric( val1 ) ); const char val2[] = "123456789A"; - BOOST_CHECK_EQUAL( false, isNumeric( val2 ) ); + OIIO_CHECK_FALSE( isNumeric( val2 ) ); }; -BOOST_AUTO_TEST_CASE( Test_IsCTLetterDigit ) +void test_IsCTLetterDigit() { const char val1 = '1'; - BOOST_CHECK_EQUAL( true, isCTLetterDigit( val1 ) ); + OIIO_CHECK_EQUAL( true, isCTLetterDigit( val1 ) ); const char val2 = 'A'; - BOOST_CHECK_EQUAL( true, isCTLetterDigit( val2 ) ); + OIIO_CHECK_EQUAL( true, isCTLetterDigit( val2 ) ); const char val3 = '-'; - BOOST_CHECK_EQUAL( true, isCTLetterDigit( val3 ) ); + OIIO_CHECK_EQUAL( true, isCTLetterDigit( val3 ) ); const char val4 = '_'; - BOOST_CHECK_EQUAL( false, isCTLetterDigit( val4 ) ); + OIIO_CHECK_FALSE( isCTLetterDigit( val4 ) ); const char val5 = '.'; - BOOST_CHECK_EQUAL( false, isCTLetterDigit( val5 ) ); + OIIO_CHECK_FALSE( isCTLetterDigit( val5 ) ); }; -BOOST_AUTO_TEST_CASE( Test_IsValidCT ) +void test_IsValidCT() { string val1 = "D6500"; - BOOST_CHECK_EQUAL( true, isValidCT( val1 ) ); + OIIO_CHECK_EQUAL( true, isValidCT( val1 ) ); string val2 = "d6500"; - BOOST_CHECK_EQUAL( true, isValidCT( val2 ) ); + OIIO_CHECK_EQUAL( true, isValidCT( val2 ) ); string val3 = "3200K"; - BOOST_CHECK_EQUAL( true, isValidCT( val3 ) ); + OIIO_CHECK_EQUAL( true, isValidCT( val3 ) ); string val4 = "32.00K"; - BOOST_CHECK_EQUAL( false, isValidCT( val4 ) ); + OIIO_CHECK_FALSE( isValidCT( val4 ) ); string val5 = "6500"; - BOOST_CHECK_EQUAL( true, isValidCT( val5 ) ); + OIIO_CHECK_EQUAL( true, isValidCT( val5 ) ); string val6 = "65"; - BOOST_CHECK_EQUAL( true, isValidCT( val6 ) ); + OIIO_CHECK_EQUAL( true, isValidCT( val6 ) ); string val7 = "iso-3200"; - BOOST_CHECK_EQUAL( true, isValidCT( val7 ) ); + OIIO_CHECK_EQUAL( true, isValidCT( val7 ) ); string val8 = "iso_3200"; - BOOST_CHECK_EQUAL( false, isValidCT( val8 ) ); + OIIO_CHECK_FALSE( isValidCT( val8 ) ); string val9 = "d65k"; - BOOST_CHECK_EQUAL( false, isValidCT( val9 ) ); + OIIO_CHECK_FALSE( isValidCT( val9 ) ); }; -BOOST_AUTO_TEST_CASE( Test_PathsFinder ) +void test_PathsFinder() { dataPath dps = pathsFinder(); vector::iterator it = dps.paths.begin(); @@ -153,5 +150,17 @@ BOOST_AUTO_TEST_CASE( Test_PathsFinder ) string first = "/usr/local/include/rawtoaces/data"; #endif - BOOST_CHECK_EQUAL( first, *it ); + OIIO_CHECK_EQUAL( first, *it ); }; + +int main( int, char ** ) +{ + test_OpenDir(); + test_LowerCase(); + test_IsNumeric(); + test_IsCTLetterDigit(); + test_IsValidCT(); + test_PathsFinder(); + + return unit_test_failures; +} diff --git a/unittest/testSpst.cpp b/unittest/testSpst.cpp index ee7d5603..930887c9 100644 --- a/unittest/testSpst.cpp +++ b/unittest/testSpst.cpp @@ -57,10 +57,9 @@ # include #endif -#define BOOST_TEST_MAIN -#include -#include -#include +#include + +#include #include #include @@ -68,7 +67,7 @@ using namespace std; using namespace rta; -BOOST_AUTO_TEST_CASE( TestSpst_DefaultConstructor ) +void testSpst_DefaultConstructor() { char *brand; char *model; @@ -99,26 +98,23 @@ BOOST_AUTO_TEST_CASE( TestSpst_DefaultConstructor ) spstobject1->setWLIncrement( increment ); spstobject1->setSensitivity( rgbsen ); - // boost::test_tools::const_string csBrand(spstobject1->getBrand()); - // BOOST_CHECK_THROW( csBrand.at( csBrand.size()+1 ), std::out_of_range ); - - BOOST_CHECK_EQUAL( std::strcmp( spstobject1->getBrand(), "test" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject1->getModel(), "test" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject1->getWLIncrement() ), 5 ); - BOOST_CHECK_EQUAL( int( spstobject1->getSensitivity().size() ), 81 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject1->getBrand(), "test" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject1->getModel(), "test" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject1->getWLIncrement() ), 5 ); + OIIO_CHECK_EQUAL( int( spstobject1->getSensitivity().size() ), 81 ); vector rgbsen_cp = spstobject1->getSensitivity(); delete spstobject1; FORI( 81 ) { - BOOST_CHECK_EQUAL( rgbsen_cp[i]._RSen, 1.0 ); - BOOST_CHECK_EQUAL( rgbsen_cp[i]._GSen, 1.0 ); - BOOST_CHECK_EQUAL( rgbsen_cp[i]._BSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._RSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._GSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._BSen, 1.0 ); } }; -BOOST_AUTO_TEST_CASE( TestSpst_Constructor2 ) +void testSpst_Constructor2() { char *brand; char *model; @@ -144,22 +140,22 @@ BOOST_AUTO_TEST_CASE( TestSpst_Constructor2 ) // Constructor 2 Spst spstobject2( brand, model, increment, rgbsen ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject2.getBrand(), "test" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject2.getModel(), "test" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject2.getWLIncrement() ), increment ); - BOOST_CHECK_EQUAL( int( spstobject2.getSensitivity().size() ), 81 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject2.getBrand(), "test" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject2.getModel(), "test" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject2.getWLIncrement() ), increment ); + OIIO_CHECK_EQUAL( int( spstobject2.getSensitivity().size() ), 81 ); vector rgbsen_cp = spstobject2.getSensitivity(); FORI( 81 ) { - BOOST_CHECK_EQUAL( rgbsen_cp[i]._RSen, 1.0 ); - BOOST_CHECK_EQUAL( rgbsen_cp[i]._GSen, 1.0 ); - BOOST_CHECK_EQUAL( rgbsen_cp[i]._BSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._RSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._GSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._BSen, 1.0 ); } }; -BOOST_AUTO_TEST_CASE( TestSpst_CopyConstructor ) +void testSpst_CopyConstructor() { char *brand; char *model; @@ -192,10 +188,10 @@ BOOST_AUTO_TEST_CASE( TestSpst_CopyConstructor ) Spst spstobject3( *spstobject1 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject3.getBrand(), "test" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject3.getModel(), "test" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject3.getWLIncrement() ), 5 ); - BOOST_CHECK_EQUAL( int( spstobject3.getSensitivity().size() ), 81 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject3.getBrand(), "test" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject3.getModel(), "test" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject3.getWLIncrement() ), 5 ); + OIIO_CHECK_EQUAL( int( spstobject3.getSensitivity().size() ), 81 ); vector rgbsen_cp = spstobject3.getSensitivity(); @@ -203,13 +199,13 @@ BOOST_AUTO_TEST_CASE( TestSpst_CopyConstructor ) FORI( 81 ) { - BOOST_CHECK_EQUAL( rgbsen_cp[i]._RSen, 1.0 ); - BOOST_CHECK_EQUAL( rgbsen_cp[i]._GSen, 1.0 ); - BOOST_CHECK_EQUAL( rgbsen_cp[i]._BSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._RSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._GSen, 1.0 ); + OIIO_CHECK_EQUAL( rgbsen_cp[i]._BSen, 1.0 ); } }; -BOOST_AUTO_TEST_CASE( TestSpst_LoadSpst ) +void testSpst_LoadSpst() { uint8_t len = 6; char *brand = (char *)malloc( len + 1 ); @@ -223,12 +219,18 @@ BOOST_AUTO_TEST_CASE( TestSpst_LoadSpst ) memcpy( model, "d21", len ); model[len] = '\0'; - Spst *spstTest = new Spst(); - boost::filesystem::path absolutePath = boost::filesystem::absolute( + Spst *spstTest = new Spst(); + std::filesystem::path absolutePath = std::filesystem::absolute( "../../data/camera/arri_d21_380_780_5.json" ); - BOOST_CHECK_NO_THROW( - spstTest->loadSpst( absolutePath.string(), brand, model ) ); + try + { + spstTest->loadSpst( absolutePath.string(), brand, model ); + } + catch ( ... ) + { + OIIO_CHECK_ASSERT( 0 ); + } const vector rgbsenTest = spstTest->getSensitivity(); @@ -314,16 +316,19 @@ BOOST_AUTO_TEST_CASE( TestSpst_LoadSpst ) { 0.000149065, 7.26E-05, 5.84E-05 }, { 3.71E-05, 0.0, 2.70E-06 } }; - BOOST_CHECK_EQUAL( int( rgbsenTest.size() ), 81 ); - BOOST_CHECK_EQUAL( std::strcmp( spstTest->getBrand(), "arri" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstTest->getModel(), "d21" ), 0 ); - BOOST_CHECK_EQUAL( int( spstTest->getWLIncrement() ), 5 ); + OIIO_CHECK_EQUAL( int( rgbsenTest.size() ), 81 ); + OIIO_CHECK_EQUAL( std::strcmp( spstTest->getBrand(), "arri" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstTest->getModel(), "d21" ), 0 ); + OIIO_CHECK_EQUAL( int( spstTest->getWLIncrement() ), 5 ); FORI( 81 ) { - BOOST_CHECK_CLOSE( double( rgbsenTest[i]._RSen ), rgb[i][0], 1e-5 ); - BOOST_CHECK_CLOSE( double( rgbsenTest[i]._GSen ), rgb[i][1], 1e-5 ); - BOOST_CHECK_CLOSE( double( rgbsenTest[i]._BSen ), rgb[i][2], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + double( rgbsenTest[i]._RSen ), rgb[i][0], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + double( rgbsenTest[i]._GSen ), rgb[i][1], 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( + double( rgbsenTest[i]._BSen ), rgb[i][2], 1e-5 ); } free( model ); @@ -331,7 +336,7 @@ BOOST_AUTO_TEST_CASE( TestSpst_LoadSpst ) delete spstTest; }; -BOOST_AUTO_TEST_CASE( TestSpst_DataAccess ) +void testSpst_DataAccess() { char *brand1, *brand2, *brand3; char *model1, *model2, *model3; @@ -382,33 +387,33 @@ BOOST_AUTO_TEST_CASE( TestSpst_DataAccess ) spstobject1->setWLIncrement( 5 ); spstobject1->setSensitivity( rgbsen1 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject1->getBrand(), "" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject1->getModel(), "" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject1->getWLIncrement() ), 5 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject1->getBrand(), "" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject1->getModel(), "" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject1->getWLIncrement() ), 5 ); vector rgbsen_cp = spstobject1->getSensitivity(); FORI( 81 ) { - BOOST_CHECK_CLOSE( rgbsen_cp[i]._RSen, 1.00000001, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._BSen, 0.999999999, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._RSen, 1.00000001, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._BSen, 0.999999999, 1e-5 ); } Spst spstobject2( brand2, model2, 10, rgbsen2 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject2.getBrand(), "b2" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject2.getModel(), "m2" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject2.getWLIncrement() ), 10 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject2.getBrand(), "b2" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject2.getModel(), "m2" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject2.getWLIncrement() ), 10 ); rgbsen_cp.clear(); rgbsen_cp = spstobject2.getSensitivity(); FORI( 81 ) { - BOOST_CHECK_CLOSE( rgbsen_cp[i]._RSen, 1.0, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._BSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._RSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._GSen, 1.0, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._BSen, 1.0, 1e-5 ); } Spst spstobject3( spstobject2 ); @@ -418,18 +423,18 @@ BOOST_AUTO_TEST_CASE( TestSpst_DataAccess ) spstobject3.setWLIncrement( 20 ); spstobject3.setSensitivity( rgbsen3 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject3.getBrand(), "brand3" ), 0 ); - BOOST_CHECK_EQUAL( std::strcmp( spstobject3.getModel(), "model3" ), 0 ); - BOOST_CHECK_EQUAL( int( spstobject3.getWLIncrement() ), 20 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject3.getBrand(), "brand3" ), 0 ); + OIIO_CHECK_EQUAL( std::strcmp( spstobject3.getModel(), "model3" ), 0 ); + OIIO_CHECK_EQUAL( int( spstobject3.getWLIncrement() ), 20 ); rgbsen_cp.clear(); rgbsen_cp = spstobject3.getSensitivity(); FORI( 81 ) { - BOOST_CHECK_CLOSE( rgbsen_cp[i]._RSen, -0.9999999999999, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._GSen, 1e-3, 1e-5 ); - BOOST_CHECK_CLOSE( rgbsen_cp[i]._BSen, 1.0000000000001, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._RSen, -0.9999999999999, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._GSen, 1e-3, 1e-5 ); + OIIO_CHECK_EQUAL_THRESH( rgbsen_cp[i]._BSen, 1.0000000000001, 1e-5 ); } // free ( model1 ); @@ -440,3 +445,14 @@ BOOST_AUTO_TEST_CASE( TestSpst_DataAccess ) // free ( brand3 ); // delete spstobject1; }; + +int main( int, char ** ) +{ + testSpst_DefaultConstructor(); + testSpst_Constructor2(); + testSpst_CopyConstructor(); + testSpst_LoadSpst(); + testSpst_DataAccess(); + + return unit_test_failures; +} From 7665b227c4b1228faffaee5e8aa6eb8af5f5a80c Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Thu, 20 Feb 2025 19:16:22 +1300 Subject: [PATCH 19/20] add the --overwrite, --create-dirs, --output-dir parameters Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/rawtoaces_util.h | 16 ++++- src/rawtoaces2/main.cpp | 26 ++++++-- src/rawtoaces_util2/rawtoaces_util.cpp | 91 ++++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 14 deletions(-) diff --git a/include/rawtoaces/rawtoaces_util.h b/include/rawtoaces/rawtoaces_util.h index 1733a814..e37a7ba4 100644 --- a/include/rawtoaces/rawtoaces_util.h +++ b/include/rawtoaces/rawtoaces_util.h @@ -83,6 +83,10 @@ class ImageConverter int cropbox[4] = { 0, 0, 0, 0 }; int verbosity = 0; + bool overwrite = false; + bool create_dirs = false; + std::string output_dir; + /// Initialise the parser object with all the command line parameters /// used by this tool. The method also sets the help and usage strings. /// The parser object can be amended by the calling code afterwards if @@ -90,7 +94,7 @@ class ImageConverter /// modified directly. /// @param argParse /// The command line parser object to be updated. - void init_parser( OIIO::ArgParse &argParse ) const; + void init_parser( OIIO::ArgParse &argParse ); /// Initialise the converter settings from the command line parser object. /// Prior to calling this, first initialise the object via @@ -158,6 +162,16 @@ class ImageConverter bool apply_scale( OIIO::ImageBuf &dst, const OIIO::ImageBuf &src, OIIO::ROI roi = {} ); + /// Make output file path and check if it is writable. + /// @param path + /// A reference to a variable containing the input file path. The output file path gets generated + /// in-place. + /// @result + /// `true` if the file can be written, e.g. the output directory exists, or creating directories + /// is allowed; the file does not exist or overwriting is allowed. + bool + make_output_path( std::string &path, const std::string &suffix = "_oiio" ); + /// Saves the image into ACES Container. /// @param output_filename /// Full path to the file to be saved. diff --git a/src/rawtoaces2/main.cpp b/src/rawtoaces2/main.cpp index 10e59232..07cecc76 100644 --- a/src/rawtoaces2/main.cpp +++ b/src/rawtoaces2/main.cpp @@ -49,6 +49,15 @@ int main( int argc, const char *argv[] ) if ( std::filesystem::is_regular_file( filename2 ) || std::filesystem::is_symlink( filename2 ) ) { + auto e = filename2.path().extension(); + + if ( e == ".exr" || e == ".EXR" ) + continue; + if ( e == ".jpg" || e == ".JPG" ) + continue; + if ( e == ".jpeg" || e == ".JPEG" ) + continue; + files_to_convert.push_back( filename2.path().string() ); } } @@ -57,6 +66,15 @@ int main( int argc, const char *argv[] ) std::filesystem::is_regular_file( filename ) || std::filesystem::is_symlink( filename ) ) { + auto e = std::filesystem::path( filename ).extension(); + + if ( e == ".exr" || e == ".EXR" ) + continue; + if ( e == ".jpg" || e == ".JPG" ) + continue; + if ( e == ".jpeg" || e == ".JPEG" ) + continue; + files_to_convert.push_back( filename ); } else @@ -70,12 +88,8 @@ int main( int argc, const char *argv[] ) for ( auto const &input_filename: files_to_convert ) { std::string output_filename = input_filename; - size_t pos = input_filename.rfind( '.' ); - if ( pos != std::string::npos ) - { - output_filename = input_filename.substr( 0, pos ); - } - output_filename += "_oiio.exr"; + if ( !converter.make_output_path( output_filename ) ) + continue; OIIO::ParamValueList options; diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index d98fa81d..04269b89 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -137,7 +137,7 @@ bool check_param( } } -void ImageConverter::init_parser( OIIO::ArgParse &argParse ) const +void ImageConverter::init_parser( OIIO::ArgParse &argParse ) { argParse.intro( HelpString ); argParse.usage( UsageString ); @@ -192,6 +192,26 @@ void ImageConverter::init_parser( OIIO::ArgParse &argParse ) const .defaultval( 6.0f ) .action( OIIO::ArgParse::store() ); + argParse.separator( "General options:" ); + + argParse.arg( "--overwrite" ) + .help( + "Allows overwriting existing files. If not set, trying to write " + "to an existing file will generate an error." ) + .action( OIIO::ArgParse::store_true() ); + + argParse.arg( "--output-dir" ) + .help( + "The directory to write the output files to. " + "This gets applied to every input directory, so it is better to " + "be used with a single input directory." ) + .metavar( "STR" ) + .action( OIIO::ArgParse::store() ); + + argParse.arg( "--create-dirs" ) + .help( "Create output directories if they don't exist." ) + .action( OIIO::ArgParse::store_true() ); + argParse.separator( "Raw conversion options:" ); argParse.arg( "--no-auto-bright" ) @@ -273,10 +293,13 @@ void ImageConverter::init_parser( OIIO::ArgParse &argParse ) const .action( OIIO::ArgParse::store_true() ); argParse.arg( "--verbose" ) - .help( "Verbosity level. 0 = off, 1 = info, 2 = debug." ) - .metavar( "VAL" ) - .defaultval( 0 ) - .action( OIIO::ArgParse::store() ); + .help( + "(-v) Print progress messages. " + "Repeated -v will increase verbosity." ) + .action( [&]( OIIO::cspan argv ) { verbosity++; } ); + + argParse.arg( "-v" ).hidden().action( + [&]( OIIO::cspan argv ) { verbosity++; } ); } bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) @@ -335,8 +358,6 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) exit( 0 ); } - verbosity = argParse["verbose"].get(); - std::string wb_method = argParse["wb-method"].get(); if ( wb_method == "metadata" ) @@ -488,6 +509,10 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) highlight_mode = argParse["highlight-mode"].get(); flip = argParse["flip"].get(); + overwrite = argParse["overwrite"].get(); + create_dirs = argParse["create-dirs"].get(); + output_dir = argParse["output-dir"].get(); + return true; } @@ -767,6 +792,58 @@ bool ImageConverter::apply_scale( return OIIO::ImageBufAlgo::mul( dst, src, headroom ); } +bool ImageConverter::make_output_path( + std::string &path, const std::string &suffix ) +{ + std::filesystem::path temp_path( path ); + + temp_path.replace_extension(); + temp_path += suffix + ".exr"; + + if ( !output_dir.empty() ) + { + auto new_directory = std::filesystem::path( output_dir ); + + auto filename = temp_path.filename(); + auto old_directory = temp_path.remove_filename(); + + new_directory = old_directory / new_directory; + + if ( !std::filesystem::exists( new_directory ) ) + { + if ( create_dirs ) + { + if ( !std::filesystem::create_directory( new_directory ) ) + { + std::cerr << "ERROR: Failed to create directory " + << new_directory << "." << std::endl; + return false; + } + } + else + { + std::cerr << "ERROR: The output directory " << new_directory + << " does not exist." << std::endl; + return false; + } + } + + temp_path = std::filesystem::absolute( new_directory / filename ); + } + + if ( !overwrite && std::filesystem::exists( temp_path ) ) + { + std::cerr + << "ERROR: file " << temp_path << " already exists. Use " + << "--overwrite to allow overwriting existing files. Skipping " + << "this file." << std::endl; + return false; + } + + path = temp_path.string(); + return true; +} + bool ImageConverter::save( const std::string &output_filename, const OIIO::ImageBuf &buf ) { From f2aacfb429de9859e5a7ebdb2022cad7bf85eb03 Mon Sep 17 00:00:00 2001 From: Anton Dukhovnikov Date: Sat, 22 Feb 2025 13:47:30 +1300 Subject: [PATCH 20/20] add --disable-cache Signed-off-by: Anton Dukhovnikov --- include/rawtoaces/cache_base.h | 55 +++++---- include/rawtoaces/rawtoaces_util.h | 5 +- src/rawtoaces2/main.cpp | 164 +++++++++++++------------ src/rawtoaces_util2/rawtoaces_util.cpp | 12 +- 4 files changed, 133 insertions(+), 103 deletions(-) diff --git a/include/rawtoaces/cache_base.h b/include/rawtoaces/cache_base.h index 58655831..78fe888d 100644 --- a/include/rawtoaces/cache_base.h +++ b/include/rawtoaces/cache_base.h @@ -40,37 +40,49 @@ template class CacheBase std::list> &map = _maps[map_index]; - if ( verbosity > 0 ) + if ( disabled ) { - std::cerr << name << ": searching for a " << descriptor; + if ( verbosity > 0 ) + { + std::cerr << name << ": disabled " << std::endl; + } + map.clear(); } - - for ( auto iter = map.begin(); iter != map.end(); ++iter ) + else { - if ( iter->first == descriptor ) + + if ( verbosity > 0 ) { - if ( iter != map.begin() ) - { - map.splice( map.begin(), map, iter, std::next( iter ) ); - } + std::cerr << name << ": searching for a " << descriptor; + } - if ( verbosity > 0 ) + for ( auto iter = map.begin(); iter != map.end(); ++iter ) + { + if ( iter->first == descriptor ) { - std::cerr << name << ": found in cache!" << std::endl; + if ( iter != map.begin() ) + { + map.splice( map.begin(), map, iter, std::next( iter ) ); + } + + if ( verbosity > 0 ) + { + std::cerr << name << ": found in cache!" << std::endl; + } + return map.front().second; } - return map.front().second; } - } - if ( map.size() == capacity ) - { - map.pop_back(); - } + if ( map.size() == capacity ) + { + map.pop_back(); + } - if ( verbosity > 0 ) - { - std::cerr << name << ": not found. Calculating a new entry." - << std::endl; + if ( verbosity > 0 ) + { + std::cerr << name << ": not found. Calculating a new entry." + << std::endl; + } } map.emplace_front( @@ -83,6 +95,7 @@ template class CacheBase return data; }; + bool disabled = false; int capacity = 10; int verbosity = 0; std::string name = "Cache"; diff --git a/include/rawtoaces/rawtoaces_util.h b/include/rawtoaces/rawtoaces_util.h index e37a7ba4..06d88aa0 100644 --- a/include/rawtoaces/rawtoaces_util.h +++ b/include/rawtoaces/rawtoaces_util.h @@ -83,8 +83,9 @@ class ImageConverter int cropbox[4] = { 0, 0, 0, 0 }; int verbosity = 0; - bool overwrite = false; - bool create_dirs = false; + bool disable_cache = false; + bool overwrite = false; + bool create_dirs = false; std::string output_dir; /// Initialise the parser object with all the command line parameters diff --git a/src/rawtoaces2/main.cpp b/src/rawtoaces2/main.cpp index 07cecc76..3abf5741 100644 --- a/src/rawtoaces2/main.cpp +++ b/src/rawtoaces2/main.cpp @@ -8,6 +8,31 @@ using namespace rta; +bool check_and_add( + const std::filesystem::path &path, std::vector &batch ) +{ + if ( std::filesystem::is_regular_file( path ) || + std::filesystem::is_symlink( path ) ) + { + auto e = path.extension(); + + if ( e == ".exr" || e == ".EXR" ) + return false; + if ( e == ".jpg" || e == ".JPG" ) + return false; + if ( e == ".jpeg" || e == ".JPEG" ) + return false; + + std::string str = path.string(); + batch.push_back( str ); + } + else + { + std::cerr << "Not a regular file: " << path << std::endl; + } + return true; +} + int main( int argc, const char *argv[] ) { OIIO::ArgParse argParse; @@ -26,9 +51,11 @@ int main( int argc, const char *argv[] ) return 1; } - auto files = argParse["filename"].as_vec(); - std::vector files_to_convert; + // Create a separate batch for each input directory. + // Reserve the first batch for the individual input files. + std::vector> batches( 1 ); + auto files = argParse["filename"].as_vec(); for ( auto filename: files ) { if ( !std::filesystem::exists( filename ) ) @@ -42,102 +69,85 @@ int main( int argc, const char *argv[] ) if ( std::filesystem::is_directory( filename ) ) { + std::vector &curr_batch = batches.emplace_back(); auto it = std::filesystem::directory_iterator( filename ); for ( auto filename2: it ) { - if ( std::filesystem::is_regular_file( filename2 ) || - std::filesystem::is_symlink( filename2 ) ) - { - auto e = filename2.path().extension(); - - if ( e == ".exr" || e == ".EXR" ) - continue; - if ( e == ".jpg" || e == ".JPG" ) - continue; - if ( e == ".jpeg" || e == ".JPEG" ) - continue; - - files_to_convert.push_back( filename2.path().string() ); - } + if ( !check_and_add( filename2, curr_batch ) ) + continue; } } - else if ( - std::filesystem::is_regular_file( filename ) || - std::filesystem::is_symlink( filename ) ) - { - auto e = std::filesystem::path( filename ).extension(); - - if ( e == ".exr" || e == ".EXR" ) - continue; - if ( e == ".jpg" || e == ".JPG" ) - continue; - if ( e == ".jpeg" || e == ".JPEG" ) - continue; - - files_to_convert.push_back( filename ); - } else { - std::cerr << "Not a file or directory: " << filename << std::endl; - return 1; + if ( !check_and_add( filename, batches[0] ) ) + continue; } } bool result = true; - for ( auto const &input_filename: files_to_convert ) + for ( auto const &batch: batches ) { - std::string output_filename = input_filename; - if ( !converter.make_output_path( output_filename ) ) - continue; + for ( auto const &input_filename: batch ) + { + std::string output_filename = input_filename; + if ( !converter.make_output_path( output_filename ) ) + continue; - OIIO::ParamValueList options; + OIIO::ParamValueList options; - if ( !converter.configure( input_filename, options ) ) - { - std::cerr << "Failed to configure the reader for the file: " - << input_filename << std::endl; - result = false; - continue; - } + if ( !converter.configure( input_filename, options ) ) + { + std::cerr << "Failed to configure the reader for the file: " + << input_filename << std::endl; + result = false; + continue; + } - OIIO::ImageSpec imageSpec; - imageSpec.extra_attribs = options; + OIIO::ImageSpec imageSpec; + imageSpec.extra_attribs = options; - OIIO::ImageBuf buffer = OIIO::ImageBuf( - input_filename, 0, 0, nullptr, &imageSpec, nullptr ); + OIIO::ImageBuf buffer = OIIO::ImageBuf( + input_filename, 0, 0, nullptr, &imageSpec, nullptr ); - if ( !buffer.read( - 0, 0, 0, buffer.nchannels(), true, OIIO::TypeDesc::FLOAT ) ) - { - std::cerr << "Failed to read for the file: " << input_filename - << std::endl; - result = false; - continue; - } + if ( !buffer.read( + 0, + 0, + 0, + buffer.nchannels(), + true, + OIIO::TypeDesc::FLOAT ) ) + { + std::cerr << "Failed to read for the file: " << input_filename + << std::endl; + result = false; + continue; + } - if ( !converter.apply_matrix( buffer, buffer ) ) - { - std::cerr << "Failed to apply colour space conversion to the file: " - << input_filename << std::endl; - result = false; - continue; - } + if ( !converter.apply_matrix( buffer, buffer ) ) + { + std::cerr + << "Failed to apply colour space conversion to the file: " + << input_filename << std::endl; + result = false; + continue; + } - if ( !converter.apply_scale( buffer, buffer ) ) - { - std::cerr << "Failed to apply scale to the file: " << input_filename - << std::endl; - result = false; - continue; - } + if ( !converter.apply_scale( buffer, buffer ) ) + { + std::cerr << "Failed to apply scale to the file: " + << input_filename << std::endl; + result = false; + continue; + } - if ( !converter.save( output_filename, buffer ) ) - { - std::cerr << "Failed to save the file: " << output_filename - << std::endl; - result = false; - continue; + if ( !converter.save( output_filename, buffer ) ) + { + std::cerr << "Failed to save the file: " << output_filename + << std::endl; + result = false; + continue; + } } } diff --git a/src/rawtoaces_util2/rawtoaces_util.cpp b/src/rawtoaces_util2/rawtoaces_util.cpp index 04269b89..cabb04d5 100644 --- a/src/rawtoaces_util2/rawtoaces_util.cpp +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -212,6 +212,10 @@ void ImageConverter::init_parser( OIIO::ArgParse &argParse ) .help( "Create output directories if they don't exist." ) .action( OIIO::ArgParse::store_true() ); + argParse.arg( "--disable-cache" ) + .help( "Disable the colour space transform cache." ) + .action( OIIO::ArgParse::store_true() ); + argParse.separator( "Raw conversion options:" ); argParse.arg( "--no-auto-bright" ) @@ -509,9 +513,10 @@ bool ImageConverter::parse_params( const OIIO::ArgParse &argParse ) highlight_mode = argParse["highlight-mode"].get(); flip = argParse["flip"].get(); - overwrite = argParse["overwrite"].get(); - create_dirs = argParse["create-dirs"].get(); - output_dir = argParse["output-dir"].get(); + disable_cache = argParse["disable-cache"].get(); + overwrite = argParse["overwrite"].get(); + create_dirs = argParse["create-dirs"].get(); + output_dir = argParse["output-dir"].get(); return true; } @@ -919,6 +924,7 @@ void ImageConverter::prepareIDT_spectral( descriptor.value = lower_illuminant; } + transform_cache.disabled = disable_cache; transform_cache.verbosity = verbosity; const cache::TransformCacheEntryData &wb_data = transform_cache.fetch( descriptor );