Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to FLIP v1.4 #27

Merged
merged 15 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ _ReSharper*/

# Python ignores
*__pycache__*
python/build/
python/*.egg-info/

# LaTeX ignores
*.synctex.gz
Expand All @@ -42,3 +44,6 @@ _ReSharper*/

# VSCode ignores
*.vscode

# Ignore build
build/
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,11 @@ include(GNUInstallDirs)

option(FLIP_ENABLE_CUDA "Include CUDA version of flip" OFF)

find_package(OpenMP)
if (OPENMP_FOUND)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

add_subdirectory(cpp)
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ For individual contributions to the project, please confer the [Individual Contr
For business inquiries, please visit our website and submit the form: [NVIDIA Research Licensing](https://www.nvidia.com/en-us/research/inquiries/).

# Python (API and Tool)
**Setup** (with Anaconda3):
**Setup** (with pip):
```
conda create -n flip python numpy matplotlib
conda activate flip
conda install -c conda-forge opencv
conda install -c conda-forge openexr-python
cd python
pip install -r requirements.txt .
```

**Usage:**
**Usage:**<br>

*Remember to activate the* `flip` *environment through* `conda activate flip` *before using the tool.*
API:<br>
See the example script `python/api_example.py`. Note that the script requires `matplotlib`.

Tool:
```
python flip.py --reference reference.{exr|png} --test test.{exr|png} [--options]
```
Expand All @@ -67,20 +67,25 @@ The `FLIP.sln` solution contains one CUDA backend project and one pure C++ backe

Compiling the CUDA project requires a CUDA compatible GPU. Instruction on how to install CUDA can be found [here](https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html).

Alternatively, a CMake build can be done by creating a build directory and invoking CMake on the source dir:
Alternatively, a CMake build can be done by creating a build directory and invoking CMake on the source dir (add `--config Release` to build release configuration on Windows):

```
mkdir build
cd build
cmake ..
cmake --build .
cmake --build . [--config Release]
```

CUDA support is enabled via the `FLIP_ENABLE_CUDA`, which can be passed to CMake on the command line with
`-DFLIP_ENABLE_CUDA=ON` or set interactively with `ccmake` or `cmake-gui`.
`FLIP_LIBRARY` option allows to output a library rather than an executable.

**Usage:**
**Usage:**<br>

API:<br>
See the [README](cpp/README.md).

Tool:
```
flip[-cuda].exe --reference reference.{exr|png} --test test.{exr|png} [options]
```
Expand Down Expand Up @@ -118,4 +123,4 @@ Should your work use the ꟻLIP tool in a more general fashion, please cite the

# Acknowledgements
We appreciate the following peoples' contributions to this repository:
Jonathan Granskog, Jacob Munkberg, Jon Hasselgren, Jefferson Amstutz, Alan Wolfe, Killian Herveau, Vinh Truong, Philippe Dagobert, Hannes Hergeth, and Matt Pharr.
Jonathan Granskog, Jacob Munkberg, Jon Hasselgren, Jefferson Amstutz, Alan Wolfe, Killian Herveau, Vinh Truong, Philippe Dagobert, Hannes Hergeth, Matt Pharr, and Tizian Zeltner.
58 changes: 39 additions & 19 deletions cpp/FLIP.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
#include <sstream>
#include <fstream>
#include <limits>
#include "tool/pooling.h"

#ifdef FLIP_ENABLE_CUDA
#include "cuda_runtime.h"
Expand Down Expand Up @@ -2183,7 +2184,7 @@ namespace FLIP
this->setState(CudaTensorState::DEVICE_ONLY);
}
#endif
void computeExposures(std::string tm, float& startExposure, float& stopExposure)
void computeExposures(const std::string tm, float& startExposure, float& stopExposure)
pandersson94 marked this conversation as resolved.
Show resolved Hide resolved
{
int toneMapper = 1;
if (tm == "reinhard")
Expand Down Expand Up @@ -2312,10 +2313,10 @@ namespace FLIP
/** Main function for computing (the image metric called) FLIP between a reference image and a test image.
* See FLIP-tool.cpp for usage of this function.
*
* @param[in] useHDR Set to true if the input images are to be considered containing HDR content, i.e., not necessarily in [0,1].
* @param[in,out] parameters Contains parameters (e.g., PPD, exposure settings,etc). If the exposures have not been set by the user, then those will be computed (and returned).
* @param[in] referenceImageInput Reference input image. For LDR, the content should be in [0,1]. Input is expected in linear RGB.
* @param[in] testImageInput Test input image. For LDR, the content should be in [0,1]. Input is expected in linear RGB.
* @param[in] useHDR Set to true if the input images are to be considered containing HDR content, i.e., not necessarily in [0,1].
* @param[in,out] parameters Contains parameters (e.g., PPD, exposure settings,etc). If the exposures have not been set by the user, then those will be computed (and returned).
* @param[out] errorMapFLIPOutput The FLIP error image in [0,1], a single channel (grayscale).
The user should map it using MapMagma if that is desired (with: errorMapWithMagma.colorMap(errorMapFLIP, FLIP::magmaMap);)
* @param[out] maxErrorExposureMapOutput Exposure map output (only for HDR content).
Expand All @@ -2325,8 +2326,8 @@ namespace FLIP
* @param[in] returnLDRImages True if the next argument should be filled in by FLIP::evaluate().
* @param[out] hdrOutputLDRImages A list of temporary tonemapped output LDR images (in linear RGB) from HDR-FLIP. Images in this order: Ref0, Test0, Ref1, Test1,...
*/
static void evaluate(const bool useHDR, FLIP::Parameters& parameters, FLIP::image<FLIP::color3>& referenceImageInput, FLIP::image<FLIP::color3>& testImageInput,
FLIP::image<float>& errorMapFLIPOutput, FLIP::image<float>& maxErrorExposureMapOutput,
static void evaluate(FLIP::image<FLIP::color3>& referenceImageInput, FLIP::image<FLIP::color3>& testImageInput,
const bool useHDR, FLIP::Parameters& parameters, FLIP::image<float>& errorMapFLIPOutput, FLIP::image<float>& maxErrorExposureMapOutput,
const bool returnLDRFLIPImages, std::vector<FLIP::image<float>*>& hdrOutputFlipLDRImages,
const bool returnLDRImages, std::vector<FLIP::image<FLIP::color3>*>& hdrOutputLDRImages)
{
Expand Down Expand Up @@ -2404,54 +2405,73 @@ namespace FLIP
}

// This variant does not return any LDR images computed by HDR-FLIP and thus avoids two parameters (since using those is a rare use case).
static void evaluate(const bool useHDR, FLIP::Parameters& parameters, FLIP::image<FLIP::color3>& referenceImageInput, FLIP::image<FLIP::color3>& testImageInput,
FLIP::image<float>& errorMapFLIPOutput, FLIP::image<float>& maxErrorExposureMapOutput)
static void evaluate(FLIP::image<FLIP::color3>& referenceImageInput, FLIP::image<FLIP::color3>& testImageInput,
const bool useHDR, FLIP::Parameters& parameters, FLIP::image<float>& errorMapFLIPOutput, FLIP::image<float>& maxErrorExposureMapOutput)
{
std::vector<FLIP::image<float>*> hdrOutputFlipLDRImages;
std::vector<FLIP::image<FLIP::color3>*> hdrOutputLDRImages;
FLIP::evaluate(useHDR, parameters, referenceImageInput, testImageInput, errorMapFLIPOutput, maxErrorExposureMapOutput, false, hdrOutputFlipLDRImages, false, hdrOutputLDRImages);
FLIP::evaluate(referenceImageInput, testImageInput, useHDR, parameters, errorMapFLIPOutput, maxErrorExposureMapOutput, false, hdrOutputFlipLDRImages, false, hdrOutputLDRImages);
}

// This variant does not return the exposure map, which may also be used quite seldom.
static void evaluate(const bool useHDR, FLIP::Parameters& parameters, FLIP::image<FLIP::color3>& referenceImageInput, FLIP::image<FLIP::color3>& testImageInput,
static void evaluate(FLIP::image<FLIP::color3>& referenceImageInput, FLIP::image<FLIP::color3>& testImageInput, const bool useHDR, FLIP::Parameters& parameters,
FLIP::image<float>& errorMapFLIPOutput)
{
FLIP::image<float> maxErrorExposureMapOutput(referenceImageInput.getWidth(), referenceImageInput.getHeight());
FLIP::evaluate(useHDR, parameters, referenceImageInput, testImageInput, errorMapFLIPOutput, maxErrorExposureMapOutput);
FLIP::evaluate(referenceImageInput, testImageInput, useHDR, parameters, errorMapFLIPOutput, maxErrorExposureMapOutput);
}

/** A simplified function for computing (the image metric called) FLIP between a reference image and a test image, without the input images being defined using FLIP::image, etc.
*
* Note that the user is responsible for deallocating the output image in the varible errorMapFLIPOutput. See the desciption of errorMapFLIPOutput below.
*
* @param[in] useHDR Set to true if the input images are to be considered contain HDR content, i.e., not necessarily in [0,1].
* @param[in,out] parameters Contains parameters (e.g., PPD, exposure settings,etc). If the exposures have not been set by the user, then those will be computed (and returned).
* @param[in] imageWidth Width of the reference and test images.
* @param[in] imageHeight Height of the reference and test images.
* @param[in] referenceThreeChannelImage Reference input image. For LDR, the content should be in [0,1]. The image is expected to have 3 floats per pixel and they
* are interleaved, i.e., they come in the order: R0G0B0, R1G1B1, etc. Input is expected to be in linear RGB.
* @param[in] testThreeChannelImage Test input image. For LDR, the content should be in [0,1]. The image is expected to have 3 floats per pixel and they are interleaved.
Input is expected to be in linear RGB
Input is expected to be in linear RGB.
* @param[in] imageWidth Width of the reference and test images.
* @param[in] imageHeight Height of the reference and test images.
* @param[in,out] parameters Contains parameters (e.g., PPD, exposure settings,etc). If the exposures have not been set by the user, then those will be computed (and returned).
* @param[in] useHDR Set to true if the input images are to be considered containing HDR content, i.e., not necessarily in [0,1].
* @param[in] computeMeanFLIPError Set to true if the mean FLIP error should be computed. If false, mean error is set to 0.
* @param[in] applyMagmaMapToOutput A boolean indicating whether the output should have the MagmaMap applied to it before the image is returned.
* @param[out] errorMapFLIPOutput The computed FLIP error image is returned in this variable. If applyMagmaMapToOutput is true, the function will allocate
* three channels (and store the magma-mapped FLIP images in sRGB), and
if it is false, only one channel will be allocated (and the FLIP error is returned in that grayscale image).
* if it is false, only one channel will be allocated (and the FLIP error is returned in that grayscale image).
* Note that the user is responsible for deallocating the errorMapFLIPOutput image.
* @param[out] meanFLIPError Mean FLIP error in the test (testThreeChannelImage) compared to the reference (referenceThreeChannelImage).
*/
static void evaluate(const bool useHDR, FLIP::Parameters& parameters, const int imageWidth, const int imageHeight,
const float* referenceThreeChannelImage, const float* testThreeChannelImage, const bool applyMagmaMapToOutput, float** errorMapFLIPOutput)
static void evaluate(const float* referenceThreeChannelImage, const float* testThreeChannelImage,
const int imageWidth, const int imageHeight, FLIP::Parameters& parameters, const bool useHDR,
pandersson94 marked this conversation as resolved.
Show resolved Hide resolved
const bool computeMeanFLIPError, const bool applyMagmaMapToOutput, float** errorMapFLIPOutput, float& meanFLIPError)
{
FLIP::image<FLIP::color3> referenceImage;
FLIP::image<FLIP::color3> testImage;
FLIP::image<float> errorMapFLIPOutputImage(imageWidth, imageHeight);
referenceImage.setPixels(referenceThreeChannelImage, imageWidth, imageHeight);
testImage.setPixels(testThreeChannelImage, imageWidth, imageHeight);

FLIP::evaluate(useHDR, parameters, referenceImage, testImage, errorMapFLIPOutputImage);
FLIP::evaluate(referenceImage, testImage, useHDR, parameters, errorMapFLIPOutputImage);

#ifdef FLIP_ENABLE_CUDA
errorMapFLIPOutputImage.synchronizeHost();
#endif

// Compute mean FLIP error, if desired.
if (computeMeanFLIPError)
{
FLIPPooling::pooling<float> pooledValues;
// #pragma omp parallel for // TODO: Use pragma here? Does it work for CUDA?
for (int y = 0; y < errorMapFLIPOutputImage.getHeight(); y++)
{
for (int x = 0; x < errorMapFLIPOutputImage.getWidth(); x++)
{
pooledValues.update(x, y, errorMapFLIPOutputImage.get(x, y));
}
}
meanFLIPError = pooledValues.getMean();
}

if (applyMagmaMapToOutput)
{
*errorMapFLIPOutput = new float[imageWidth * imageHeight * 3];
Expand Down
16 changes: 13 additions & 3 deletions cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ can be found [here](misc/separatedConvolutions.pdf).

With v1.3, we have switched to a single header [FLIP.h](FLIP.h) for easier integration into other projects.

Since v1.4, the code is contained in [FLIPToolHelpers.h](FLIPToolHelpers.h), but is still run through [FLIP-tool.cpp](FLIP-tool.cpp) and [FLIP-tool.cu](FLIP-tool.cu), respectively.
pandersson94 marked this conversation as resolved.
Show resolved Hide resolved


# License

Expand Down Expand Up @@ -47,21 +49,21 @@ For business inquiries, please visit our website and submit the form: [NVIDIA Re
```
- The FLIP.sln solution contains one CUDA backend project and one pure C++ backend project for the FLIP tool.
- Compiling the CUDA project requires a CUDA compatible GPU. Instruction on how to install CUDA can be found [here](https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html).
- Alternatively, a CMake build can be done by creating a build directory and invoking CMake on the source `cpp` dir:
- Alternatively, a CMake build can be done by creating a build directory and invoking CMake on the source `cpp` dir (add `--config Release` to build release configuration on Windows):

```
mkdir build
cd build
cmake ..
cmake --build .
cmake --build . [--config Release]
```

CUDA support is enabled via the `FLIP_ENABLE_CUDA`, which can be passed to CMake on the command line with `-DFLIP_ENABLE_CUDA=ON` or set interactively with `ccmake` or `cmake-gui`.
`FLIP_LIBRARY` option allows to output a library rather than an executable.
- Usage: `flip[-cuda].exe --reference reference.{exr|png} --test test.{exr|png} [options]`, where the list of options can be seen by `flip[-cuda].exe -h`.
- Tested on Windows 10 version 22H2 and Windows 11 version 23H2 with CUDA 12.3. Compiled with Visual Studio 2022. If you use another version of CUDA, you will need to change the `CUDA 12.3` strings in the `CUDA.vcxproj` file accordingly.
- `../tests/test.py` contains simple tests used to test whether code updates alter results.
- Weighted histograms are output as Python scripts. Running the script will create a PDF version of the histogram. Note that the python script has some dependencies, so it is best to `conda activate flip` before it is executed. See [README.md](https://github.com/NVlabs/flip/blob/main/python/README.md) for our Python code to set this up.
- Weighted histograms are output as Python scripts. Running the script will create a PDF version of the histogram. Notice that those scripts require `numpy` and `matplotlib`, both of which may be installed using pip. These are automantically installed when installing the Python version of ꟻLIP (see [README.md](https://github.com/NVlabs/flip/blob/main/python/README.md)).
- The naming convention used for the ꟻLIP tool's output is as follows (where `ppd` is the assumed number of pixels per degree,
`tm` is the tone mapper assumed by HDR-ꟻLIP, `cstart` and `cstop` are the shortest and longest exposures, respectively, assumed by HDR-ꟻLIP,
with `p` indicating a positive value and `m` indicating a negative value,
Expand All @@ -74,6 +76,8 @@ For business inquiries, please visit our website and submit the form: [NVIDIA Re

LDR-ꟻLIP: `flip.<reference>.<test>.<ppd>ppd.ldr.png`<br>
Weighted histogram: `weighted_histogram.reference>.<test>.<ppd>ppd.ldr.py`<br>
Overlapping weighted histogram: `overlapping_weighted_histogram.<reference>.<test1>.<test2>.<ppd>ppd.ldr.py`<br>
Text file: `pooled_values.<reference>.<test>.<ppd>ppd.ldr.txt`<br>

*High dynamic range images:*<br>

Expand All @@ -82,13 +86,17 @@ For business inquiries, please visit our website and submit the form: [NVIDIA Re
Intermediate LDR-ꟻLIP maps: `flip.<reference>.<test>.<ppd>ppd.ldr.<tm>.<nnn>.<exp>.png`<br>
Intermediate LDR images: `<reference|test>.<tm>.<nnn>.<exp>.png`<br>
Weighted histogram: `weighted_histogram.<reference>.<test>.<ppd>ppd.hdr.<tm>.<cstart>_to_<cstop>.<N>.py`<br>
Overlapping weighted histogram: `overlapping_weighted_histogram.<reference>.<test1>.<test2>.<ppd>ppd.hdr.<tm>.<cstart>_to_<cstop>.<N>.py`<br>
Text file: `pooled_values.<reference>.<test>.<ppd>ppd.hdr.<tm>.<cstart>_to_<cstop>.<N>.txt`<br>

**With** `--basename <name>` **(note: not applicable if more than one test image is evaluated):**

*Low dynamic range images:*<br>

LDR-ꟻLIP: `<name>.png`<br>
Weighted histogram: `<name>.py`<br>
Overlapping weighted histogram: N/A<br>
Text file: `<name>.txt`<br>

*High dynamic range images:*<br>

Expand All @@ -97,6 +105,8 @@ For business inquiries, please visit our website and submit the form: [NVIDIA Re
Intermediate LDR-ꟻLIP maps: `<name>.<nnn>.png`<br>
Intermediate LDR images: `<name>.reference|test.<nnn>.png`<br>
Weighted histogram: `<name>.py`<br>
Overlapping weighted histogram: N/A<br>
Text file: `<name>.txt`<br>

**Example usage:**
After compiling the `FLIP.sln` project, navigate to the `flip[-cuda].exe` executable and try:
Expand Down
2 changes: 1 addition & 1 deletion cpp/tool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# SPDX-FileCopyrightText: Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES
# SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES
# SPDX-License-Identifier: BSD-3-Clause
#################################################################################

Expand Down
1 change: 1 addition & 0 deletions cpp/tool/CPP.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<ClInclude Include="..\FLIP.h" />
<ClInclude Include="commandline.h" />
<ClInclude Include="filename.h" />
<ClInclude Include="FLIPToolHelpers.h" />
<ClInclude Include="imagehelpers.h" />
<ClInclude Include="pooling.h" />
<ClInclude Include="stb_image.h" />
Expand Down
3 changes: 3 additions & 0 deletions cpp/tool/CPP.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<ClInclude Include="filename.h">
<Filter>tool</Filter>
</ClInclude>
<ClInclude Include="FLIPToolHelpers.h">
<Filter>tool</Filter>
</ClInclude>
<ClInclude Include="imagehelpers.h">
<Filter>tool</Filter>
</ClInclude>
Expand Down
1 change: 1 addition & 0 deletions cpp/tool/CUDA.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ClInclude Include="..\FLIP.h" />
<ClInclude Include="commandline.h" />
<ClInclude Include="filename.h" />
<ClInclude Include="FLIPToolHelpers.h" />
<ClInclude Include="imagehelpers.h" />
<ClInclude Include="pooling.h" />
<ClInclude Include="stb_image.h" />
Expand Down
3 changes: 3 additions & 0 deletions cpp/tool/CUDA.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<ClInclude Include="filename.h">
<Filter>tool</Filter>
</ClInclude>
<ClInclude Include="FLIPToolHelpers.h">
<Filter>tool</Filter>
</ClInclude>
<ClInclude Include="imagehelpers.h">
<Filter>tool</Filter>
</ClInclude>
Expand Down
Loading
Loading