Ask Your Question
1

Copy histogram of an image to another

asked 2016-03-17 04:03:32 -0600

bjorn89 gravatar image

updated 2016-06-01 18:11:48 -0600

Hi all! Here's my problem: I have two images of the same thing acquired with different illumination condition. I found that is possible to copy the histogram of a reference image to a destination image, and it's called histogram specification or histogram matching. As shown here https://studentathome.wordpress.com/2..., in matlab it's pretty simple. There is a way to do the same thing on OpenCV?

EDIT The code linked on the page link text gives me error on the lines:

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

it says that I can't pass a matrix (src_hist etc) because the function accepts double*. How can I make it work with Opencv 3.1?

EDIT 2 Now it compiles and run, but i obtain as a matched image a black image. Since I need to match the histogram of the whole image, I created as mask a Mat on ones. Am I doing right? Any suggestion?

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
2

answered 2016-03-18 06:21:03 -0600

berak gravatar image

imho, if you use "typed" Mat's it all gets much easier, since you can skip all the at<type> and ptr<type> calls:

#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 dst = imread("im/bb_beach.png");
    Mat src = imread("im/bb_cam.png");
    Mat mask = Mat(src.size(), CV_8U, Scalar(255));
    //Mat src_mask = imread("image008_mask.bmp",0);
    //Mat dst_mask = imread("image003_mask.bmp",0);

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

Comments

Hi! I've tried your solution and it works, but it doesn't match perfectly the histogram. it is normal? I've seen that the matlab module matches perfectly!

bjorn89 gravatar imagebjorn89 ( 2016-03-18 08:16:35 -0600 )edit

idk, all i tried is to make the code run. (and there's no matlab here)

berak gravatar imageberak ( 2016-03-18 08:25:09 -0600 )edit
0

answered 2016-03-17 04:33:06 -0600

I think this source is a sample you may want.

edit flag offensive delete link more

Comments

Hi! If found by myself the same website, but I can't make it work with opencv 3.1. In particular, it gives me error on vector (which I correct by using vector <intZ), on double* _src_cdf = src_cdf.ptr(); (which I can't resolve), on LUT(chns[i], lut, chns[i]);(it undelines chns1, also this unresolved) and on every h[c][/ c] (it underlines the slash). How can I proceed?

bjorn89 gravatar imagebjorn89 ( 2016-03-18 03:35:39 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2016-03-17 04:03:32 -0600

Seen: 1,557 times

Last updated: Mar 18 '16