Ask Your Question
3

Matching colors between two pictures in OpenCV?

asked 2017-11-12 08:03:29 -0600

xihe gravatar image

updated 2017-11-12 09:18:08 -0600

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: Picture I want to match Picture I want to change green intensity of

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 flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
3

answered 2017-11-12 09:19:25 -0600

berak gravatar image

maybe a simple mean subtraction will already get you close: image description

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
edit flag offensive delete link more
2

answered 2017-11-12 10:18:56 -0600

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

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

image description image description

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

image description image description

#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++)
    {
        if (mask(p) > 0)
        {
            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);

        do1ChnHist(chns[i], src_mask, src_hist, src_cdf);
        do1ChnHist(chns1[i], dst_mask, dst_hist, dst_cdf);

        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 src = imread("e:/test/iO6S1m.png");
    Mat dst = imread("e:/test/kfku3m.png");
    Mat mask = Mat(src.size(), CV_8U, Scalar(255));

    histMatchRGB(dst, mask, src, mask);
    return 0;
}
edit flag offensive delete link more

Comments

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?

xihe gravatar imagexihe ( 2017-11-12 11:59:39 -0600 )edit

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

sturkmen gravatar imagesturkmen ( 2017-11-12 13:22:53 -0600 )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 ?)

berak gravatar imageberak ( 2017-11-12 13:27:15 -0600 )edit
1

just now i found it.link

sturkmen gravatar imagesturkmen ( 2017-11-12 13:35:22 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2017-11-12 08:03:29 -0600

Seen: 6,680 times

Last updated: Nov 12 '17