I'm working in a big project so I decided to take just part of it which you can copy/paste and compile in your machine. You might get weird image at the end but that's fine, that's what I want.
I'm sharing with you this part of the code for the main reason to make it run faster, but if you have any other advice or anything to say about my code feel free.
The program simply takes two images and do some processing and gives you an image at the end as a result. The program is little bit long but I believe it is easy to understand.
You can compile this program:
g++ -g -std=c++1z -Wall -Weffc++ -Ofast -march=native test5.cpp -o test5 -fopenmp `pkg-config --cflags --libs opencv`
And run the program like that:
./test5 image1.png image2.png
This is the code:
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/core/utility.hpp>
#include <iostream>
#include <chrono>
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::microseconds;
class Parallel_process : public cv::ParallelLoopBody
{
private:
cv::Mat img;
std::vector<int> A;
int diff;
public:
Parallel_process(cv::Mat inputImgage, std::vector<int> AA, int diffVal)
: img(inputImgage), A(AA), diff(diffVal){}
virtual void operator()(const cv::Range& range) const
{
for(int i = range.start; i < range.end; i++)
{
cv::Mat in(img, cv::Rect(0, (img.rows/diff)*i, img.cols, img.rows/diff));
std::vector<int> AAA (A);
in.forEach<cv::Vec3f>
(
[&AAA](cv::Vec3f &pixel, const int* po) -> void
{
pixel[0]/=AAA[0];
pixel[1]/=AAA[1];
pixel[2]/=AAA[2];
}
);
}
}
};
cv::Mat dcp(const cv::Mat&, auto, auto, const cv::Mat&, double);
auto calculateSD(const cv::Mat&,auto, auto);
void fftshift(cv::Mat&);
cv::Mat transmission(cv::Mat&, cv::Mat&);
void GammaCorrection(cv::Mat&, unsigned char*, cv::Mat&);
template <typename T, typename ... Ts>
void insert_all(std::vector<T> &vec, Ts ... ts)
{
(vec.push_back(ts), ...);
}
typedef std::vector<std::vector<int> > Matrix;
int main(int argc, char* argv[])
{
cv::Mat im_test = cv::imread(argv[1]);// = cv::Mat::zeros(src.rows, src.cols, CV_32FC1);
auto rows=im_test.rows,
cols=im_test.cols;
cv::Mat fin_img;
cv::Mat src=cv::imread(argv[2]);
cv::Mat src_temp = src.clone();
// build look up table
unsigned char lut[256];
auto fGamma=0.4;
#pragma omp for
for (size_t i=0; i<256; i++)
lut[i] = cv::saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
//std::cout<<cv::getBuildInformation()<<std::endl;
high_resolution_clock::time_point t1(high_resolution_clock::now());
GammaCorrection(src_temp, lut, src_temp);
std::vector<cv::Mat> rgb;
cv::split(src_temp, rgb);
Matrix histSum(3, std::vector<int>(256,0));
src_temp.forEach<cv::Vec3b>
(
[&histSum](cv::Vec3b &pixel, const int* po) -> void
{
++histSum[0][pixel[0]];
++histSum[1][pixel[1]];
++histSum[2][pixel[2]];
}
);
std::vector<int> A(3, 255);
auto A_estim_lambda([&A, rows, cols, &histSum]{
for (auto index=8*rows*cols/1000; index>histSum[0][A[0]]; --A[0])
index -= histSum[0][A[0]];
for (auto index=8*rows*cols/1000; index>histSum[1][A[1]]; --A[1])
index -= histSum[1][A[1]];
for (auto index=8*rows*cols/1000; index>histSum[2][A[2]]; --A[2])
index -= histSum[2][A[2]];
return A;
});
auto AA=A_estim_lambda();
cv::Mat srcN = src_temp.clone();
srcN.convertTo(srcN, CV_32FC3);
im_test.convertTo(im_test, CV_32FC3);
cv::parallel_for_(cv::Range(0, 91), Parallel_process(srcN, AA, 91));
cv::Mat IllumTrans = transmission(srcN, im_test);
std::vector<cv::Mat> rgbDCP;
rgbDCP.reserve(3);
insert_all(rgbDCP, dcp(rgb[0], rows, cols, IllumTrans, A[0]),
dcp(rgb[1], rows, cols, IllumTrans, A[1]),
dcp(rgb[2], rows, cols, IllumTrans, A[2]));
cv::merge(rgbDCP, fin_img);
cv::medianBlur(fin_img, fin_img, 3); //5 c trop
fin_img.convertTo(fin_img, CV_8UC3, 255.0);
cv::Mat temp;
cv::GaussianBlur(fin_img, temp, cv::Size(0, 0), 3);
cv::addWeighted(fin_img, 1.5, temp, -0.5, 0, fin_img);
fGamma=1.5;
for (size_t i=0; i<256; i++)
lut[i] = cv::saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);
GammaCorrection(fin_img, lut, fin_img);
high_resolution_clock::time_point t2(high_resolution_clock::now());
auto timeEnd=1.0/static_cast<double>(duration_cast<microseconds>(t2 - t1).count())*1000000;
std::cout<<timeEnd<<std::endl;
cv::imshow("kernel", fin_img);
cv::waitKey();
return 0;
}
void GammaCorrection(cv::Mat& src, unsigned char* lut, cv::Mat& dst)
{
dst.forEach<cv::Vec3b>
(
[&lut](cv::Vec3b &pixel, const int* po) -> void
{
pixel[0] = lut[(pixel[0])];
pixel[1] = lut[(pixel[1])];
pixel[2] = lut[(pixel[2])];
}
);
}
auto calculateSD(const cv::Mat& src, auto rows, auto cols)
{
double sum{0};
double sq_sum{0};
#pragma omp for
for(auto j=0;j<rows;j++)
for(auto i=0;i<cols;i++)
{
sum += src.at<float>(j,i);
sq_sum += src.at<float>(j,i) * src.at<float>(j,i);
}
double mean = sum / (rows*cols);
double variance = sq_sum / (rows*cols) - mean * mean;
return sqrt(variance);
}
cv::Mat transmission(cv::Mat& srcN, cv::Mat& im_test )
{
cv::Mat srcN_gray;
cv::cvtColor(srcN, srcN_gray, cv::COLOR_RGB2GRAY);
cv::cvtColor(im_test, im_test, cv::COLOR_RGB2GRAY);
cv::Mat srcN_fft;
dft(srcN_gray, srcN_fft, cv::DFT_COMPLEX_OUTPUT) ;
dft(im_test, im_test, cv::DFT_COMPLEX_OUTPUT);
cv::Mat mul_fft;
cv::mulSpectrums(im_test, srcN_fft, mul_fft, 0);
cv::Mat mul_invfft;
dft(mul_fft, mul_invfft, cv::DFT_INVERSE | cv::DFT_SCALE | cv::DFT_REAL_OUTPUT);
fftshift(mul_invfft);
float stddev=calculateSD(mul_invfft, im_test.rows, im_test.cols);
return (1-(mul_invfft-stddev));
}
cv::Mat dcp(const cv::Mat& src, auto rows, auto cols, const cv::Mat& IllumTrans, double A )
{
cv::Mat imJ=cv::Mat::zeros(rows, cols, CV_32FC1);
#pragma omp for
for(auto j=0;j<rows;j++)
for(auto i=0;i<cols;i++)
imJ.at<float>(j,i)= A+((src.at<uchar>(j,i)-A)/std::max(IllumTrans.at<float>(j,i), 0.1f));
double minVal=0, maxVal=0;
minMaxLoc(imJ, &minVal, &maxVal);
return imJ/maxVal;
}
void fftshift(cv::Mat& src)
{
int cx = src.cols/2;
int cy = src.rows/2;
cv::Mat q0(src, cv::Rect(0, 0, cx, cy));
cv::Mat q1(src, cv::Rect(cx, 0, cx, cy));
cv::Mat q2(src, cv::Rect(0, cy, cx, cy));
cv::Mat q3(src, cv::Rect(cx, cy, cx, cy));
cv::Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}