diff --git a/.gitignore b/.gitignore index 574da8c..e1bbbb0 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,8 @@ # CMake build/ +.vs/ +x64/ # MacOS / Linux .DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index b215501..aba965b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,11 @@ project(hdrplus) # set c++ standard set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall -static-openmp") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall -static-openmp") + +add_definitions(-DUSE_LCMS2) +add_definitions(-DANDROID_STL=c++_shared) # make sure we use Release and warn otherwise if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) @@ -24,7 +27,7 @@ else() endif() # require OpenCV -find_package( OpenCV 4 REQUIRED ) +find_package( OpenCV 4 REQUIRED) include_directories( BEFORE ${OpenCV_INCLUDE_DIRS} ) message(STATUS "Found OpenCV ${OpenCV_INCLUDE_DIRS} ${OpenCV_LIBS}") @@ -33,13 +36,25 @@ link_directories(/home/matthew/jniLibs/lib) list(APPEND CMAKE_LIBRARY_PATH /home/matthew/jniLibs/lib/) # LibRaw-cmake 0.20 -# find_library(LIBRAW_LIBRARY raw /home/matthew/jniLibs/lib/) - +if(CMAKE_SYSTEM_NAME STREQUAL "Android") +SET(LIBRAW_LIBRARY "") +include_directories(${LIBRAW_INCLUDE_DIR}) +link_directories(${LIBRAW_DIR}) +else() +find_library(LIBRAW_LIBRARY raw) message(STATUS "Found LIBRAW_LIBRARY to be ${LIBRAW_LIBRARY}" ) +endif() + # Exiv2 -find_package(exiv2 REQUIRED CONFIG NAMES exiv2) -message(STATUS "Found Exiv2 and linked") +if(CMAKE_SYSTEM_NAME STREQUAL "Android") +include_directories(${exiv2_DIR}/include) +link_directories(${exiv2_DIR}/lib) +else() +#find_package(exiv2 REQUIRED CONFIG NAMES exiv2) +#message(STATUS "Found Exiv2 and linked") +endif() + # OpenMP find_package(OpenMP REQUIRED) @@ -67,18 +82,24 @@ add_library(${PROJECT_NAME} STATIC ${src_files} ) target_link_libraries(${PROJECT_NAME} PUBLIC ${OpenCV_LIBS} # ${LIBRAW_LIBRARY} - raw exiv2lib lcms2 + lcms2 raw exiv2 exiv2-xmp expat z OpenMP::OpenMP_CXX ) # example set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin ) -add_executable( demo - bin/demo.cpp ) -target_link_libraries( demo - ${PROJECT_NAME} ) +add_executable( hdrp + ${src_files} + bin/hdrplus.cpp ) +target_link_libraries( hdrp PUBLIC -fopenmp -static-openmp + ${OpenCV_LIBS} + # ${LIBRAW_LIBRARY} + raw lcms2 exiv2 exiv2-xmp expat z + ) # unit test +if(WITH_TEST STREQUAL "ON") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/tests ) add_executable( test_bayer_image tests/test_bayer_image.cpp) @@ -96,3 +117,4 @@ target_link_libraries( test_burst add_executable( test_align tests/test_align.cpp ) target_link_libraries( test_align ${PROJECT_NAME} ) +endif() diff --git a/bin/demo.cpp b/bin/demo.cpp deleted file mode 100644 index 5a610cd..0000000 --- a/bin/demo.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "hdrplus/hdrplus_pipeline.h" - -int main( int argc, char** argv ) -{ - if ( argc != 3 ) - { - printf("Usage: ./demo BURST_FOLDER_PATH(no / at end) REFERENCE_IMAGE_PATH\n"); - exit(1); - } - - hdrplus::hdrplus_pipeline pipeline; - pipeline.run_pipeline( argv[1], argv[ 2 ]); -} \ No newline at end of file diff --git a/bin/hdrp b/bin/hdrp new file mode 100644 index 0000000..23273c3 Binary files /dev/null and b/bin/hdrp differ diff --git a/bin/hdrplus.cpp b/bin/hdrplus.cpp new file mode 100644 index 0000000..948785c --- /dev/null +++ b/bin/hdrplus.cpp @@ -0,0 +1,19 @@ +#include "hdrplus/hdrplus_pipeline.h" + +int main( int argc, char** argv ) +{ + std::vector paths; + for (int idx = 2; idx < argc; idx++) + { + paths.push_back(argv[idx]); + } + + cv::Mat rgb; + + hdrplus::hdrplus_pipeline pipeline; + pipeline.run_pipeline( paths, 0, rgb); + + cv::imwrite(argv[1], rgb); + + return 0; +} \ No newline at end of file diff --git a/buildHdr.sh b/buildHdr.sh index 69c5e16..5a2e0f1 100644 --- a/buildHdr.sh +++ b/buildHdr.sh @@ -4,6 +4,7 @@ export INSTALL_DIR="`pwd`/jni/hdrplus" export NDK=/usr/local/ndk/android-ndk-r25c export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64 export ABI=arm64-v8a +#export ABI=armeabi-v7a export MINSDKVERSION=24 export JNILIBS_DIR=/home/matthew/jniLibs # export EXPAT_DIR=/home/matthew/exiv2ForAndroid-master/expat-2.2.2/jni/expat @@ -25,16 +26,16 @@ cmake \ -DBUILD_SHARED_LIBS=OFF \ -DENABLE_EXAMPLES=OFF \ -DHDRPLUS_NO_DETAILED_OUTPUT=1 \ - -DCMAKE_PREFIX_PATH=$JNILIBS_DIR/lib/$ABI/cmake \ - -DOpenCV_DIR=$JNILIBS_DIR/opencv-mobile-4.9.0-android/sdk/native/jni \ - -DLIBRAW_INCLUDE_DIR=$JNILIBS_DIR/include \ - -DLIBRAW_DIR=$JNILIBS_DIR/lib/cmake \ + -DCMAKE_PREFIX_PATH=$JNILIBS_DIR/$ABI/lib/cmake \ + -DOpenCV_DIR=$JNILIBS_DIR/opencv-mobile-4.10.0-android/sdk/native/jni \ + -DLIBRAW_INCLUDE_DIR=$JNILIBS_DIR/$ABI/include \ + -DLIBRAW_DIR=$JNILIBS_DIR/$ABI/lib \ -DJPEG_INCLUDE_DIR=$JNILIBS_DIR/include \ - -DJPEG_LIBRARIES=$JNILIBS_DIR/lib/$ABI \ - -Dexiv2_INCLUDE_DIR=$JNILIBS_DIR/include \ - -Dexiv2_DIR=$JNILIBS_DIR/lib/cmake/exiv2 \ - -DLCMS2_INCLUDE_DIR=$JNILIBS_DIR/include \ - -DLCMS2_LIBRARY=$JNILIBS_DIR/lib/$ABI \ + -DJPEG_LIBRARIES=$JNILIBS_DIR/$ABI/lib \ + -Dexiv2_INCLUDE_DIR=$JNILIBS_DIR/$ABI/include \ + -Dexiv2_DIR=$JNILIBS_DIR/$ABI \ + -DLCMS2_INCLUDE_DIR=$JNILIBS_DIR/$ABI/include \ + -DLCMS2_LIBRARY=$JNILIBS_DIR/$ABI/lib \ -DLCMS2_LIBRARIES=lcms2 \ .. diff --git a/include/dirent.h b/include/dirent.h new file mode 100644 index 0000000..0788a06 --- /dev/null +++ b/include/dirent.h @@ -0,0 +1,1239 @@ +/* + * Dirent interface for Microsoft Visual Studio + * + * Copyright (C) 1998-2019 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* Hide warnings about unreferenced local functions */ +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunused-function" +#elif defined(_MSC_VER) +# pragma warning(disable:4505) +#elif defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/* + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. + */ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat(), general mask */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT +#endif + +/* Directory bit */ +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR +#endif + +/* Character device bit */ +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR +#endif + +/* Pipe bit */ +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO +#endif + +/* Regular file bit */ +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG +#endif + +/* Read permission */ +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD +#endif + +/* Write permission */ +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE +#endif + +/* Execute permission */ +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC +#endif + +/* Pipe */ +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + +/* Block device */ +#if !defined(S_IFBLK) +# define S_IFBLK 0 +#endif + +/* + * Symbolic link. Be ware that S_IFLNK value and S_ISLNK() macro are only + * usable with dirent - they do not work with stat() function call! + */ +#if !defined(S_IFLNK) +# define S_IFLNK (_S_IFDIR | _S_IFREG) +#endif + +/* Socket */ +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +# define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +# define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +# define S_IXUSR 0 +#endif + +/* User full permissions */ +#if !defined(S_IRWXU) +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +# define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +# define S_IWGRP 0 +#endif + +/* Execute group permission */ +#if !defined(S_IXGRP) +# define S_IXGRP 0 +#endif + +/* Group full permissions */ +#if !defined(S_IRWXG) +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +# define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +# define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +# define S_IXOTH 0 +#endif + +/* Other full permissions */ +#if !defined(S_IRWXO) +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices and sockets cannot be + * distinguished on Windows, and the macros S_ISBLK and S_ISSOCK are only + * defined for compatibility. These macros should always return false on + * Windows. + */ +#if !defined(S_ISFIFO) +# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISDIR) +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISLNK) +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) +# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISCHR) +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISBLK) +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#endif + +/* Return the exact length of the file name without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + /* Always zero */ + long d_ino; + + /* Position of next file in a directory stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX+1]; +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* True if next entry is invalid */ + int invalid; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; +}; +typedef struct _WDIR _WDIR; + +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + + /* Position of next file in a directory stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX+1]; +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + + +/* Dirent functions */ +static DIR *opendir(const char *dirname); +static _WDIR *_wopendir(const wchar_t *dirname); + +static struct dirent *readdir(DIR *dirp); +static struct _wdirent *_wreaddir(_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + +static int closedir(DIR *dirp); +static int _wclosedir(_WDIR *dirp); + +static void rewinddir(DIR *dirp); +static void _wrewinddir(_WDIR *dirp); + +static long telldir(DIR *dirp); +static long _wtelldir(_WDIR *dirp); + +static void seekdir(DIR *dirp, long loc); +static void _wseekdir(_WDIR *dirp, long loc); + +static int scandir(const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort(const struct dirent **a, const struct dirent **b); + +static int versionsort(const struct dirent **a, const struct dirent **b); + +static int strverscmp(const char *a, const char *b); + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir +#define wtelldir _wtelldir +#define wseekdir _wseekdir + +/* Compatibility with older Microsoft compilers and non-Microsoft compilers */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +# define wcstombs_s dirent_wcstombs_s +# define mbstowcs_s dirent_mbstowcs_s +#endif + +/* Optimize dirent_set_errno() away on modern Microsoft compilers */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define dirent_set_errno _set_errno +#endif + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); +static long dirent_hash(WIN32_FIND_DATAW *datap); + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int dirent_mbstowcs_s( + size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, + const char *mbstr, size_t count); +#endif + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int dirent_wcstombs_s( + size_t *pReturnValue, char *mbstr, size_t sizeInBytes, + const wchar_t *wcstr, size_t count); +#endif + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static void dirent_set_errno(int error); +#endif + + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR * +_wopendir(const wchar_t *dirname) +{ + wchar_t *p; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno(ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + _WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR)); + if (!dirp) + return NULL; + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + dirp->invalid = 0; + + /* + * Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL); +#else + /* WinRT */ + size_t n = wcslen(dirname); +#endif + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16); + if (dirp->patt == NULL) + goto exit_closedir; + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + n = GetFullPathNameW(dirname, n, dirp->patt, NULL); + if (n <= 0) + goto exit_closedir; +#else + /* WinRT */ + wcsncpy_s(dirp->patt, n+1, dirname, n); +#endif + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (!dirent_first(dirp)) + goto exit_closedir; + + /* Success */ + return dirp; + + /* Failure */ +exit_closedir: + _wclosedir(dirp); + return NULL; +} + +/* + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). + */ +static struct _wdirent * +_wreaddir(_WDIR *dirp) +{ + /* + * Read directory entry to buffer. We can safely ignore the return + * value as entry will be set to NULL in case of error. + */ + struct _wdirent *entry; + (void) _wreaddir_r(dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result) +{ + /* Validate directory handle */ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) { + dirent_set_errno(EBADF); + *result = NULL; + return -1; + } + + /* Read next directory entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp); + if (!datap) { + /* Return NULL to indicate end of directory */ + *result = NULL; + return /*OK*/0; + } + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + size_t i = 0; + while (i < PATH_MAX && datap->cFileName[i] != 0) { + entry->d_name[i] = datap->cFileName[i]; + i++; + } + entry->d_name[i] = 0; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = i; + + /* Determine file type */ + DWORD attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) + entry->d_type = DT_CHR; + else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) + entry->d_type = DT_LNK; + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + entry->d_type = DT_DIR; + else + entry->d_type = DT_REG; + + /* Read the next directory entry to cache */ + datap = dirent_next(dirp); + if (datap) { + /* Compute 31-bit hash of the next directory entry */ + entry->d_off = dirent_hash(datap); + + /* Push the next directory entry back to cache */ + dirp->cached = 1; + } else { + /* End of directory stream */ + entry->d_off = (long) ((~0UL) >> 1); + } + + /* Reset other fields */ + entry->d_ino = 0; + entry->d_reclen = sizeof(struct _wdirent); + + /* Set result address */ + *result = entry; + return /*OK*/0; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir(_WDIR *dirp) +{ + if (!dirp) { + dirent_set_errno(EBADF); + return /*failure*/-1; + } + + /* + * Release search handle if we have one. Being able to handle + * partially initialized _WDIR structure allows us to use this + * function to handle errors occurring within _wopendir. + */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose(dirp->handle); + } + + /* + * Release search pattern. Note that we don't need to care if + * dirp->patt is NULL or not: function free is guaranteed to act + * appropriately. + */ + free(dirp->patt); + + /* Release directory structure */ + free(dirp); + return /*success*/0; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void _wrewinddir(_WDIR* dirp) +{ + /* Check directory pointer */ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) + return; + + /* Release existing search handle */ + FindClose(dirp->handle); + + /* Open new search handle */ + dirent_first(dirp); +} + +/* Get first directory entry */ +static WIN32_FIND_DATAW * +dirent_first(_WDIR *dirp) +{ + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); + if (dirp->handle == INVALID_HANDLE_VALUE) + goto error; + + /* A directory entry is now waiting in memory */ + dirp->cached = 1; + return &dirp->data; + +error: + /* Failed to open directory: no directory entry in memory */ + dirp->cached = 0; + dirp->invalid = 1; + + /* Set error code */ + DWORD errorcode = GetLastError(); + switch (errorcode) { + case ERROR_ACCESS_DENIED: + /* No read access to directory */ + dirent_set_errno(EACCES); + break; + + case ERROR_DIRECTORY: + /* Directory name is invalid */ + dirent_set_errno(ENOTDIR); + break; + + case ERROR_PATH_NOT_FOUND: + default: + /* Cannot find the file */ + dirent_set_errno(ENOENT); + } + return NULL; +} + +/* Get next directory entry */ +static WIN32_FIND_DATAW * +dirent_next(_WDIR *dirp) +{ + /* Return NULL if seek position was invalid */ + if (dirp->invalid) + return NULL; + + /* Is the next directory entry already in cache? */ + if (dirp->cached) { + /* Yes, a valid directory entry found in memory */ + dirp->cached = 0; + return &dirp->data; + } + + /* Read the next directory entry from stream */ + if (FindNextFileW(dirp->handle, &dirp->data) == FALSE) { + /* End of directory stream */ + return NULL; + } + + /* Success */ + return &dirp->data; +} + +/* + * Compute 31-bit hash of file name. + * + * See djb2 at http://www.cse.yorku.ca/~oz/hash.html + */ +static long +dirent_hash(WIN32_FIND_DATAW *datap) +{ + unsigned long hash = 5381; + unsigned long c; + const wchar_t *p = datap->cFileName; + const wchar_t *e = p + MAX_PATH; + while (p != e && (c = *p++) != 0) { + hash = (hash << 5) + hash + c; + } + + return (long) (hash & ((~0UL) >> 1)); +} + +/* Open directory stream using plain old C-string */ +static DIR *opendir(const char *dirname) +{ + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno(ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR)); + if (!dirp) + return NULL; + + /* Convert directory name to wide-character string */ + wchar_t wname[PATH_MAX + 1]; + size_t n; + int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1); + if (error) + goto exit_failure; + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir(wname); + if (!dirp->wdirp) + goto exit_failure; + + /* Success */ + return dirp; + + /* Failure */ +exit_failure: + free(dirp); + return NULL; +} + +/* Read next directory entry */ +static struct dirent * +readdir(DIR *dirp) +{ + /* + * Read directory entry to buffer. We can safely ignore the return + * value as entry will be set to NULL in case of error. + */ + struct dirent *entry; + (void) readdir_r(dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result) +{ + /* Read next directory entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp); + if (!datap) { + /* No more directory entries */ + *result = NULL; + return /*OK*/0; + } + + /* Attempt to convert file name to multi-byte string */ + size_t n; + int error = wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cFileName, PATH_MAX + 1); + + /* + * If the file name cannot be represented by a multi-byte string, then + * attempt to use old 8+3 file name. This allows the program to + * access files although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file name + * unless the file system provides one. At least VirtualBox shared + * folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); + } + + if (!error) { + /* Length of file name excluding zero terminator */ + entry->d_namlen = n - 1; + + /* Determine file type */ + DWORD attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) + entry->d_type = DT_CHR; + else if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) + entry->d_type = DT_LNK; + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + entry->d_type = DT_DIR; + else + entry->d_type = DT_REG; + + /* Get offset of next file */ + datap = dirent_next(dirp->wdirp); + if (datap) { + /* Compute 31-bit hash of the next directory entry */ + entry->d_off = dirent_hash(datap); + + /* Push the next directory entry back to cache */ + dirp->wdirp->cached = 1; + } else { + /* End of directory stream */ + entry->d_off = (long) ((~0UL) >> 1); + } + + /* Reset fields */ + entry->d_ino = 0; + entry->d_reclen = sizeof(struct dirent); + } else { + /* + * Cannot convert file name to multi-byte string so construct + * an erroneous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + } + + /* Return pointer to directory entry */ + *result = entry; + return /*OK*/0; +} + +/* Close directory stream */ +static int +closedir(DIR *dirp) +{ + int ok; + + if (!dirp) + goto exit_failure; + + /* Close wide-character directory stream */ + ok = _wclosedir(dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free(dirp); + return ok; + +exit_failure: + /* Invalid directory stream */ + dirent_set_errno(EBADF); + return /*failure*/-1; +} + +/* Rewind directory stream to beginning */ +static void +rewinddir(DIR *dirp) +{ + if (!dirp) + return; + + /* Rewind wide-character string directory stream */ + _wrewinddir(dirp->wdirp); +} + +/* Get position of directory stream */ +static long +_wtelldir(_WDIR *dirp) +{ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE) { + dirent_set_errno(EBADF); + return /*failure*/-1; + } + + /* Read next file entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp); + if (!datap) { + /* End of directory stream */ + return (long) ((~0UL) >> 1); + } + + /* Store file entry to cache for readdir() */ + dirp->cached = 1; + + /* Return the 31-bit hash code to be used as stream position */ + return dirent_hash(datap); +} + +/* Get position of directory stream */ +static long +telldir(DIR *dirp) +{ + if (!dirp) { + dirent_set_errno(EBADF); + return -1; + } + + return _wtelldir(dirp->wdirp); +} + +/* Seek directory stream to offset */ +static void +_wseekdir(_WDIR *dirp, long loc) +{ + if (!dirp) + return; + + /* Directory must be open */ + if (dirp->handle == INVALID_HANDLE_VALUE) + goto exit_failure; + + /* Ensure that seek position is valid */ + if (loc < 0) + goto exit_failure; + + /* Restart directory stream from the beginning */ + FindClose(dirp->handle); + if (!dirent_first(dirp)) + goto exit_failure; + + /* Reset invalid flag so that we can read from the stream again */ + dirp->invalid = 0; + + /* + * Read directory entries from the beginning until the hash matches a + * file name. Be ware that hash code is only 31 bits longs and + * duplicates are possible: the hash code cannot return the position + * with 100.00% accuracy! Moreover, the method is slow for large + * directories. + */ + long hash; + do { + /* Read next directory entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp); + if (!datap) { + /* + * End of directory stream was reached before finding + * the requested location. Perhaps the file in + * question was deleted or moved out of the directory. + */ + goto exit_failure; + } + + /* Does the file name match the hash? */ + hash = dirent_hash(datap); + } while (hash != loc); + + /* + * File name matches the hash! Push the directory entry back to cache + * from where next readdir() will return it. + */ + dirp->cached = 1; + dirp->invalid = 0; + return; + +exit_failure: + /* Ensure that readdir will return NULL */ + dirp->invalid = 1; +} + +/* Seek directory stream to offset */ +static void +seekdir(DIR *dirp, long loc) +{ + if (!dirp) + return; + + _wseekdir(dirp->wdirp, loc); +} + +/* Scan directory for entries */ +static int +scandir( + const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + int result; + + /* Open directory stream */ + DIR *dir = opendir(dirname); + if (!dir) { + /* Cannot open directory */ + return /*Error*/ -1; + } + + /* Read directory entries to memory */ + struct dirent *tmp = NULL; + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + while (1) { + /* Allocate room for a temporary directory entry */ + if (!tmp) { + tmp = (struct dirent*) malloc(sizeof(struct dirent)); + if (!tmp) + goto exit_failure; + } + + /* Read directory entry to temporary area */ + struct dirent *entry; + if (readdir_r(dir, tmp, &entry) != /*OK*/0) + goto exit_failure; + + /* Stop if we already read the last directory entry */ + if (entry == NULL) + goto exit_success; + + /* Determine whether to include the entry in results */ + if (filter && !filter(tmp)) + continue; + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + /* Compute number of entries in the new table */ + size_t num_entries = size * 2 + 16; + + /* Allocate new pointer table or enlarge existing */ + void *p = realloc(files, sizeof(void*) * num_entries); + if (!p) + goto exit_failure; + + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } + + /* Store the temporary entry to ptr table */ + files[size++] = tmp; + tmp = NULL; + } + +exit_failure: + /* Release allocated entries */ + for (size_t i = 0; i < size; i++) { + free(files[i]); + } + + /* Release the pointer table */ + free(files); + files = NULL; + + /* Exit with error code */ + result = /*error*/ -1; + goto exit_status; + +exit_success: + /* Sort directory entries */ + if (size > 1 && compare) { + qsort(files, size, sizeof(void*), + (int (*) (const void*, const void*)) compare); + } + + /* Pass pointer table to caller */ + if (namelist) + *namelist = files; + + /* Return the number of directory entries read */ + result = (int) size; + +exit_status: + /* Release temporary directory entry, if we had one */ + free(tmp); + + /* Close directory stream */ + closedir(dir); + return result; +} + +/* Alphabetical sorting */ +static int +alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcoll((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort(const struct dirent **a, const struct dirent **b) +{ + return strverscmp((*a)->d_name, (*b)->d_name); +} + +/* Compare strings */ +static int +strverscmp(const char *a, const char *b) +{ + size_t i = 0; + size_t j; + + /* Find first difference */ + while (a[i] == b[i]) { + if (a[i] == '\0') { + /* No difference */ + return 0; + } + ++i; + } + + /* Count backwards and find the leftmost digit */ + j = i; + while (j > 0 && isdigit(a[j-1])) { + --j; + } + + /* Determine mode of comparison */ + if (a[j] == '0' || b[j] == '0') { + /* Find the next non-zero digit */ + while (a[j] == '0' && a[j] == b[j]) { + j++; + } + + /* String with more digits is smaller, e.g 002 < 01 */ + if (isdigit(a[j])) { + if (!isdigit(b[j])) { + return -1; + } + } else if (isdigit(b[j])) { + return 1; + } + } else if (isdigit(a[j]) && isdigit(b[j])) { + /* Numeric comparison */ + size_t k1 = j; + size_t k2 = j; + + /* Compute number of digits in each string */ + while (isdigit(a[k1])) { + k1++; + } + while (isdigit(b[k2])) { + k2++; + } + + /* Number with more digits is bigger, e.g 999 < 1000 */ + if (k1 < k2) + return -1; + else if (k1 > k2) + return 1; + } + + /* Alphabetical comparison */ + return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]); +} + +/* Convert multi-byte string to wide character string */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int +dirent_mbstowcs_s( + size_t *pReturnValue, wchar_t *wcstr, + size_t sizeInWords, const char *mbstr, size_t count) +{ + /* Older Visual Studio or non-Microsoft compiler */ + size_t n = mbstowcs(wcstr, mbstr, sizeInWords); + if (wcstr && n >= count) + return /*error*/ 1; + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) + n = sizeInWords - 1; + wcstr[n] = 0; + } + + /* Length of multi-byte string with zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + return 0; +} +#endif + +/* Convert wide-character string to multi-byte string */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int +dirent_wcstombs_s( + size_t *pReturnValue, char *mbstr, + size_t sizeInBytes, const wchar_t *wcstr, size_t count) +{ + /* Older Visual Studio or non-Microsoft compiler */ + size_t n = wcstombs(mbstr, wcstr, sizeInBytes); + if (mbstr && n >= count) + return /*error*/1; + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Length of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + return 0; +} +#endif + +/* Set errno variable */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static void +dirent_set_errno(int error) +{ + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; +} +#endif + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ diff --git a/include/hdrplus/AndroidHelper.h b/include/hdrplus/AndroidHelper.h new file mode 100644 index 0000000..235a9f4 --- /dev/null +++ b/include/hdrplus/AndroidHelper.h @@ -0,0 +1,78 @@ +#ifndef __ANDROID_HELPER_H__ +#define __ANDROID_HELPER_H__ + +#ifdef __ANDROID__ +#include +#include +#include +#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING +#include +#include + +#if 0 +#ifndef ALOG +#define ALOG(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) +#ifdef NDEBUG +#define ALOG(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0) +#else +#define ALOGV(...) __ALOGV(__VA_ARGS__) +#endif +#endif +#endif // 0 + +#define MP_TAG "MPLOG" +#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, MP_TAG,__VA_ARGS__) +#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, MP_TAG,__VA_ARGS__) +#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, MP_TAG, __VA_ARGS__) +#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, MP_TAG, __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, MP_TAG,__VA_ARGS__) + +#define AASSERT(cond, fmt, ...) \ + if (!(cond)) { \ + __android_log_assert(#cond, MP_TAG, fmt, ##__VA_ARGS__); \ + } + + +inline std::string jstring2string(JNIEnv *env, jstring jStr) + { + if (!jStr) + return ""; + const jclass stringClass = env->GetObjectClass(jStr); + const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B"); + const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8")); + size_t length = (size_t) env->GetArrayLength(stringJbytes); + jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL); + std::string ret = std::string((char *)pBytes, length); + env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT); + env->DeleteLocalRef(stringJbytes); + env->DeleteLocalRef(stringClass); + return ret; +} + +inline std::wstring utf8_to_wstr(const std::string& src) +{ + std::wstring_convert> converter; + return converter.from_bytes(src); +} + +inline int property_get(const char* key, char* buf, int len) +{ + int ret = 0; + std::string command = "getprop "; + command += key; + FILE* file = popen(command.c_str(), "r"); + if (file) + { + std::fgets(buf, len, file); + // ret = std::atoi(output); + + pclose(file); + } + + return ret; +} + +#endif + + +#endif // __ANDROID_HELPER_H__ diff --git a/include/hdrplus/bayer_image.h b/include/hdrplus/bayer_image.h index 090d8da..e2e5059 100644 --- a/include/hdrplus/bayer_image.h +++ b/include/hdrplus/bayer_image.h @@ -10,10 +10,29 @@ namespace hdrplus { + class MemFile + { + public: + std::vector content; + + const std::vector GetConstData() const + { + return content; + } + + std::vector GetData() + { + return content; + } + }; + class bayer_image { public: explicit bayer_image( const std::string& bayer_image_path ); + explicit bayer_image( const std::vector& bayer_image_content ); + explicit bayer_image( std::shared_ptr bayer_image_file ); + ~bayer_image() = default; std::pair get_noise_params() const; diff --git a/include/hdrplus/burst.h b/include/hdrplus/burst.h index b65c438..33d2f1c 100644 --- a/include/hdrplus/burst.h +++ b/include/hdrplus/burst.h @@ -8,11 +8,14 @@ namespace hdrplus { + class burst { public: explicit burst( const std::string& burst_path, const std::string& reference_image_path ); explicit burst(const std::vector& burst_paths, int reference_image_index); + explicit burst( const std::vector >& bayer_image_contents, int reference_image_index ); + explicit burst( const std::vector >& bayer_image_files, int reference_image_index ); ~burst() = default; diff --git a/include/hdrplus/finish.h b/include/hdrplus/finish.h index 7fc68ae..fdc86eb 100644 --- a/include/hdrplus/finish.h +++ b/include/hdrplus/finish.h @@ -33,10 +33,14 @@ class finish bayer_image* refBayer; std::string mergedImgPath; - finish() = default; + finish() + { + refBayer = NULL; + } // please use this initialization after merging part finish - finish(std::string burstPath, cv::Mat mergedBayer,int refIdx){ + finish(std::string burstPath, cv::Mat mergedBayer,int refIdx) { + refBayer = NULL; this->refIdx = refIdx; this->burstPath = burstPath; this->mergedBayer = mergedBayer; @@ -60,7 +64,14 @@ class finish - ~finish() = default; + ~finish() + { + if (refBayer != NULL) + { + delete refBayer; + refBayer = NULL; + } + } // finish pipeline func // void process(std::string burstPath, cv::Mat mergedBayer,int refIdx); @@ -79,8 +90,8 @@ class finish // cv::Mat tmp(4208,3120,CV_16UC1); cv::Mat tmp(img); - // u_int16_t* ptr_tmp = (u_int16_t*)tmp.data; - // u_int16_t* ptr_img = (u_int16_t*)img.data; + // uint16_t* ptr_tmp = (uint16_t*)tmp.data; + // uint16_t* ptr_img = (uint16_t*)img.data; // // col major to row major // for(int r = 0; r < tmp.rows; r++) { // for(int c = 0; c < tmp.cols; c++) { @@ -91,7 +102,7 @@ class finish // std::cout<<"width="<& burst_paths, int reference_image_index, cv::Mat& finalImg ); + bool run_pipeline( const std::vector& burst_paths, int reference_image_index, cv::Mat& finalImg ); + bool run_pipeline( const std::vector >& burst_contents, int reference_image_index, cv::Mat& finalImg ); + bool run_pipeline( const std::vector >& burst_contents, int reference_image_index, cv::Mat& finalImg ); + hdrplus_pipeline() = default; ~hdrplus_pipeline() = default; }; diff --git a/include/hdrplus/merge.h b/include/hdrplus/merge.h index 77319e7..9a81c92 100644 --- a/include/hdrplus/merge.h +++ b/include/hdrplus/merge.h @@ -1,8 +1,14 @@ #pragma once +#ifdef _WIN32 +#define _USE_MATH_DEFINES +#include +#else +#include +#endif + #include #include // all opencv header -#include #include "hdrplus/burst.h" #define TILE_SIZE 16 @@ -163,7 +169,7 @@ class merge circshift(out, pt); } - std::vector getReferenceTiles(cv::Mat reference_image); + void getReferenceTiles(cv::Mat reference_image, std::vector& reference_tiles); cv::Mat mergeTiles(std::vector tiles, int rows, int cols); @@ -175,8 +181,8 @@ class merge float lambda_read); //temporal denoise - std::vector temporal_denoise(std::vector tiles, std::vector> alt_tiles, std::vector noise_variance, float temporal_factor); - std::vector spatial_denoise(std::vector tiles, int num_alts, std::vector noise_variance, float spatial_factor); + void temporal_denoise(std::vector tiles, std::vector> alt_tiles, std::vector noise_variance, float temporal_factor, std::vector& ); + void spatial_denoise(std::vector tiles, int num_alts, std::vector noise_variance, float spatial_factor, std::vector&); }; diff --git a/include/hdrplus/params.h b/include/hdrplus/params.h index 96bb2c9..6bf1744 100644 --- a/include/hdrplus/params.h +++ b/include/hdrplus/params.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include // std::shared_ptr #include // all opencv header #include @@ -45,26 +45,21 @@ class Tuning{ class Parameters{ public: - std::unordered_map flags{ - {"writeReferenceImage",true}, - {"writeGammaReference", true}, - {"writeMergedImage", true}, - {"writeGammaMerged", true}, - {"writeShortExposure", true}, - {"writeLongExposure", true}, - {"writeFusedExposure", true}, - {"writeLTMImage", true}, - {"writeLTMGamma", true}, - {"writeGTMImage", true}, - {"writeReferenceFinal", true}, - {"writeFinalImage", true} - }; + std::unordered_map flags; RawpyArgs rawpyArgs; Options options; Tuning tuning; - Parameters()= default; + Parameters() + { + const char* keys[] = {"writeReferenceImage", "writeGammaReference", "writeMergedImage", "writeGammaMerged", + "writeShortExposure", "writeLongExposure", "writeFusedExposure", "writeLTMImage", + "writeLTMGamma", "writeGTMImage", "writeReferenceFinal", "writeFinalImage"}; + for (int idx = 0; idx < sizeof(keys) / sizeof(const char*); idx++) { + flags[keys[idx]] = true; + } + } }; diff --git a/include/hdrplus/utility.h b/include/hdrplus/utility.h index bad8358..0b8c7e9 100644 --- a/include/hdrplus/utility.h +++ b/include/hdrplus/utility.h @@ -40,7 +40,11 @@ cv::Mat box_filter_kxk( const cv::Mat& src_image ) if ( kernel <= 0 ) { +#ifdef __ANDROID__ + return cv::Mat(); +#else throw std::runtime_error(std::string( __FILE__ ) + "::" + __func__ + " box filter only support kernel size >= 1"); +#endif } // int(src_height / kernel) = floor(src_height / kernel) @@ -150,7 +154,10 @@ void print_cvmat( cv::Mat image ) } else { +#ifdef __ANDROID__ +#else throw std::runtime_error("cv::Mat number of channel currently not support to print\n"); +#endif } } @@ -175,7 +182,10 @@ void extract_rgb_from_bayer( const cv::Mat& bayer_img, \ if ( bayer_width % 2 != 0 || bayer_height % 2 != 0 ) { +#ifdef __ANDROID__ +#else throw std::runtime_error("Bayer image data size incorrect, must be multiplier of 2\n"); +#endif } // RGB image is half the size of bayer image diff --git a/src/align.cpp b/src/align.cpp index f5dc514..46efa04 100644 --- a/src/align.cpp +++ b/src/align.cpp @@ -106,7 +106,11 @@ static void build_per_grayimg_pyramid( \ images_pyramid.at( i ) = downsample_image.clone(); break; default: +#ifdef __ANDROID__ + break; +#else throw std::runtime_error("inv scale factor " + std::to_string( inv_scale_factors[ i ]) + "invalid" ); +#endif } } } @@ -139,7 +143,11 @@ static void build_upsampled_prev_aligement( \ if ( dst_num_tiles_main_h > num_tiles_h || dst_num_tiles_main_w > num_tiles_w ) { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("current level number of tiles smaller than upsampled tiles\n"); +#endif } // Allocate data for dst_alignment @@ -286,24 +294,40 @@ static unsigned long long l1_distance( const cv::Mat& img1, const cv::Mat& img2, // Range check for safety if ( img1_tile_row_start_idx < 0 || img1_tile_row_start_idx > img1_height - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l1 distance img1_tile_row_start_idx" + std::to_string( img1_tile_row_start_idx ) + \ " out of valid range (0, " + std::to_string( img1_height - tile_size ) + ")\n" ); +#endif } if ( img1_tile_col_start_idx < 0 || img1_tile_col_start_idx > img1_width - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l1 distance img1_tile_col_start_idx" + std::to_string( img1_tile_col_start_idx ) + \ " out of valid range (0, " + std::to_string( img1_width - tile_size ) + ")\n" ); +#endif } if ( img2_tile_row_start_idx < 0 || img2_tile_row_start_idx > img2_height - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l1 distance img2_tile_row_start_idx out of valid range\n"); +#endif } if ( img2_tile_col_start_idx < 0 || img2_tile_col_start_idx > img2_width - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l1 distance img2_tile_col_start_idx out of valid range\n"); +#endif } return_type sum(0); @@ -350,24 +374,40 @@ static return_type l2_distance( const cv::Mat& img1, const cv::Mat& img2, \ // Range check for safety if ( img1_tile_row_start_idx < 0 || img1_tile_row_start_idx > img1_height - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l2 distance img1_tile_row_start_idx" + std::to_string( img1_tile_row_start_idx ) + \ " out of valid range (0, " + std::to_string( img1_height - tile_size ) + ")\n" ); +#endif } if ( img1_tile_col_start_idx < 0 || img1_tile_col_start_idx > img1_width - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l2 distance img1_tile_col_start_idx" + std::to_string( img1_tile_col_start_idx ) + \ " out of valid range (0, " + std::to_string( img1_width - tile_size ) + ")\n" ); +#endif } if ( img2_tile_row_start_idx < 0 || img2_tile_row_start_idx > img2_height - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l2 distance img2_tile_row_start_idx out of valid range\n"); +#endif } if ( img2_tile_col_start_idx < 0 || img2_tile_col_start_idx > img2_width - tile_size ) { +#ifdef __ANDROID__ + return 0; +#else throw std::runtime_error("l2 distance img2_tile_col_start_idx out of valid range\n"); +#endif } // printf("Search two tile with ref : \n"); @@ -407,14 +447,22 @@ static cv::Mat extract_img_tile( const cv::Mat& img, int img_tile_row_start_idx, if ( img_tile_row_start_idx < 0 || img_tile_row_start_idx > img_height - tile_size ) { +#ifdef __ANDROID__ + return cv::Mat(); +#else throw std::runtime_error("extract_img_tile img_tile_row_start_idx " + std::to_string( img_tile_row_start_idx ) + \ " out of valid range (0, " + std::to_string( img_height - tile_size ) + ")\n" ); +#endif } if ( img_tile_col_start_idx < 0 || img_tile_col_start_idx > img_width - tile_size ) { +#ifdef __ANDROID__ + return cv::Mat(); +#else throw std::runtime_error("extract_img_tile img_tile_col_start_idx " + std::to_string( img_tile_col_start_idx ) + \ " out of valid range (0, " + std::to_string( img_width - tile_size ) + ")\n" ); +#endif } cv::Mat img_tile( tile_size, tile_size, img.type() ); @@ -494,7 +542,11 @@ void align_image_level( \ } else { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Something wrong with upsampling function setting\n"); +#endif } } @@ -510,12 +562,20 @@ void align_image_level( \ } else { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Something wrong with upsampling function setting\n"); +#endif } } else { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Something wrong with upsampling function setting\n"); +#endif } } else if ( scale_factor_prev_curr == 4 ) @@ -532,7 +592,11 @@ void align_image_level( \ } else { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Something wrong with upsampling function setting\n"); +#endif } } @@ -548,12 +612,20 @@ void align_image_level( \ } else { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Something wrong with upsampling function setting\n"); +#endif } } else { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Something wrong with upsampling function setting\n"); +#endif } } @@ -713,7 +785,11 @@ void align_image_level( \ // print_tile( alt_img_pad, curr_tile_size + 2 * search_radiou, alt_tile_row_start_idx_i, alt_tile_col_start_idx_i ); // Search based on L1/L2 distance +#ifdef _WIN32 + unsigned long long min_distance_i = ULLONG_MAX; +#else unsigned long long min_distance_i = ULONG_LONG_MAX; +#endif int min_distance_row_i = -1; int min_distance_col_i = -1; for ( int search_row_j = 0; search_row_j < ( search_radiou * 2 + 1 ); search_row_j++ ) @@ -861,6 +937,8 @@ void align::process( const hdrplus::burst& burst_images, \ // Align every image const std::vector& ref_grayimg_pyramid = per_grayimg_pyramid[ burst_images.reference_image_idx ]; + std::vector>> curr_alignment; + std::vector>> prev_alignment; for ( int img_idx = 0; img_idx < burst_images.num_images; ++img_idx ) { // Do not align with reference image @@ -872,8 +950,8 @@ void align::process( const hdrplus::burst& burst_images, \ // Align every level from coarse to grain // level 0 : finest level, the original image // level 3 : coarsest level - std::vector>> curr_alignment; - std::vector>> prev_alignment; + curr_alignment.clear(); + prev_alignment.clear(); for ( int level_i = num_levels - 1; level_i >= 0; level_i-- ) // 3,2,1,0 { // make curr alignment as previous alignment @@ -913,6 +991,8 @@ void align::process( const hdrplus::burst& burst_images, \ } // for alternative image + per_grayimg_pyramid.clear(); + } } // namespace hdrplus diff --git a/src/bayer_image.cpp b/src/bayer_image.cpp index 53a34b2..a65811a 100644 --- a/src/bayer_image.cpp +++ b/src/bayer_image.cpp @@ -21,13 +21,21 @@ bayer_image::bayer_image( const std::string& bayer_image_path ) if ( ( return_code = libraw_processor->open_file( bayer_image_path.c_str() ) ) != LIBRAW_SUCCESS ) { libraw_processor->recycle(); +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code )); +#endif } // Unpack the raw image if ( ( return_code = libraw_processor->unpack() ) != LIBRAW_SUCCESS ) { +#ifdef __ANDROID__ + return; +#else throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code )); +#endif } // Get image basic info @@ -69,6 +77,142 @@ bayer_image::bayer_image( const std::string& bayer_image_path ) #endif } +bayer_image::bayer_image( const std::vector& bayer_image_content ) +{ + libraw_processor = std::make_shared(); + + // Open RAW image file + int return_code; + if ( ( return_code = libraw_processor->open_buffer( (void *)(&bayer_image_content[0]), bayer_image_content.size() ) ) != LIBRAW_SUCCESS ) + { + libraw_processor->recycle(); +#ifdef __ANDROID__ || _WIN32 + return; +#else + // throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code )); + return; +#endif + } + + // Unpack the raw image + if ( ( return_code = libraw_processor->unpack() ) != LIBRAW_SUCCESS ) + { +#ifdef __ANDROID__ || _WIN32 + return; +#else + // throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code )); + return; +#endif + } + + // Get image basic info + width = int( libraw_processor->imgdata.rawdata.sizes.raw_width ); + height = int( libraw_processor->imgdata.rawdata.sizes.raw_height ); + + // Read exif tags + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(&bayer_image_content[0], bayer_image_content.size()); + assert(image.get() != 0); + image->readMetadata(); + Exiv2::ExifData &exifData = image->exifData(); + if (exifData.empty()) { + std::string error = "No Exif data found in the file"; + std::cout << error << std::endl; + } + + white_level = exifData["Exif.Image.WhiteLevel"].toLong(); + black_level_per_channel.resize( 4 ); + black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0); + black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1); + black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2); + black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3); + iso = exifData["Exif.Image.ISOSpeedRatings"].toLong(); + + // Create CV mat + // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ + // https://www.libraw.org/node/2141 + raw_image = cv::Mat( height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image ).clone(); // changed the order of width and height + + // 2x2 box filter + grayscale_image = box_filter_kxk( raw_image ); + +#ifndef NDEBUG + printf("%s::%s read bayer image with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \ + __FILE__, __func__, width, height, iso, white_level, \ + black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3] ); + fflush( stdout ); +#endif +} + + bayer_image::bayer_image( std::shared_ptr bayer_image_file ) + { + libraw_processor = std::make_shared(); + + // Open RAW image file + int return_code; + { + std::vector& fileData = bayer_image_file->content; + if ( ( return_code = libraw_processor->open_buffer( (void *)(&fileData[0]), fileData.size() ) ) != LIBRAW_SUCCESS ) + { + libraw_processor->recycle(); +#ifdef __ANDROID__ + return; +#else + return; + // throw std::runtime_error("Error opening file " + bayer_image_path + " " + libraw_strerror( return_code )); +#endif + } + } + + + // Unpack the raw image + if ( ( return_code = libraw_processor->unpack() ) != LIBRAW_SUCCESS ) + { +#ifdef __ANDROID__ + return; +#else + return; + // throw std::runtime_error("Error unpack file " + bayer_image_path + " " + libraw_strerror( return_code )); +#endif + } + + // Get image basic info + width = int( libraw_processor->imgdata.rawdata.sizes.raw_width ); + height = int( libraw_processor->imgdata.rawdata.sizes.raw_height ); + + // Read exif tags + Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(&bayer_image_file->content[0], bayer_image_file->content.size()); + assert(image.get() != 0); + image->readMetadata(); + Exiv2::ExifData &exifData = image->exifData(); + if (exifData.empty()) { + std::string error = "No Exif data found in the file"; + std::cout << error << std::endl; + } + + white_level = exifData["Exif.Image.WhiteLevel"].toLong(); + black_level_per_channel.resize( 4 ); + black_level_per_channel.at(0) = exifData["Exif.Image.BlackLevel"].toLong(0); + black_level_per_channel.at(1) = exifData["Exif.Image.BlackLevel"].toLong(1); + black_level_per_channel.at(2) = exifData["Exif.Image.BlackLevel"].toLong(2); + black_level_per_channel.at(3) = exifData["Exif.Image.BlackLevel"].toLong(3); + iso = exifData["Exif.Image.ISOSpeedRatings"].toLong(); + + // Create CV mat + // https://answers.opencv.org/question/105972/de-bayering-a-cr2-image/ + // https://www.libraw.org/node/2141 + raw_image = cv::Mat( height, width, CV_16U, libraw_processor->imgdata.rawdata.raw_image ).clone(); // changed the order of width and height + + // 2x2 box filter + grayscale_image = box_filter_kxk( raw_image ); + +#ifndef NDEBUG + printf("%s::%s read bayer image with\n width %zu\n height %zu\n iso %.3f\n white level %d\n black level %d %d %d %d\n", \ + __FILE__, __func__, width, height, iso, white_level, \ + black_level_per_channel[0], black_level_per_channel[1], black_level_per_channel[2], black_level_per_channel[3] ); + fflush( stdout ); +#endif + } + std::pair bayer_image::get_noise_params() const { // Set ISO to 100 if not positive diff --git a/src/burst.cpp b/src/burst.cpp index ad4e63c..c0c83c8 100644 --- a/src/burst.cpp +++ b/src/burst.cpp @@ -41,7 +41,8 @@ burst::burst( const std::string& burst_path, const std::string& reference_image_ if ( reference_image_idx == -1 ) { - throw std::runtime_error("Error unable to locate reference image " + reference_image_path ); + return; + // throw std::runtime_error("Error unable to locate reference image " + reference_image_path ); } #ifndef NDEBUG @@ -109,14 +110,15 @@ burst::burst( const std::vector& bayer_image_paths, int reference_i // Find reference image path in input directory // reference image path need to be absolute path reference_image_idx = -1; - if ( reference_image_index > 0 && reference_image_index < bayer_image_paths.size() ) + if ( reference_image_index >= 0 && reference_image_index < bayer_image_paths.size() ) { reference_image_idx = reference_image_index; } if ( reference_image_idx == -1 ) { - throw std::runtime_error("Error reference image index is out of range " ); + return; + // throw std::runtime_error("Error reference image index is out of range " ); } #ifndef NDEBUG @@ -176,4 +178,144 @@ burst::burst( const std::vector& bayer_image_paths, int reference_i #endif } +burst::burst( const std::vector >& bayer_image_contents, int reference_image_index ) +{ + // Number of images + num_images = bayer_image_contents.size(); + + // Find reference image path in input directory + // reference image path need to be absolute path + reference_image_idx = -1; + if ( reference_image_index >= 0 && reference_image_index < bayer_image_contents.size() ) + { + reference_image_idx = reference_image_index; + } + + if ( reference_image_idx == -1 ) + { + return; + // throw std::runtime_error("Error reference image index is out of range " ); + } + +#ifndef NDEBUG + printf("%s::%s reference image idx %d\n", \ + __FILE__, __func__, reference_image_idx ); +#endif + + // Get source bayer image + // Downsample original bayer image by 2x2 box filter + for ( const auto& bayer_image_content : bayer_image_contents ) + { + bayer_images.emplace_back( bayer_image_content ); + } + + // Pad information + int tile_size_bayer = 32; + int padding_top = tile_size_bayer / 2; + int padding_bottom = tile_size_bayer / 2 + \ + ( (bayer_images[ 0 ].height % tile_size_bayer) == 0 ? \ + 0 : tile_size_bayer - bayer_images[ 0 ].height % tile_size_bayer ); + int padding_left = tile_size_bayer / 2; + int padding_right = tile_size_bayer / 2 + \ + ( (bayer_images[ 0 ].width % tile_size_bayer) == 0 ? \ + 0 : tile_size_bayer - bayer_images[ 0 ].width % tile_size_bayer ); + padding_info_bayer = std::vector{ padding_top, padding_bottom, padding_left, padding_right }; + + // Pad bayer image + for ( const auto& bayer_image_i : bayer_images ) + { + cv::Mat bayer_image_pad_i; + cv::copyMakeBorder( bayer_image_i.raw_image, \ + bayer_image_pad_i, \ + padding_top, padding_bottom, padding_left, padding_right, \ + cv::BORDER_REFLECT ); + + // cv::Mat use internal reference count + bayer_images_pad.emplace_back( bayer_image_pad_i ); + grayscale_images_pad.emplace_back( box_filter_kxk( bayer_image_pad_i ) ); + } + +#ifndef NDEBUG + printf("%s::%s Pad bayer image from (%d, %d) -> (%d, %d)\n", \ + __FILE__, __func__, \ + bayer_images[ 0 ].height, \ + bayer_images[ 0 ].width, \ + bayer_images_pad[ 0 ].size().height, \ + bayer_images_pad[ 0 ].size().width ); + printf("%s::%s pad top %d, buttom %d, left %d, right %d\n", \ + __FILE__, __func__, \ + padding_top, padding_bottom, padding_left, padding_right ); +#endif +} + +burst::burst( const std::vector >& bayer_image_files, int reference_image_index ) +{ + // Number of images + num_images = bayer_image_files.size(); + + // Find reference image path in input directory + // reference image path need to be absolute path + reference_image_idx = -1; + if ( reference_image_index >= 0 && reference_image_index < bayer_image_files.size() ) + { + reference_image_idx = reference_image_index; + } + + if ( reference_image_idx == -1 ) + { + return; + // throw std::runtime_error("Error reference image index is out of range " ); + } + +#ifndef NDEBUG + printf("%s::%s reference image idx %d\n", \ + __FILE__, __func__, reference_image_idx ); +#endif + + // Get source bayer image + // Downsample original bayer image by 2x2 box filter + for ( const auto& bayer_image_file : bayer_image_files ) + { + bayer_images.emplace_back( bayer_image_file ); + } + + // Pad information + int tile_size_bayer = 32; + int padding_top = tile_size_bayer / 2; + int padding_bottom = tile_size_bayer / 2 + \ + ( (bayer_images[ 0 ].height % tile_size_bayer) == 0 ? \ + 0 : tile_size_bayer - bayer_images[ 0 ].height % tile_size_bayer ); + int padding_left = tile_size_bayer / 2; + int padding_right = tile_size_bayer / 2 + \ + ( (bayer_images[ 0 ].width % tile_size_bayer) == 0 ? \ + 0 : tile_size_bayer - bayer_images[ 0 ].width % tile_size_bayer ); + padding_info_bayer = std::vector{ padding_top, padding_bottom, padding_left, padding_right }; + + // Pad bayer image + for ( const auto& bayer_image_i : bayer_images ) + { + cv::Mat bayer_image_pad_i; + cv::copyMakeBorder( bayer_image_i.raw_image, \ + bayer_image_pad_i, \ + padding_top, padding_bottom, padding_left, padding_right, \ + cv::BORDER_REFLECT ); + + // cv::Mat use internal reference count + bayer_images_pad.emplace_back( bayer_image_pad_i ); + grayscale_images_pad.emplace_back( box_filter_kxk( bayer_image_pad_i ) ); + } + +#ifndef NDEBUG + printf("%s::%s Pad bayer image from (%d, %d) -> (%d, %d)\n", \ + __FILE__, __func__, \ + bayer_images[ 0 ].height, \ + bayer_images[ 0 ].width, \ + bayer_images_pad[ 0 ].size().height, \ + bayer_images_pad[ 0 ].size().width ); + printf("%s::%s pad top %d, buttom %d, left %d, right %d\n", \ + __FILE__, __func__, \ + padding_top, padding_bottom, padding_left, padding_right ); +#endif +} + } // namespace hdrplus diff --git a/src/finish.cpp b/src/finish.cpp index 6a9e1b7..d241adb 100644 --- a/src/finish.cpp +++ b/src/finish.cpp @@ -1,15 +1,27 @@ +#ifdef _WIN32 +#define _USE_MATH_DEFINES +#include +#else +#include +#endif #include #include // all opencv header #include "hdrplus/finish.h" #include "hdrplus/utility.h" -#include +#ifdef _WIN32 +#include +#endif + +#ifdef __ANDROID__ +#define DBG_OUTPUT_ROOT "/sdcard/com.xypower.mpapp/tmp/" +#else +#define DBG_OUTPUT_ROOT "" +#endif // #include namespace hdrplus { - - cv::Mat convert16bit2_8bit_(cv::Mat ans){ if(ans.type()==CV_16UC3){ cv::MatIterator_ it, end; @@ -22,7 +34,7 @@ namespace hdrplus } ans.convertTo(ans, CV_8UC3); }else if(ans.type()==CV_16UC1){ - u_int16_t* ptr = (u_int16_t*)ans.data; + uint16_t* ptr = (uint16_t*)ans.data; int end = ans.rows*ans.cols; for(int i=0;iUSHRT_MAX){ *(ptr+i) = USHRT_MAX; }else{ - *(ptr+i)=(u_int16_t)tmp; + *(ptr+i)=(uint16_t)tmp; } } return img; @@ -234,7 +247,7 @@ namespace hdrplus double getSaturated(cv::Mat img, double threshold){ threshold *= USHRT_MAX; double count=0; - u_int16_t* ptr = (u_int16_t*)img.data; + uint16_t* ptr = (uint16_t*)img.data; int max_idx = img.rows*img.cols*img.channels(); for(int i=0;ithreshold){ @@ -253,7 +266,7 @@ namespace hdrplus int H = img.rows; int W = img.cols; cv::Mat processedImg = cv::Mat(H,W,CV_16UC1); - u_int16_t* ptr = (u_int16_t*)processedImg.data; + uint16_t* ptr = (uint16_t*)processedImg.data; int idx=0; cv::MatIterator_ it, end; @@ -290,8 +303,8 @@ namespace hdrplus cv::Mat applyScaling_(cv::Mat mergedImage, cv::Mat shortGray, cv::Mat fusedGray){ cv::Mat result = mergedImage.clone(); - u_int16_t* ptr_shortg = (u_int16_t*)shortGray.data; - u_int16_t* ptr_fusedg = (u_int16_t*)fusedGray.data; + uint16_t* ptr_shortg = (uint16_t*)shortGray.data; + uint16_t* ptr_fusedg = (uint16_t*)fusedGray.data; int count = 0; cv::MatIterator_ it, end; for( it = result.begin(), end = result.end(); it != end; ++it) @@ -384,7 +397,7 @@ namespace hdrplus std::cout<<"--- Scale channels"<1){ x = 1; } - u_int16_t result = x*USHRT_MAX; + uint16_t result = x*USHRT_MAX; return result; } cv::Mat enhanceContrast(cv::Mat image, Options options){ if(options.gtmContrast>=0 && options.gtmContrast<=1){ - u_int16_t* ptr = (u_int16_t*)image.data; + uint16_t* ptr = (uint16_t*)image.data; int end = image.rows*image.cols*image.channels(); for(int idx = 0;idxUSHRT_MAX) r = USHRT_MAX; - *(ptr_r+idx) = (u_int16_t)r; + *(ptr_r+idx) = (uint16_t)r; } return result; } @@ -496,9 +509,9 @@ namespace hdrplus return sharpImage; } - void copy_mat_16U_3(u_int16_t* ptr_A, cv::Mat B){ - // u_int16_t* ptr_A = (u_int16_t*)A.data; - u_int16_t* ptr_B = (u_int16_t*)B.data; + void copy_mat_16U_3(uint16_t* ptr_A, cv::Mat B){ + // uint16_t* ptr_A = (uint16_t*)A.data; + uint16_t* ptr_B = (uint16_t*)B.data; int H = B.rows; int W = B.cols; int end = H*W; @@ -507,9 +520,9 @@ namespace hdrplus } } - // void copy_mat_16U_3(u_int16_t* ptr_A, cv::Mat B){ - // // u_int16_t* ptr_A = (u_int16_t*)A.data; - // u_int16_t* ptr_B = (u_int16_t*)B.data; + // void copy_mat_16U_3(uint16_t* ptr_A, cv::Mat B){ + // // uint16_t* ptr_A = (uint16_t*)A.data; + // uint16_t* ptr_B = (uint16_t*)B.data; // for(int r = 0; r < B.rows; r++) { // for(int c = 0; c < B.cols; c++) { // *(ptr_A+r*B.cols+c) = *(ptr_B+r*B.cols+c); @@ -518,6 +531,7 @@ namespace hdrplus // } cv::Mat processMergedMat(cv::Mat mergedImg, int opencv_type){ cv::Mat m; +#if 0 uint16_t* ptr = (uint16_t*)mergedImg.data; for(int r = 0; r < mergedImg.rows; r++) { std::vector dvals; @@ -528,17 +542,18 @@ namespace hdrplus cv::transpose(mline, mline); m.push_back(mline); } +#endif int ch = CV_MAT_CN(opencv_type); + m = mergedImg.clone(); m = m.reshape(ch); m.convertTo(m, opencv_type); return m; - } void show20_20(cv::Mat m){ - u_int16_t* ptr = (u_int16_t*)m.data; + uint16_t* ptr = (uint16_t*)m.data; for(int i=0;i<20;i++){ for(int j=0;j<20;j++){ std::cout<<*(ptr+i*m.cols+j)<<", "; @@ -561,29 +576,30 @@ namespace hdrplus // save merged Image value #ifndef HDRPLUS_NO_DETAILED_OUTPUT - writeCSV("merged.csv",burst_images.merged_bayer_image); + writeCSV(DBG_OUTPUT_ROOT "merged.csv",burst_images.merged_bayer_image); #endif this->refIdx = burst_images.reference_image_idx; // this->burstPath = burstPath; // std::cout<<"processMerged:"<mergedBayer = loadFromCSV(DBG_OUTPUT_ROOT "merged.csv", CV_16UC1); // this->mergedBayer = processMergedMat(mergedB,CV_16UC1);//loadFromCSV("merged.csv", CV_16UC1); // std::cout<<"processMerged:"<mergedBayer); - this->mergedBayer = loadFromCSV("merged.csv", CV_16UC1); + // this->mergedBayer = loadFromCSV(DBG_OUTPUT_ROOT "merged.csv", CV_16UC1); + // this->mergedBayer = processMergedMat(burst_images.merged_bayer_image, CV_16UC1); #else - this->mergedBayer = processMergedMat(burst_images.merged_bayer_image, CV_16UC1); + // this->mergedBayer = loadFromCSV(DBG_OUTPUT_ROOT "merged.csv", CV_16UC1); + this->mergedBayer = processMergedMat(burst_images.merged_bayer_image, CV_16UC1); // std::cout<<"processMerged:"<mergedBayer); // load_rawPathList(burstPath); - - // read in ref img // bayer_image* ref = new bayer_image(rawPathList[refIdx]); bayer_image* ref = new bayer_image(burst_images.bayer_images[burst_images.reference_image_idx]); @@ -598,7 +614,7 @@ namespace hdrplus cv::Mat outputImg = convert16bit2_8bit_(processedRefImage.clone()); cv::cvtColor(outputImg, outputImg, cv::COLOR_RGB2BGR); // cv::imshow("test",processedImage); - cv::imwrite("processedRef.jpg", outputImg); + cv::imwrite(DBG_OUTPUT_ROOT "processedRef.jpg", outputImg); // cv::waitKey(0); } #endif @@ -610,7 +626,7 @@ namespace hdrplus cv::Mat outputImg = gammasRGB(processedRefImage.clone(),true); outputImg = convert16bit2_8bit_(outputImg); cv::cvtColor(outputImg, outputImg, cv::COLOR_RGB2BGR); - cv::imwrite("processedRefGamma.jpg", outputImg); + cv::imwrite(DBG_OUTPUT_ROOT "processedRefGamma.jpg", outputImg); } #endif @@ -627,7 +643,7 @@ namespace hdrplus std::cout<<"writing Merged img ..."<& libraw_ptr, cv::Mat B){ - u_int16_t* ptr_A = (u_int16_t*)libraw_ptr->imgdata.rawdata.raw_image; - u_int16_t* ptr_B = (u_int16_t*)B.data; + uint16_t* ptr_A = (uint16_t*)libraw_ptr->imgdata.rawdata.raw_image; + uint16_t* ptr_B = (uint16_t*)B.data; for(int r = 0; r < B.rows; r++) { for(int c = 0; c < B.cols; c++) { *(ptr_A+r*B.cols+c) = *(ptr_B+r*B.cols+c); diff --git a/src/hdrplus_pipeline.cpp b/src/hdrplus_pipeline.cpp index b38caf0..11e6fd2 100644 --- a/src/hdrplus_pipeline.cpp +++ b/src/hdrplus_pipeline.cpp @@ -10,6 +10,10 @@ #include "hdrplus/finish.h" #include +#ifdef __ANDROID__ +// #include +#endif + namespace hdrplus { @@ -19,6 +23,7 @@ void hdrplus_pipeline::run_pipeline( \ { // Create burst of images burst burst_images( burst_path, reference_image_path ); + std::vector>>> alignments; // Run align @@ -27,27 +32,107 @@ void hdrplus_pipeline::run_pipeline( \ // Run merging merge_module.process( burst_images, alignments ); + // Run finishing cv::Mat finalImg; finish_module.process( burst_images, finalImg); } -void hdrplus_pipeline::run_pipeline( \ +bool hdrplus_pipeline::run_pipeline( \ const std::vector& burst_paths, \ int reference_image_index, cv::Mat& finalImg ) { // Create burst of images burst burst_images( burst_paths, reference_image_index ); std::vector>>> alignments; +#ifdef __ANDROID__ + // ALOGI("Finish loading images"); +#endif + + // Run align + align_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + // ALOGI("Finish align"); +#endif + + // Run merging + merge_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + // ALOGI("Finish merging"); +#endif + + // Run finishing + finish_module.process( burst_images, finalImg); +#ifdef __ANDROID__ + // ALOGI("Finish process"); +#endif + + return true; +} + +bool hdrplus_pipeline::run_pipeline( \ + const std::vector >& burst_contents, \ + int reference_image_index, cv::Mat& finalImg ) +{ + // Create burst of images + burst burst_images( burst_contents, reference_image_index ); + std::vector>>> alignments; +#ifdef __ANDROID__ + // ALOGI("Finish loading images"); +#endif // Run align align_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + // ALOGI("Finish align"); +#endif // Run merging merge_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + // ALOGI("Finish merging"); +#endif // Run finishing finish_module.process( burst_images, finalImg); +#ifdef __ANDROID__ + // ALOGI("Finish process"); +#endif + + return true; } + + bool hdrplus_pipeline::run_pipeline( \ + const std::vector >& burst_files, \ + int reference_image_index, cv::Mat& finalImg ) + { + // Create burst of images + burst burst_images( burst_files, reference_image_index ); + std::vector>>> alignments; +#ifdef __ANDROID__ + // ALOGI("Finish loading images"); +#endif + + // Run align + align_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + // ALOGI("Finish align"); +#endif + + // Run merging + merge_module.process( burst_images, alignments ); +#ifdef __ANDROID__ + // ALOGI("Finish merging"); +#endif + + // Run finishing + finish_module.process( burst_images, finalImg); +#ifdef __ANDROID__ + // ALOGI("Finish process"); +#endif + + return true; + } + } // namespace hdrplus diff --git a/src/merge.cpp b/src/merge.cpp index 5e0de3b..9781c63 100644 --- a/src/merge.cpp +++ b/src/merge.cpp @@ -20,7 +20,9 @@ namespace hdrplus // Get padded bayer image cv::Mat reference_image = burst_images.bayer_images_pad[burst_images.reference_image_idx]; - cv::imwrite("ref.jpg", reference_image); +#ifndef NDEBUG + // cv::imwrite("ref.jpg", reference_image); +#endif // Get raw channels std::vector channels(4); @@ -98,26 +100,25 @@ namespace hdrplus cv::Range horizontal = cv::Range(padding[2], reference_image.cols - padding[3]); cv::Range vertical = cv::Range(padding[0], reference_image.rows - padding[1]); burst_images.merged_bayer_image = merged(vertical, horizontal); - cv::imwrite("merged.jpg", burst_images.merged_bayer_image); + // cv::imwrite("merged.jpg", burst_images.merged_bayer_image); } - std::vector merge::getReferenceTiles(cv::Mat reference_image) { - std::vector reference_tiles; + void merge::getReferenceTiles(cv::Mat reference_image, std::vector& reference_tiles) { for (int y = 0; y < reference_image.rows - offset; y += offset) { for (int x = 0; x < reference_image.cols - offset; x += offset) { cv::Mat tile = reference_image(cv::Rect(x, y, TILE_SIZE, TILE_SIZE)); reference_tiles.push_back(tile); } } - return reference_tiles; } cv::Mat merge::mergeTiles(std::vector tiles, int num_rows, int num_cols) { // 1. get all four subsets: original (evenly split), horizontal overlapped, // vertical overlapped, 2D overlapped std::vector> tiles_original; + std::vector row; for (int y = 0; y < num_rows / offset - 1; y += 2) { - std::vector row; + row.clear(); for (int x = 0; x < num_cols / offset - 1; x += 2) { row.push_back(tiles[y * (num_cols / offset - 1) + x]); } @@ -125,8 +126,9 @@ namespace hdrplus } std::vector> tiles_horizontal; + // std::vector row; for (int y = 0; y < num_rows / offset - 1; y += 2) { - std::vector row; + row.clear(); for (int x = 1; x < num_cols / offset - 1; x += 2) { row.push_back(tiles[y * (num_cols / offset - 1) + x]); } @@ -134,8 +136,9 @@ namespace hdrplus } std::vector> tiles_vertical; + // std::vector row; for (int y = 1; y < num_rows / offset - 1; y += 2) { - std::vector row; + row.clear(); for (int x = 0; x < num_cols / offset - 1; x += 2) { row.push_back(tiles[y * (num_cols / offset - 1) + x]); } @@ -143,8 +146,9 @@ namespace hdrplus } std::vector> tiles_2d; + // std::vector row; for (int y = 1; y < num_rows / offset - 1; y += 2) { - std::vector row; + row.clear(); for (int x = 1; x < num_cols / offset - 1; x += 2) { row.push_back(tiles[y * (num_cols / offset - 1) + x]); } @@ -172,7 +176,8 @@ namespace hdrplus float lambda_shot, \ float lambda_read) { // Get tiles of the reference image - std::vector reference_tiles = getReferenceTiles(channel_image); + std::vector reference_tiles; + getReferenceTiles(channel_image, reference_tiles); // Get noise variance (sigma**2 = lambda_shot * tileRMS + lambda_read) std::vector noise_variance = getNoiseVariance(reference_tiles, lambda_shot, lambda_read); @@ -190,9 +195,10 @@ namespace hdrplus std::vector> alt_tiles_list(reference_tiles.size()); int num_tiles_row = alternate_channel_i_list[0].rows / offset - 1; int num_tiles_col = alternate_channel_i_list[0].cols / offset - 1; + std::vector alt_tiles; for (int y = 0; y < num_tiles_row; ++y) { for (int x = 0; x < num_tiles_col; ++x) { - std::vector alt_tiles; + alt_tiles.clear(); // Get reference tile location int top_left_y = y * offset; int top_left_x = x * offset; @@ -214,10 +220,19 @@ namespace hdrplus } // 4.2 Temporal Denoising - reference_tiles_DFT = temporal_denoise(reference_tiles_DFT, alt_tiles_list, noise_variance, TEMPORAL_FACTOR); + + std::vector reference_tiles_DFTNew; + temporal_denoise(reference_tiles_DFT, alt_tiles_list, noise_variance, TEMPORAL_FACTOR, reference_tiles_DFTNew); + reference_tiles_DFT.swap(reference_tiles_DFTNew); // 4.3 Spatial Denoising - reference_tiles_DFT = spatial_denoise(reference_tiles_DFT, alternate_channel_i_list.size(), noise_variance, SPATIAL_FACTOR); + reference_tiles_DFTNew.clear(); + spatial_denoise(reference_tiles_DFT, alternate_channel_i_list.size(), noise_variance, SPATIAL_FACTOR, reference_tiles_DFTNew); + reference_tiles_DFT.swap(reference_tiles_DFTNew); + { + std::vector empty; + reference_tiles_DFTNew.swap(empty); + } //now reference tiles are temporally and spatially denoised // Apply IFFT on reference tiles (frequency to spatial) @@ -228,7 +243,13 @@ namespace hdrplus cv::dft(dft_tile, denoised_tile, cv::DFT_INVERSE | cv::DFT_REAL_OUTPUT); denoised_tiles.push_back(denoised_tile); } - reference_tiles = denoised_tiles; + + { + reference_tiles.swap(denoised_tiles); + std::vector empty; + denoised_tiles.swap(empty); + } + // 4.4 Cosine Window Merging // Process tiles through 2D cosine window @@ -241,7 +262,8 @@ namespace hdrplus return mergeTiles(windowed_tiles, channel_image.rows, channel_image.cols); } - std::vector merge::temporal_denoise(std::vector tiles, std::vector> alt_tiles, std::vector noise_variance, float temporal_factor) { + void merge::temporal_denoise(std::vector tiles, std::vector> alt_tiles, std::vector noise_variance, float temporal_factor, std::vector& denoised) + { // goal: temporially denoise using the weiner filter // input: // 1. array of 2D dft tiles of the reference image @@ -254,7 +276,6 @@ namespace hdrplus double temporal_noise_scaling = (TILE_SIZE * TILE_SIZE * (2.0 / 16)) * TEMPORAL_FACTOR; // loop across tiles - std::vector denoised; for (int i = 0; i < tiles.size(); ++i) { // sum of pairwise denoising cv::Mat tile_sum = tiles[i].clone(); @@ -290,10 +311,10 @@ namespace hdrplus denoised.push_back(tile_sum); } - return denoised; + } - std::vector merge::spatial_denoise(std::vector tiles, int num_alts, std::vector noise_variance, float spatial_factor) { + void merge::spatial_denoise(std::vector tiles, int num_alts, std::vector noise_variance, float spatial_factor, std::vector& denoised) { double spatial_noise_scaling = (TILE_SIZE * TILE_SIZE * (1.0 / 16)) * spatial_factor; @@ -307,8 +328,7 @@ namespace hdrplus cv::Mat distances; cv::sqrt(row_distances.mul(row_distances) + col_distances.mul(col_distances), distances); ifftshift(distances); - - std::vector denoised; + // Loop through all tiles for (int i = 0; i < tiles.size(); ++i) { cv::Mat tile = tiles[i]; @@ -326,7 +346,6 @@ namespace hdrplus cv::merge(std::vector{scale, scale}, scale); denoised.push_back(tile.mul(scale)); } - return denoised; } diff --git a/vs/TestHDRplus.cpp b/vs/TestHDRplus.cpp new file mode 100644 index 0000000..71e6841 --- /dev/null +++ b/vs/TestHDRplus.cpp @@ -0,0 +1,20 @@ +// TestHDRplus.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include + +int main() +{ + std::cout << "Hello World!\n"; +} + +// Run program: Ctrl + F5 or Debug > Start Without Debugging menu +// Debug program: F5 or Debug > Start Debugging menu + +// Tips for Getting Started: +// 1. Use the Solution Explorer window to add/manage files +// 2. Use the Team Explorer window to connect to source control +// 3. Use the Output window to see build output and other messages +// 4. Use the Error List window to view errors +// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project +// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file diff --git a/vs/TestHDRplus.sln b/vs/TestHDRplus.sln new file mode 100644 index 0000000..1c99128 --- /dev/null +++ b/vs/TestHDRplus.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.34829.251 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHDRplus", "TestHDRplus.vcxproj", "{98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Debug|x64.ActiveCfg = Debug|x64 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Debug|x64.Build.0 = Debug|x64 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Debug|x86.ActiveCfg = Debug|Win32 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Debug|x86.Build.0 = Debug|Win32 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Release|x64.ActiveCfg = Release|x64 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Release|x64.Build.0 = Release|x64 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Release|x86.ActiveCfg = Release|Win32 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ECEDF19B-B6B3-4AC2-841C-B64ECB21A38B} + EndGlobalSection +EndGlobal diff --git a/vs/TestHDRplus.vcxproj b/vs/TestHDRplus.vcxproj new file mode 100644 index 0000000..a3216ab --- /dev/null +++ b/vs/TestHDRplus.vcxproj @@ -0,0 +1,188 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + 15.0 + {98A6E8C6-16F7-480A-AD0C-DCFE94FD9BC8} + Win32Proj + TestHDRplus + 10.0.17763.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + D:\Workspace\Github\imx291\opencv-4.10.0\build\install\include;D:\Workspace\deps\include;$(ProjectDir)\..\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); + D:\Workspace\Github\imx291\opencv-4.10.0\build\install\x64\vc15\staticlib;D:\Workspace\deps\x64\dbg;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64 + + + false + + + false + D:\Workspace\Github\imx291\opencv-4.10.0\build\install\include;D:\Workspace\deps\include;$(ProjectDir)\..\include;$(VC_IncludePath);$(WindowsSDK_IncludePath); + D:\Workspace\Github\imx291\opencv-4.10.0\build\install\x64\vc15\staticlib;D:\Workspace\deps\x64\rel;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64 + + + + + + Level3 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level3 + Disabled + true + HDRPLUS_NO_DETAILED_OUTPUT;LIBRAW_BUILDLIB;EXV_HAVE_ICONV;exiv2lib_STATIC;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreadedDebug + + + Console + true + /FORCE:MULTIPLE %(AdditionalOptions) + Psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + Level3 + MaxSpeed + true + true + true + LIBRAW_BUILDLIB;EXV_HAVE_ICONV;exiv2lib_STATIC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + Psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + /FORCE:MULTIPLE %(AdditionalOptions) + + + + + + \ No newline at end of file diff --git a/vs/TestHDRplus.vcxproj.filters b/vs/TestHDRplus.vcxproj.filters new file mode 100644 index 0000000..b67bc7c --- /dev/null +++ b/vs/TestHDRplus.vcxproj.filters @@ -0,0 +1,75 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/vs/TestHDRplus.vcxproj.user b/vs/TestHDRplus.vcxproj.user new file mode 100644 index 0000000..a64a449 --- /dev/null +++ b/vs/TestHDRplus.vcxproj.user @@ -0,0 +1,13 @@ + + + + 1.dng 2.dng 3.dng 4.dng 5.dng 6.dng 7.dng 8.dng + D:\Workspace\Github\imx291\dngs\291 + WindowsLocalDebugger + + + out.jpg 1.dng 2.dng 3.dng 4.dng 5.dng 6.dng 7.dng 8.dng + WindowsLocalDebugger + D:\Workspace\Github\imx291\dngs\291 + + \ No newline at end of file diff --git a/vs/pcb.cpp b/vs/pcb.cpp new file mode 100644 index 0000000..fdcc9e1 --- /dev/null +++ b/vs/pcb.cpp @@ -0,0 +1,88 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +// #include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. + +#ifdef _DEBUG + +#pragma comment(lib, "opencv_core4100d.lib") +#pragma comment(lib, "opencv_highgui4100d.lib") +#pragma comment(lib, "opencv_imgproc4100d.lib") +#pragma comment(lib, "opencv_photo4100d.lib") +#pragma comment(lib, "opencv_imgcodecs4100d.lib") +#pragma comment(lib, "opencv_dnn4100d.lib") +#pragma comment(lib, "opencv_xphoto4100d.lib") +#pragma comment(lib, "opencv_mcc4100d.lib") +#pragma comment(lib, "ittnotifyd.lib") +#pragma comment(lib, "libclapackd.lib") +#pragma comment(lib, "zlibd.lib") +#pragma comment(lib, "libwebp.lib") +#pragma comment(lib, "tiffd.lib") +#pragma comment(lib, "jpeg.lib") +#pragma comment(lib, "libpng16d.lib") +#pragma comment(lib, "libsharpyuv.lib") +#pragma comment(lib, "lzma.lib") +#pragma comment(lib, "libopenjp2d.lib") +#pragma comment(lib, "ippicvmt.lib") +#pragma comment(lib, "ippiwd.lib") +#pragma comment(lib, "IlmImfd.lib") +// #pragma comment(lib, "ncnnd.lib") +#pragma comment(lib, "freetyped.lib") +#pragma comment(lib, "bz2d.lib") +#pragma comment(lib, "brotlidec.lib") +#pragma comment(lib, "brotlicommon.lib") +#pragma comment(lib, "libprotobufd.lib") + +#pragma comment(lib, "libjpeg-turbo.lib") + +#pragma comment(lib, "exiv2.lib") +#pragma comment(lib, "expatd.lib") +#pragma comment(lib, "libraw.lib") + +#pragma comment(lib, "libiconv.lib") +#pragma comment(lib, "libcharset.lib") + + + +#else + +#pragma comment(lib, "opencv_core4100.lib") +#pragma comment(lib, "opencv_highgui4100.lib") +#pragma comment(lib, "opencv_imgproc4100.lib") +#pragma comment(lib, "opencv_photo4100.lib") +#pragma comment(lib, "opencv_imgcodecs4100.lib") +#pragma comment(lib, "opencv_dnn4100.lib") +#pragma comment(lib, "opencv_xphoto4100.lib") +#pragma comment(lib, "opencv_mcc4100.lib") +#pragma comment(lib, "ittnotify.lib") +// #pragma comment(lib, "libclapack.lib") +#pragma comment(lib, "zlib.lib") +#pragma comment(lib, "libwebp.lib") +#pragma comment(lib, "libtiff.lib") +#pragma comment(lib, "libopenjp2.lib") +#pragma comment(lib, "libjpeg-turbo.lib") +#pragma comment(lib, "libpng.lib") +// #pragma comment(lib, "libsharpyuv.lib") +// #pragma comment(lib, "lzma.lib") +#pragma comment(lib, "libopenjp2d.lib") +// #pragma comment(lib, "ippicvmt.lib") +// #pragma comment(lib, "ippiwd.lib") +#pragma comment(lib, "IlmImf.lib") +// #pragma comment(lib, "freetype.lib") +// #pragma comment(lib, "bz2.lib") +// #pragma comment(lib, "brotlidec.lib") +// #pragma comment(lib, "brotlicommon.lib") +#pragma comment(lib, "libprotobuf.lib") + + + +#pragma comment(lib, "exiv2.lib") +#pragma comment(lib, "expat.lib") +#pragma comment(lib, "libraw.lib") + +#pragma comment(lib, "libiconv.lib") +#pragma comment(lib, "libcharset.lib") + + +#endif \ No newline at end of file