Skip to content

Commit

Permalink
Add OpenCV function NLMeans
Browse files Browse the repository at this point in the history
add associated parameters
  • Loading branch information
Stella TAN committed Aug 10, 2022
1 parent 1ef3bad commit 2d538d9
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ set(ALICEVISION_HAVE_OCVSIFT 0)

if(ALICEVISION_BUILD_SFM)
if(NOT ALICEVISION_USE_OPENCV STREQUAL "OFF")
find_package(OpenCV COMPONENTS core imgproc video imgcodecs videoio features2d)
find_package(OpenCV COMPONENTS core imgproc video imgcodecs videoio features2d photo)

if(OpenCV_FOUND)
# We do not set the minimal version directly in find_package
Expand Down
30 changes: 26 additions & 4 deletions src/aliceVision/image/convertionOpenCV.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,35 @@ inline cv::Mat imageRGBAToCvMatBGR(const image::Image<image::RGBAfColor>& img, i
*/
inline void cvMatBGRToImageRGBA(const cv::Mat& img, image::Image<image::RGBAfColor>& imageOut)
{
const float charToFloat = 1.0f / 255.0f;
for(int row = 0; row < imageOut.Height(); row++)
{
const cv::Vec3f* rowPtr = img.ptr<cv::Vec3f>(row);
for(int col = 0; col < imageOut.Width(); col++)
switch(img.type())
{
const cv::Vec3f& matPixel = rowPtr[col];
imageOut(row, col) = image::RGBAfColor(matPixel[2], matPixel[1], matPixel[0], imageOut(row, col).a());
case CV_32FC3:
{
const cv::Vec3f* rowPtr = img.ptr<cv::Vec3f>(row);
for(int col = 0; col < imageOut.Width(); col++)
{
const cv::Vec3f& matPixel = rowPtr[col];
imageOut(row, col) =
image::RGBAfColor(matPixel[2], matPixel[1], matPixel[0], imageOut(row, col).a());
}
break;
}
case CV_8UC3:
{
const cv::Vec3b* rowPtr = img.ptr<cv::Vec3b>(row);
for(int col = 0; col < imageOut.Width(); col++)
{
const cv::Vec3b& matPixel = rowPtr[col];
imageOut(row, col) = image::RGBAfColor(matPixel[2] * charToFloat, matPixel[1] * charToFloat,
matPixel[0] * charToFloat, imageOut(row, col).a());
}
break;
}
default:
std::runtime_error("Cannot handle OpenCV matrix type '" + std::to_string(img.type()) + "'.");
}
}
}
Expand Down
96 changes: 85 additions & 11 deletions src/software/utils/main_imageProcessing.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#include <aliceVision/image/all.hpp>
#include <aliceVision/system/cmdline.hpp>
#include <aliceVision/system/Logger.hpp>
Expand All @@ -17,6 +16,9 @@

#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_OPENCV)
#include <opencv2/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/photo.hpp>
#include <opencv2/photo/cuda.hpp>
#endif

#include <OpenImageIO/imageio.h>
Expand Down Expand Up @@ -212,6 +214,39 @@ inline std::istream& operator>>(std::istream& in, EImageFormat& e)
return in;
}

struct NLMeansFilterParams
{
bool enabled;
float filterStrength;
float filterStrengthColor;
int templateWindowSize;
int searchWindowSize;
};

std::istream& operator>>(std::istream& in, NLMeansFilterParams& nlmParams)
{
std::string token;
in >> token;
std::vector<std::string> splitParams;
boost::split(splitParams, token, boost::algorithm::is_any_of(":"));
if(splitParams.size() != 5)
throw std::invalid_argument("Failed to parse NLMeansFilterParams from: " + token);
nlmParams.enabled = boost::to_lower_copy(splitParams[0]) == "true";
nlmParams.filterStrength = boost::lexical_cast<float>(splitParams[1]);
nlmParams.filterStrengthColor = boost::lexical_cast<float>(splitParams[2]);
nlmParams.templateWindowSize = boost::lexical_cast<int>(splitParams[3]);
nlmParams.searchWindowSize = boost::lexical_cast<int>(splitParams[4]);

return in;
}

inline std::ostream& operator<<(std::ostream& os, const NLMeansFilterParams& nlmParams)
{
os << nlmParams.enabled << ":" << nlmParams.filterStrength << ":" << nlmParams.filterStrengthColor << ":"
<< nlmParams.templateWindowSize << ":" << nlmParams.searchWindowSize;
return os;
}

struct ProcessingParams
{
bool reconstructedViewsOnly = false;
Expand All @@ -228,6 +263,7 @@ struct ProcessingParams
{
false, // enable
3, // width

1.0f, // contrast
0.0f // threshold
};
Expand Down Expand Up @@ -255,6 +291,14 @@ struct ProcessingParams
true // mono
};

