diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 801e5844..071a852e 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 @@ -54,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. @@ -83,40 +84,49 @@ 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 + build_shared_libs: ON + - title: ubuntu + os: ubuntu-24.04 cpp_compiler: clang++ install_deps: install_deps_linux - - os: macos-latest + 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: - - 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 +150,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 0b91e2da..329b957b 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 ) @@ -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) @@ -74,8 +74,10 @@ 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") - +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}") @@ -93,45 +95,46 @@ install( FILES "${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) + 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() -### 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/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/build_scripts/install_deps.bash b/build_scripts/install_deps.bash index b56f40af..a3444ae3 100755 --- a/build_scripts/install_deps.bash +++ b/build_scripts/install_deps.bash @@ -8,6 +8,5 @@ time sudo apt-get update time sudo apt-get -q -f install -y \ libunwind-dev libilmbase-dev libopenexr-dev \ - libboost-dev libboost-thread-dev libboost-filesystem-dev \ - libboost-test-dev \ - libraw-dev libceres-dev + libopenimageio-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 e29f9c4c..a79ea705 100755 --- a/build_scripts/install_deps_linux.bash +++ b/build_scripts/install_deps_linux.bash @@ -5,7 +5,10 @@ set -ex time sudo apt-get update time sudo apt-get -q -f install -y \ - libunwind-dev libimath-dev \ - libboost-dev libboost-filesystem-dev \ - libboost-test-dev \ - libraw-dev libceres-dev + libunwind-dev \ + libimath-dev libopenexr-dev \ + libraw-dev libceres-dev \ + libopencv-dev \ + openimageio-tools \ + libopenimageio-dev \ + nlohmann-json3-dev diff --git a/build_scripts/install_deps_mac.bash b/build_scripts/install_deps_mac.bash index 223fd737..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 +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 b0dd8a14..8c59b371 100755 --- a/build_scripts/install_deps_windows.bash +++ b/build_scripts/install_deps_windows.bash @@ -6,8 +6,5 @@ vcpkg install \ libraw:x64-windows \ ceres:x64-windows \ imath:x64-windows \ - boost-system:x64-windows \ - boost-foreach:x64-windows \ - boost-filesystem:x64-windows \ - boost-test:x64-windows \ - boost-property-tree:x64-windows + openimageio:x64-windows \ + nlohmann-json:x64-windows 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/configure.cmake b/configure.cmake index 6e831feb..1b8d4716 100644 --- a/configure.cmake +++ b/configure.cmake @@ -1,18 +1,14 @@ # 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 ) 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/include/rawtoaces/acesrender.h b/include/rawtoaces/acesrender.h index 2d8d98ce..7a9cfdd0 100644 --- a/include/rawtoaces/acesrender.h +++ b/include/rawtoaces/acesrender.h @@ -56,7 +56,8 @@ #define _ACESRENDER_h__ #include - +#include +#include #include using namespace rta; diff --git a/include/rawtoaces/cache_base.h b/include/rawtoaces/cache_base.h new file mode 100644 index 00000000..78fe888d --- /dev/null +++ b/include/rawtoaces/cache_base.h @@ -0,0 +1,108 @@ +// 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 ( disabled ) + { + if ( verbosity > 0 ) + { + std::cerr << name << ": disabled " << std::endl; + } + map.clear(); + } + else + { + + 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; + }; + + bool disabled = false; + int capacity = 10; + int verbosity = 0; + std::string name = "Cache"; + +private: + std::list> _maps[size]; +}; + +} // namespace cache +} // namespace rta diff --git a/include/rawtoaces/define.h b/include/rawtoaces/define.h index 3b3a28ab..ab7e3182 100644 --- a/include/rawtoaces/define.h +++ b/include/rawtoaces/define.h @@ -55,8 +55,10 @@ #define _DEFINE_h__ #include +#include #include -#include +#include +#include #ifndef WIN32 # include @@ -266,6 +268,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 }, @@ -343,10 +359,13 @@ inline vector openDir( string path = "." ) { vector paths; - for ( auto &i: boost::filesystem::directory_iterator( path ) ) + if ( filesystem::exists( path ) ) { - if ( i.status().type() != boost::filesystem::file_type::directory_file ) - 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; @@ -390,8 +409,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; @@ -444,16 +463,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; + } + } + + { + const char *env = getenv( "RAWTOACES_DATA_PATH" ); + if ( env != nullptr ) + { + if ( !path.empty() ) + path += separator; + path += env; + } + } - if ( path == "" ) + if ( path.empty() ) { #if defined( WIN32 ) || defined( WIN64 ) path = "."; @@ -470,11 +509,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/metadata.h b/include/rawtoaces/metadata.h new file mode 100644 index 00000000..704d0ce3 --- /dev/null +++ b/include/rawtoaces/metadata.h @@ -0,0 +1,60 @@ +// 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_ + +#include + +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; + + 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 + +#endif // RTA_METADATA_H_ diff --git a/include/rawtoaces/rawtoaces_util.h b/include/rawtoaces/rawtoaces_util.h new file mode 100644 index 00000000..06d88aa0 --- /dev/null +++ b/include/rawtoaces/rawtoaces_util.h @@ -0,0 +1,211 @@ +// 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: + /// 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 = 0; + + 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 + /// 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 ); + + /// 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_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`. + /// 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 + /// 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, 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 + /// Destination image buffer. + /// @param src + /// Source image buffer, can be the same as `dst` for in-place + /// conversion. + /// @result + /// `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 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. + /// @param buf + /// Image buffer to be saved. + /// @result + /// `true` if saved successfully. + bool save( const std::string &output_filename, const OIIO::ImageBuf &buf ); + +private: + 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; + std::vector> _CAT_matrix; +}; + +} // namespace rta + +#endif // _RAWTOACES_UTIL_H_ diff --git a/include/rawtoaces/rta.h b/include/rawtoaces/rta.h index bb867dc3..aabfc45d 100644 --- a/include/rawtoaces/rta.h +++ b/include/rawtoaces/rta.h @@ -55,10 +55,11 @@ #ifndef _RTA_h__ #define _RTA_h__ -#include "define.h" - +#include +#include #include -#include + +#include "metadata.h" using namespace std; @@ -226,7 +227,7 @@ class DNGIdt { public: DNGIdt(); - DNGIdt( libraw_rawdata_t R ); + DNGIdt( const Metadata &metadata ); virtual ~DNGIdt(); double ccttoMired( const double cct ) const; @@ -247,16 +248,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/rawtoaces/CMakeLists.txt b/src/rawtoaces/CMakeLists.txt new file mode 100644 index 00000000..cc23c5fc --- /dev/null +++ b/src/rawtoaces/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) + +add_executable( rawtoaces + main.cpp +) + +set_property(TARGET rawtoaces PROPERTY CXX_STANDARD 17) + +target_link_libraries ( rawtoaces + PUBLIC + ${RAWTOACESLIB} +) + +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 () + +install( TARGETS rawtoaces DESTINATION bin ) diff --git a/main.cpp b/src/rawtoaces/main.cpp similarity index 100% rename from main.cpp rename to src/rawtoaces/main.cpp diff --git a/src/rawtoaces2/CMakeLists.txt b/src/rawtoaces2/CMakeLists.txt new file mode 100644 index 00000000..7571fd7b --- /dev/null +++ b/src/rawtoaces2/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.10) +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 +) + + +set_target_properties(rawtoaces2 PROPERTIES XCODE_SCHEME_ARGUMENTS "${CMAKE_XCODE_SCHEME_ARGUMENTS}" ) + +install( TARGETS rawtoaces2 DESTINATION bin ) diff --git a/src/rawtoaces2/main.cpp b/src/rawtoaces2/main.cpp new file mode 100644 index 00000000..3abf5741 --- /dev/null +++ b/src/rawtoaces2/main.cpp @@ -0,0 +1,155 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include + +#include + +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; + argParse.arg( "filename" ).action( OIIO::ArgParse::append() ).hidden(); + + ImageConverter converter; + converter.init_parser( argParse ); + + if ( argParse.parse_args( argc, argv ) < 0 ) + { + return 1; + } + + if ( !converter.parse_params( argParse ) ) + { + return 1; + } + + // 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 ) ) + { + 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 ) ) + { + std::vector &curr_batch = batches.emplace_back(); + auto it = std::filesystem::directory_iterator( filename ); + + for ( auto filename2: it ) + { + if ( !check_and_add( filename2, curr_batch ) ) + continue; + } + } + else + { + if ( !check_and_add( filename, batches[0] ) ) + continue; + } + } + + bool result = true; + for ( auto const &batch: batches ) + { + for ( auto const &input_filename: batch ) + { + std::string output_filename = input_filename; + if ( !converter.make_output_path( output_filename ) ) + continue; + + 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; + } + + 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; + 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.save( output_filename, buffer ) ) + { + std::cerr << "Failed to save the file: " << output_filename + << std::endl; + result = false; + continue; + } + } + } + + return result ? 0 : 1; +} diff --git a/src/rawtoaces_idt/CMakeLists.txt b/src/rawtoaces_idt/CMakeLists.txt index 62f56dfa..54895feb 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,18 +8,21 @@ 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) + +# Eigen is also used in rawtoaces_util and rawtoaces_util2, so setting it public here target_link_libraries( ${RAWTOACESIDTLIB} PUBLIC - Boost::boost - Boost::system - Boost::filesystem - Imath::Imath - Imath::ImathConfig + Eigen3::Eigen + PRIVATE + nlohmann_json::nlohmann_json ) +# 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 () @@ -37,8 +40,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_idt/rta.cpp b/src/rawtoaces_idt/rta.cpp index 73b2973a..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", @@ -592,33 +590,37 @@ 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 ); 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 ( 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 ( 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,23 +1026,27 @@ 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() ) { - _cmf[i]._wl = atoi( ( row.first ).c_str() ); + std::string row = index; + int wl = stoi( row ); - 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() ); + for ( auto j: values ) + data.push_back( (double)j ); assert( data.size() == 3 ); _cmf[i]._xbar = data[0]; @@ -1543,67 +1552,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 +1652,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 +1662,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 +1701,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 +1801,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/CMakeLists.txt b/src/rawtoaces_util/CMakeLists.txt index 3cc023c6..1c337b70 100644 --- a/src/rawtoaces_util/CMakeLists.txt +++ b/src/rawtoaces_util/CMakeLists.txt @@ -1,25 +1,27 @@ -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 ) -if ( AcesContainer_FOUND ) - 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} - ) -endif() +set_property(TARGET ${RAWTOACESLIB} PROPERTY CXX_STANDARD 17) + +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} - INTERFACE - Eigen3::Eigen + PRIVATE Imath::Imath Imath::ImathConfig ) @@ -27,6 +29,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 () diff --git a/src/rawtoaces_util/acesrender.cpp b/src/rawtoaces_util/acesrender.cpp index 069eb10b..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 ); } @@ -1736,9 +1735,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..ee7b140a --- /dev/null +++ b/src/rawtoaces_util2/CMakeLists.txt @@ -0,0 +1,42 @@ +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) + +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 + PRIVATE + ${RAWTOACESIDTLIB} + PUBLIC + 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 + ${PROJECT_SOURCE_DIR}/include/rawtoaces/cache_base.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..cabb04d5 --- /dev/null +++ b/src/rawtoaces_util2/rawtoaces_util.cpp @@ -0,0 +1,1084 @@ +// Copyright Contributors to the rawtoaces project. +// SPDX-License-Identifier: Apache-2.0 +// https://github.com/AcademySoftwareFoundation/rawtoaces + +#include +#include +#include +#include +#include + +#include "transform_cache.h" + +#include +#include +#include + +#include + +namespace rta +{ + +cache::TransformCache transform_cache; + +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 RAWTOACES_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"; + +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 ) +{ + argParse.intro( HelpString ); + argParse.usage( UsageString ); + argParse.print_defaults( true ); + argParse.add_help( true ); + argParse.add_version( "TODO: VERSION NUMBER" ); + + 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( "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.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" ) + .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( + "(-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 ) +{ + if ( argParse["list-cameras"].get() ) + { + std::cout + << "Spectral sensitivity data are available for the following " + << "cameras:" << std::endl; + + Idt idt; + auto paths = cache::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 = cache::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 ); + } + + 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(); + + illuminant = argParse["illuminant"].get(); + + if ( wbMethod == WBMethod::Illuminant ) + { + if ( illuminant.empty() ) + { + std::cerr << "Warning: the white balancing method was set to " + << "\"illuminant\", but no \"--illuminant\" parameter " + << "provided. " << illuminant << " will be used." + << std::endl; + } + } + else + { + if ( !illuminant.empty() ) + { + 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(); + + disable_cache = argParse["disable-cache"].get(); + overwrite = argParse["overwrite"].get(); + create_dirs = argParse["create-dirs"].get(); + output_dir = argParse["output-dir"].get(); + + return true; +} + +bool ImageConverter::configure( + const OIIO::ImageSpec &imageSpec, OIIO::ParamValueList &options ) +{ + options["raw:use_camera_wb"] = 0; + options["raw:use_auto_wb"] = 0; + + 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:user_flip"] = flip; + options["raw:HighlightMode"] = highlight_mode; + + if ( cropbox[2] != 0 && cropbox[3] != 0 ) + { + options.attribute( + "raw:cropbox", OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), cropbox ); + } + + _is_DNG = imageSpec.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] = imageSpec.find_attribute( "raw:cam_mul" ) + ->get_float_indexed( i ); + } + + 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; + } + case WBMethod::Illuminant: { + std::string lower_illuminant = OIIO::Strutil::lower( illuminant ); + 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. + options["raw:use_auto_wb"] = 1; + } + else + { + int32_t box[4]; + for ( int i = 0; i < 4; i++ ) + { + box[i] = wbBox[i]; + } + options.attribute( + "raw:greybox", + OIIO::TypeDesc( OIIO::TypeDesc::INT, 4 ), + box ); + } + break; + + case WBMethod::Custom: + options.attribute( + "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: + std::cerr + << "ERROR: This white balancing method has not been configured " + << "properly." << std::endl; + exit( 1 ); + } + + switch ( matrixMethod ) + { + case MatrixMethod::Spectral: + options["raw:ColorSpace"] = "raw"; + 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:ColorSpace"] = "XYZ"; + options["raw:use_camera_matrix"] = 1; + break; + case MatrixMethod::Custom: + options["raw:ColorSpace"] = "raw"; + options["raw:use_camera_matrix"] = 0; + + _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: + std::cerr + << "ERROR: This matrix method has not been configured properly." + << std::endl; + exit( 1 ); + } + + bool spectral_white_balance = wbMethod == WBMethod::Illuminant; + bool spectral_matrix = matrixMethod == MatrixMethod::Spectral; + + if ( spectral_white_balance || spectral_matrix ) + { + prepareIDT_spectral( + imageSpec, 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]; + + options.attribute( + "raw:user_mul", + OIIO::TypeDesc( OIIO::TypeDesc::FLOAT, 4 ), + user_mul ); + } + } + + if ( matrixMethod == MatrixMethod::Metadata || + matrixMethod == MatrixMethod::Adobe ) + { + if ( _is_DNG ) + { + options["raw:use_camera_matrix"] = 1; + options["raw:use_camera_wb"] = 1; + + prepareIDT_DNG( imageSpec ); + } + else + { + prepareIDT_nonDNG( imageSpec ); + } + } + + 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, + const OIIO::ImageBuf &src, + OIIO::ROI roi ) +{ + 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; + } + } + + return OIIO::ImageBufAlgo::colormatrixtransform( dst, src, M, false, roi ); +} + +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() ) + { + success = applyMatrix( _IDT_matrix, dst, src, roi ); + if ( !success ) + return false; + } + + if ( _CAT_matrix.size() ) + { + success = applyMatrix( _CAT_matrix, dst, dst, roi ); + if ( !success ) + return false; + + success = OIIO::ImageBufAlgo::colormatrixtransform( + dst, dst, XYZ_acesrgb_transposed_4, false, roi ); + if ( !success ) + return false; + } + + return success; +} + +bool ImageConverter::apply_scale( + OIIO::ImageBuf &dst, const OIIO::ImageBuf &src, OIIO::ROI roi ) +{ + 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 ) +{ + const float chromaticities[] = { 0.7347, 0.2653, 0, 1, + 0.0001, -0.077, 0.32168, 0.33767 }; + + OIIO::ImageSpec imageSpec = buf.spec(); + 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 = buf.write( imageOutput.get() ); + return result; +} + +void ImageConverter::prepareIDT_spectral( + const OIIO::ImageSpec &imageSpec, + bool calc_white_balance, + bool calc_matrix ) +{ + std::string lower_illuminant = OIIO::Strutil::lower( illuminant ); + if ( lower_illuminant.empty() ) + lower_illuminant = "na"; + + cache::TransformDescriptor descriptor; + descriptor.camera_make = imageSpec["Make"]; + descriptor.camera_model = imageSpec["Model"]; + + if ( lower_illuminant == "na" ) + { + std::vector wb_multipliers( 4 ); + + if ( _WB_mults.size() == 4 ) + { + for ( int i = 0; i < 3; i++ ) + wb_multipliers[i] = _WB_mults[i]; + } + else + { + auto attr = imageSpec.find_attribute( "raw:pre_mul" ); + for ( int i = 0; i < 4; i++ ) + wb_multipliers[i] = attr->get_float_indexed( i ); + } + + 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; + + 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.disabled = disable_cache; + transform_cache.verbosity = verbosity; + const cache::TransformCacheEntryData &wb_data = + transform_cache.fetch( descriptor ); + + 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++ ) + { + _IDT_matrix[i].resize( 3 ); + for ( size_t j = 0; j < 3; j++ ) + { + _IDT_matrix[i][j] = mat.value[i][j]; + } + } + + _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++ ) + { + matrix[i][j] = mat.value[i][j]; + } + } +} + +void ImageConverter::prepareIDT_DNG( const OIIO::ImageSpec &imageSpec ) +{ + 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 ); + metadata.cameraCalibration1.resize( 9 ); + metadata.cameraCalibration2.resize( 9 ); + + metadata.baselineExposure = + imageSpec.get_float_attribute( "raw:dng:baseline_exposure" ); + metadata.calibrationIlluminant1 = + imageSpec.get_int_attribute( "raw:dng:calibration_illuminant1" ); + metadata.calibrationIlluminant2 = + imageSpec.get_int_attribute( "raw:dng:calibration_illuminant2" ); + + for ( int i = 0; i < 3; i++ ) + { + metadata.neutralRGB[i] = + 1.0 / + imageSpec.find_attribute( "raw:cam_mul" )->get_float_indexed( i ); + + for ( int j = 0; j < 3; j++ ) + { + metadata.xyz2rgbMatrix1[i * 3 + j] = + imageSpec.find_attribute( "raw:dng:color_matrix1" ) + ->get_float_indexed( i * 3 + j ); + metadata.xyz2rgbMatrix2[i * 3 + j] = + imageSpec.find_attribute( "raw:dng:color_matrix2" ) + ->get_float_indexed( i * 3 + j ); + metadata.cameraCalibration1[i * 3 + j] = + imageSpec.find_attribute( "raw:dng:camera_calibration1" ) + ->get_float_indexed( i * 4 + j ); + metadata.cameraCalibration2[i * 3 + j] = + imageSpec.find_attribute( "raw:dng:camera_calibration2" ) + ->get_float_indexed( i * 4 + j ); + } + } + + fetch_matrix( descriptor, _IDT_matrix ); + + // Do not apply CAT for DNG + _CAT_matrix.resize( 0 ); +} + +void ImageConverter::prepareIDT_nonDNG( const OIIO::ImageSpec &imageSpec ) +{ + if ( _read_raw ) + { + auto mat = imageSpec.find_attribute( "raw:cam_xyz" ); + size_t size = mat->type().arraylen; + + if ( size == 12 ) + { + cache::TransformDescriptor descriptor; + descriptor.type = cache::TransformEntryType::Mat_from_nonDNG; + descriptor.camera_make = imageSpec["Make"]; + descriptor.camera_model = imageSpec["Model"]; + + auto &p = + descriptor.value + .emplace>(); + + 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++ ) + { + mat2.value[row][col] = mat->get_float_indexed( idx++ ); + } + } + + fetch_matrix( descriptor, _IDT_matrix ); + } + } + else + { + _IDT_matrix.resize( 0 ); + } + + vector dIV( d65, d65 + 3 ); + vector dOV( d60, d60 + 3 ); + _CAT_matrix = getCAT( dIV, dOV ); +} + +} // namespace rta 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 diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index f8ca8d96..77e093c6 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -1,19 +1,18 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.10) -add_definitions (-DBOOST_TEST_DYN_LINK) add_executable ( Test_Spst testSpst.cpp ) +set_property(TARGET Test_Spst PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Spst PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -21,15 +20,13 @@ add_executable ( testIDT.cpp ) +set_property(TARGET Test_IDT PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_IDT PUBLIC ${RAWTOACESLIB} - Imath::Imath - Imath::ImathConfig - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -37,13 +34,13 @@ add_executable ( testIllum.cpp ) +set_property(TARGET Test_Illum PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Illum PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -51,27 +48,35 @@ add_executable ( testDNGIdt.cpp ) +set_property(TARGET Test_DNGIdt PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_DNGIdt PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) +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 ) +set_property(TARGET Test_Math PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Math PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -79,13 +84,13 @@ add_executable ( testLogic.cpp ) +set_property(TARGET Test_Logic PROPERTY CXX_STANDARD 17) + target_link_libraries( Test_Logic PUBLIC ${RAWTOACESLIB} - Boost::boost - Boost::filesystem - Boost::unit_test_framework + OpenImageIO::OpenImageIO ) add_executable ( @@ -93,13 +98,13 @@ add_executable ( testMisc.cpp ) +set_property(TARGET Test_Misc PROPERTY CXX_STANDARD 17) + 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 d8858905..2a076c35 100644 --- a/unittest/testDNGIdt.cpp +++ b/unittest/testDNGIdt.cpp @@ -52,17 +52,17 @@ // THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. /////////////////////////////////////////////////////////////////////////// -#define BOOST_TEST_MAIN -#include -#include -#include +#include + +#include #include +#include using namespace std; using namespace rta; -BOOST_AUTO_TEST_CASE( TestIDT_CcttoMired ) +void testIDT_CcttoMired() { DNGIdt *di = new DNGIdt(); @@ -70,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(); @@ -85,29 +85,74 @@ 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 ); }; -BOOST_AUTO_TEST_CASE( TestIDT_LightSourceToColorTemp ) +DNGIdt *openFile( std::string path, LibRaw &rawProcessor ) { + 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(); +#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 ); +} + +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; - 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 ); @@ -115,18 +160,16 @@ 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; - 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, @@ -137,18 +180,16 @@ 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; - 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, @@ -160,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(); @@ -173,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(); @@ -187,49 +228,59 @@ 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; - 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(); 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; - 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(); 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; +}