Matching colors between two pictures in OpenCV?

As the title is saying, I am wondering about if there are any good ways to match the colors between two pictures, more precisely I want to adjust the green intensity of one picture to match the other:

For the pictures above I want to adjust the color intensities(here it seems like adjusting the green intensity will be sufficient) of the lower picture so that it approximately has the same color intensities of the upper picture. Are there any ways I can do this with OpenCV? If not are there other good libraries that I can use to do this?

This could easily be done with image editing software such as Photoshop, but since I have to do this for approximately 6k pictures, it is not convenient for me. Hence the thought of using OpenCV.

edit retag close merge delete

Sort by ยป oldest newest most voted

maybe a simple mean subtraction will already get you close:

Scalar m1,d1;
meanStdDev(im1,m1,d1); // "lower"

Scalar m2,d2;
meanStdDev(img2,m2,d2); //"upper"

cerr << m1 << d1 << endl;
cerr << m2 << d2 << endl;

Scalar mdiff = m1-m2;

img1 -= mdiff;

Scalar m3,d3;
meanStdDev(img1 ,m3, d3);
cerr << m3 << d3 << endl;

[128.965, 129.764, 131.6, 0][61.9842, 62.0493, 57.8344, 0]   // img1
[44.4416, 79.0048, 72.5779, 0][16.5399, 34.9685, 31.0255, 0] // img2
[53.9764, 82.1853, 77.0983, 0][48.514, 56.5164, 49.9328, 0]  // result

more

i have copied the following code from a previous answer by @berak

    Mat src = imread("iO6S1m.png");


    Mat src = imread("kfku3m.png");


#include <opencv2/opencv.hpp>
using namespace cv;

#include <vector>
using namespace std;

#define HISTMATCH_EPSILON 0.000001
#define BTM_DEBUG
// Compute histogram and CDF for an image with mask
void do1ChnHist(const Mat_<uchar> &img, const Mat_<uchar> &mask, Mat_<double> &h, Mat_<double> &cdf)
{
for (size_t p = 0; p<img.total(); p++)
{
{
uchar c = img(p);
h(c) += 1.0;
}
}

normalize(h, h, 1, 0, NORM_MINMAX);

cdf(0) = h(0);
for (int j = 1; j<256; j++)
{
cdf(j) = cdf(j - 1) + h(j);
}

normalize(cdf, cdf, 1, 0, NORM_MINMAX);
}

// match histograms of 'src' to that of 'dst', according to both masks
void histMatchRGB(Mat &src, const Mat &src_mask, const Mat &dst, const Mat &dst_mask)
{
#ifdef BTM_DEBUG
namedWindow("original source", CV_WINDOW_AUTOSIZE);
imshow("original source", src);
namedWindow("original query", CV_WINDOW_AUTOSIZE);
imshow("original query", dst);
#endif

vector<Mat_<uchar>> chns, chns1;
split(src, chns);
split(dst, chns1);

for (int i = 0; i<3; i++)
{
Mat_<double> src_hist = Mat_<double>::zeros(1, 256);
Mat_<double> dst_hist = Mat_<double>::zeros(1, 256);
Mat_<double> src_cdf = Mat_<double>::zeros(1, 256);
Mat_<double> dst_cdf = Mat_<double>::zeros(1, 256);

uchar last = 0;

Mat_<uchar> lut(1, 256);
for (int j = 0; j<src_cdf.cols; j++)
{
double F1j = src_cdf(j);

for (uchar k = last; k<dst_cdf.cols; k++)
{
double F2k = dst_cdf(k);
if (abs(F2k - F1j) < HISTMATCH_EPSILON || F2k > F1j)
{
lut(j) = k;
last = k;
break;
}
}
}

LUT(chns[i], lut, chns[i]);
}

Mat res;
merge(chns, res);

#ifdef BTM_DEBUG
namedWindow("matched", CV_WINDOW_AUTOSIZE);
imshow("matched", res);

waitKey(0);
#endif

res.copyTo(src);
}

int main(int argc, char **argv)
{
Mat mask = Mat(src.size(), CV_8U, Scalar(255));

return 0;
}

more

Thank you for a well written answer! I haven't had the time to go through the code thoroughly . But would the quality of the result reduce drastically if the source image had another resolution than the destination image? For instance. if the input is 720p and the output image is 1080p?

( 2017-11-12 11:59:39 -0500 )edit

as i said i just copy paste the code. maybe @berak have an answer for your comment.

( 2017-11-12 13:22:53 -0500 )edit

@sturkmen, we'll have a pretty good laugh on that, (later), ...

but i do not recall writing that code (though it fairly looks, what equalizeHist is doing) ;)

(do you have a link to that ?)

( 2017-11-12 13:27:15 -0500 )edit
1