NLMeansFilterParams nlmFilter =
{
false, // enable
5.0f, // filterStrength
5.0f, // filterStrengthColor
7, // templateWindowSize
21 // searchWindowSize
};
};


Expand Down Expand Up @@ -403,6 +447,27 @@ void processImage(image::Image<image::RGBAfColor>& image, const ProcessingParams
oiio::ImageBuf inBuf(oiio::ImageSpec(image.Width(), image.Height(), nchannels, oiio::TypeDesc::FLOAT), image.data());
oiio::ImageBufAlgo::noise(inBuf, ENoiseMethod_enumToString(pParams.noise.method), pParams.noise.A, pParams.noise.B, pParams.noise.mono);
}

if(pParams.nlmFilter.enabled)
{
#if ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_OPENCV)

// Create temporary OpenCV Mat (keep only 3 Channels) to handled Eigen data of our image
cv::Mat openCVMatIn = image::imageRGBAToCvMatBGR(image, CV_8UC3);
cv::Mat openCVMatOut(image.Width(), image.Height(), CV_8UC3);

cv::fastNlMeansDenoisingColored(openCVMatIn, openCVMatOut, pParams.nlmFilter.filterStrength,
pParams.nlmFilter.filterStrengthColor, pParams.nlmFilter.templateWindowSize,
pParams.nlmFilter.searchWindowSize);

// Copy filtered data from openCV Mat(3 channels) to our image(keep the alpha channel unfiltered)
image::cvMatBGRToImageRGBA(openCVMatOut, image);

#else
throw std::invalid_argument(
"Unsupported mode! If you intended to use a non-local means filter, please add OpenCV support.");
#endif
}
}

void saveImage(image::Image<image::RGBAfColor>& image, const std::string& inputPath, const std::string& outputPath,
Expand Down Expand Up @@ -555,14 +620,22 @@ int aliceVision_main(int argc, char * argv[])
" * TileGridSize: Sets Size Of Grid For Histogram Equalization. Input Image Will Be Divided Into Equally Sized Rectangular Tiles.")

("noiseFilter", po::value<NoiseFilterParams>(&pParams.noise)->default_value(pParams.noise),
"Noise Filter parameters:\n"
" * Enabled: Add Noise.\n"
" * method: There are several noise types to choose from:\n"
" - uniform: adds noise values uninformly distributed on range [A,B).\n"
" - gaussian: adds Gaussian (normal distribution) noise values with mean value A and standard deviation B.\n"
" - salt: changes to value A a portion of pixels given by B.\n"
" * A, B: parameters that have a different interpretation depending on the method chosen.\n"
" * mono: If is true, a single noise value will be applied to all channels otherwise a separate noise value will be computed for each channel.")
"Noise Filter parameters:\n"
" * Enabled: Add Noise.\n"
" * method: There are several noise types to choose from:\n"
" - uniform: adds noise values uninformly distributed on range [A,B).\n"
" - gaussian: adds Gaussian (normal distribution) noise values with mean value A and standard deviation B.\n"
" - salt: changes to value A a portion of pixels given by B.\n"
" * A, B: parameters that have a different interpretation depending on the method chosen.\n"
" * mono: If is true, a single noise value will be applied to all channels otherwise a separate noise value will be computed for each channel.")

("nlmFilter", po::value<NLMeansFilterParams>(&pParams.nlmFilter)->default_value(pParams.nlmFilter),
"Non local means Filter parameters:\n"
" * Enabled: Use non local means Filter.\n"
" * H: Parameter regulating filter strength. Bigger H value perfectly removes noise but also removes image details, smaller H value preserves details but also preserves some noise.\n"
" * HColor: Parameter regulating filter strength for color images only. Normally same as Filtering Parameter H. Not necessary for grayscale images\n "
" * templateWindowSize: Size in pixels of the template patch that is used to compute weights. Should be odd. \n"
" * searchWindowSize:Size in pixels of the window that is used to compute weighted average for given pixel. Should be odd. Affect performance linearly: greater searchWindowsSize - greater denoising time.")

("outputFormat", po::value<EImageFormat>(&outputFormat)->default_value(outputFormat),
"Output image format (rgba, rgb, grayscale)")
Expand Down Expand Up @@ -624,9 +697,10 @@ int aliceVision_main(int argc, char * argv[])
}

#if !ALICEVISION_IS_DEFINED(ALICEVISION_HAVE_OPENCV)
if(pParams.bilateralFilter.enabled || pParams.claheFilter.enabled)
if(pParams.bilateralFilter.enabled || pParams.claheFilter.enabled || pParams.nlmFilter.enabled)
{
ALICEVISION_LOG_ERROR("Invalid option: BilateralFilter and claheFilter can't be used without openCV !");
ALICEVISION_LOG_ERROR(
"Invalid option: BilateralFilter, claheFilter and nlmFilter can't be used without openCV !");
return EXIT_FAILURE;
}
#endif
Expand Down

0 comments on commit 2d538d9

Please sign in to comment.