<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Recoloring via Histogram Matching with OpenCV [w/ code]</title>
	<atom:link href="http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/</link>
	<description>On software, code, the internet and more.</description>
	<lastBuildDate>Wed, 08 Feb 2012 15:59:56 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
	<item>
		<title>By: Roy</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-15978</link>
		<dc:creator>Roy</dc:creator>
		<pubDate>Sat, 31 Dec 2011 07:32:01 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-15978</guid>
		<description>@rz
Thanks, but, what is changed in the code?</description>
		<content:encoded><![CDATA[<p>@rz<br />
Thanks, but, what is changed in the code?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: rz</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-15904</link>
		<dc:creator>rz</dc:creator>
		<pubDate>Fri, 30 Dec 2011 02:57:21 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-15904</guid>
		<description>void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf);

// Match Red, Green and Blue histograms of ‘src’ to that of ‘dst’, according to both masks.
// Based on: http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/
// Modified by Shervin Emami so it can also pass NULL for the masks if you want to process the whole image.
void histMatchRGB(cv::Mat&amp; src, const cv::Mat* src_mask, const cv::Mat&amp; dst, const cv::Mat* dst_mask)
{
double const HISTMATCH_EPSILON = 0.000001;

vector chns;  
cv::split(src,chns);
vector chns1;  
cv::split(dst,chns1);
cv::Mat src_hist = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat dst_hist = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat src_cdf = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat dst_cdf = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat Mv(1,256,CV_8UC1);
uchar* M = Mv.ptr();

for(int i=0;i&lt;3;i++)
{
	src_hist.setTo(0);
	dst_hist.setTo(0);
	src_cdf.setTo(0);
	src_cdf.setTo(0);

	double* _src_cdf = src_cdf.ptr();
	double* _dst_cdf = dst_cdf.ptr();
	double* _src_hist = src_hist.ptr();
	double* _dst_hist = dst_hist.ptr();

	do1ChnHist(chns[i], src_mask, _src_hist, _src_cdf);
	do1ChnHist(chns1[i], dst_mask, _dst_hist, _dst_cdf);

	uchar last = 0;


	for(int j=0;j&lt;src_cdf.cols;j++)
	{
		double F1j = _src_cdf[j];

		for(uchar k = last; k (F1j - HISTMATCH_EPSILON))
			{
				M[j] = k;
				last = k;
				break;
			}
		}
	}

	cv::Mat lut(1,256,CV_8UC1,M);
	cv::LUT(chns[i],lut,chns[i]);
	}

cv::Mat res;
cv::merge(chns,res);

res.copyTo(src);
}

// Compute histogram and CDF for an image with mask
void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf)
{
cv::Mat _t = _i.reshape(1,1);

// Get the histogram with or without the mask
if (mask) 
{
	cv::Mat _tm;
	mask-&gt;copyTo(_tm);
	_tm = _tm.reshape(1,1);
	for(int p=0; p&lt;_t.cols; p++) 
	{
		CvPoint po;
		po.x = 0;
		po.y = p;
		uchar m = _tm.at&lt;&gt;(po);
		

		if(m &gt; 0)
		{ // Mask value
			uchar c = _t.at(0,p); // Image value
			h[c][/c] += 1.0;    // Histogram
        }
    }
}
else 
{
	//uchar* Uptr = _t.ptr(0);
	for(int p = 0; p &lt; _t.cols; p++) 
	{
		//Uptr[p] = saturate_cast((Uptr[p]-128)/2 + 128);
        uchar c = _t.at(0, p);
		//Vxy = saturate_cast((Vxy-128)/2 + 128);

		//uchar c = _t(0,p);   // Image value
		h[c][/c]+= 1.0; // Histogram
	}
}

//normalize hist to a max value of 1.0
cv::Mat _tmp(1,256,CV_64FC1,h);
double minVal,maxVal;
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);
_tmp = _tmp / maxVal;

// Calculate the Cumulative Distribution Function
cdf[0] = h[0];
for(int j=1; j&lt;256; j++) 
{
	cdf[j] = cdf[j-1]+h[j];
}

//normalize CDF to a max value of 1.0
_tmp.data = (uchar*)cdf; // Array of doubles, but gets a byte pointer.
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);
_tmp = _tmp / maxVal;
}</description>
		<content:encoded><![CDATA[<p>void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf);</p>
<p>// Match Red, Green and Blue histograms of ‘src’ to that of ‘dst’, according to both masks.<br />
// Based on: <a href="http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/" rel="nofollow">http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/</a><br />
// Modified by Shervin Emami so it can also pass NULL for the masks if you want to process the whole image.<br />
void histMatchRGB(cv::Mat&amp; src, const cv::Mat* src_mask, const cv::Mat&amp; dst, const cv::Mat* dst_mask)<br />
{<br />
double const HISTMATCH_EPSILON = 0.000001;</p>
<p>vector chns;<br />
cv::split(src,chns);<br />
vector chns1;<br />
cv::split(dst,chns1);<br />
cv::Mat src_hist = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat dst_hist = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat src_cdf = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat dst_cdf = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat Mv(1,256,CV_8UC1);<br />
uchar* M = Mv.ptr();</p>
<p>for(int i=0;i&lt;3;i++)<br />
{<br />
	src_hist.setTo(0);<br />
	dst_hist.setTo(0);<br />
	src_cdf.setTo(0);<br />
	src_cdf.setTo(0);</p>
<p>	double* _src_cdf = src_cdf.ptr();<br />
	double* _dst_cdf = dst_cdf.ptr();<br />
	double* _src_hist = src_hist.ptr();<br />
	double* _dst_hist = dst_hist.ptr();</p>
<p>	do1ChnHist(chns[i], src_mask, _src_hist, _src_cdf);<br />
	do1ChnHist(chns1[i], dst_mask, _dst_hist, _dst_cdf);</p>
<p>	uchar last = 0;</p>
<p>	for(int j=0;j&lt;src_cdf.cols;j++)<br />
	{<br />
		double F1j = _src_cdf[j];</p>
<p>		for(uchar k = last; k (F1j &#8211; HISTMATCH_EPSILON))<br />
			{<br />
				M[j] = k;<br />
				last = k;<br />
				break;<br />
			}<br />
		}<br />
	}</p>
<p>	cv::Mat lut(1,256,CV_8UC1,M);<br />
	cv::LUT(chns[i],lut,chns[i]);<br />
	}</p>
<p>cv::Mat res;<br />
cv::merge(chns,res);</p>
<p>res.copyTo(src);<br />
}</p>
<p>// Compute histogram and CDF for an image with mask<br />
void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf)<br />
{<br />
cv::Mat _t = _i.reshape(1,1);</p>
<p>// Get the histogram with or without the mask<br />
if (mask)<br />
{<br />
	cv::Mat _tm;<br />
	mask-&gt;copyTo(_tm);<br />
	_tm = _tm.reshape(1,1);<br />
	for(int p=0; p&lt;_t.cols; p++)<br />
	{<br />
		CvPoint po;<br />
		po.x = 0;<br />
		po.y = p;<br />
		uchar m = _tm.at&lt;&gt;(po);</p>
<p>		if(m &gt; 0)<br />
		{ // Mask value<br />
			uchar c = _t.at(0,p); // Image value<br />
			h += 1.0;    // Histogram<br />
        }<br />
    }<br />
}<br />
else<br />
{<br />
	//uchar* Uptr = _t.ptr(0);<br />
	for(int p = 0; p &lt; _t.cols; p++)<br />
	{<br />
		//Uptr[p] = saturate_cast((Uptr[p]-128)/2 + 128);<br />
        uchar c = _t.at(0, p);<br />
		//Vxy = saturate_cast((Vxy-128)/2 + 128);</p>
<p>		//uchar c = _t(0,p);   // Image value<br />
		h+= 1.0; // Histogram<br />
	}<br />
}</p>
<p>//normalize hist to a max value of 1.0<br />
cv::Mat _tmp(1,256,CV_64FC1,h);<br />
double minVal,maxVal;<br />
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);<br />
_tmp = _tmp / maxVal;</p>
<p>// Calculate the Cumulative Distribution Function<br />
cdf[0] = h[0];<br />
for(int j=1; j&lt;256; j++)<br />
{<br />
	cdf[j] = cdf[j-1]+h[j];<br />
}</p>
<p>//normalize CDF to a max value of 1.0<br />
_tmp.data = (uchar*)cdf; // Array of doubles, but gets a byte pointer.<br />
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);<br />
_tmp = _tmp / maxVal;<br />
}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: rz</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-15903</link>
		<dc:creator>rz</dc:creator>
		<pubDate>Fri, 30 Dec 2011 02:55:08 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-15903</guid>
		<description>my minor changes

void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf);

// Match Red, Green and Blue histograms of ‘src’ to that of ‘dst’, according to both masks.
// Based on: http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/
// Modified by Shervin Emami so it can also pass NULL for the masks if you want to process the whole image.
void histMatchRGB(cv::Mat&amp; src, const cv::Mat* src_mask, const cv::Mat&amp; dst, const cv::Mat* dst_mask)
{
double const HISTMATCH_EPSILON = 0.000001;

vector chns;  
cv::split(src,chns);
vector chns1;  
cv::split(dst,chns1);
cv::Mat src_hist = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat dst_hist = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat src_cdf = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat dst_cdf = cv::Mat::zeros(1,256,CV_64FC1);
cv::Mat Mv(1,256,CV_8UC1);
uchar* M = Mv.ptr();

for(int i=0;i&lt;3;i++)
{
	src_hist.setTo(0);
	dst_hist.setTo(0);
	src_cdf.setTo(0);
	src_cdf.setTo(0);

	double* _src_cdf = src_cdf.ptr();
	double* _dst_cdf = dst_cdf.ptr();
	double* _src_hist = src_hist.ptr();
	double* _dst_hist = dst_hist.ptr();

	do1ChnHist(chns[i], src_mask, _src_hist, _src_cdf);
	do1ChnHist(chns1[i], dst_mask, _dst_hist, _dst_cdf);

	uchar last = 0;


	for(int j=0;j&lt;src_cdf.cols;j++)
	{
		double F1j = _src_cdf[j];

		for(uchar k = last; k (F1j - HISTMATCH_EPSILON))
			{
				M[j] = k;
				last = k;
				break;
			}
		}
	}

	cv::Mat lut(1,256,CV_8UC1,M);
	cv::LUT(chns[i],lut,chns[i]);
	}

cv::Mat res;
cv::merge(chns,res);

res.copyTo(src);
}

// Compute histogram and CDF for an image with mask
void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf)
{
cv::Mat _t = _i.reshape(1,1);

// Get the histogram with or without the mask
if (mask) 
{
	cv::Mat _tm;
	mask-&gt;copyTo(_tm);
	_tm = _tm.reshape(1,1);
	for(int p=0; p&lt;_t.cols; p++) 
	{
		CvPoint po;
		po.x = 0;
		po.y = p;
		uchar m = _tm.at(po);
		

		if(m &gt; 0)
		{ // Mask value
			uchar c = _t.at(0,p); // Image value
			h[c][/c] += 1.0;    // Histogram
        }
    }
}
else 
{
	//uchar* Uptr = _t.ptr(0);
	for(int p = 0; p &lt; _t.cols; p++) 
	{
		//Uptr[p] = saturate_cast((Uptr[p]-128)/2 + 128);
        uchar c = _t.at(0, p);
		//Vxy = saturate_cast((Vxy-128)/2 + 128);

		//uchar c = _t(0,p);   // Image value
		h[c][/c]+= 1.0; // Histogram
	}
}

//normalize hist to a max value of 1.0
cv::Mat _tmp(1,256,CV_64FC1,h);
double minVal,maxVal;
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);
_tmp = _tmp / maxVal;

// Calculate the Cumulative Distribution Function
cdf[0] = h[0];
for(int j=1; j&lt;256; j++) 
{
	cdf[j] = cdf[j-1]+h[j];
}

//normalize CDF to a max value of 1.0
_tmp.data = (uchar*)cdf; // Array of doubles, but gets a byte pointer.
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);
_tmp = _tmp / maxVal;
}</description>
		<content:encoded><![CDATA[<p>my minor changes</p>
<p>void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf);</p>
<p>// Match Red, Green and Blue histograms of ‘src’ to that of ‘dst’, according to both masks.<br />
// Based on: <a href="http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/" rel="nofollow">http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/</a><br />
// Modified by Shervin Emami so it can also pass NULL for the masks if you want to process the whole image.<br />
void histMatchRGB(cv::Mat&amp; src, const cv::Mat* src_mask, const cv::Mat&amp; dst, const cv::Mat* dst_mask)<br />
{<br />
double const HISTMATCH_EPSILON = 0.000001;</p>
<p>vector chns;<br />
cv::split(src,chns);<br />
vector chns1;<br />
cv::split(dst,chns1);<br />
cv::Mat src_hist = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat dst_hist = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat src_cdf = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat dst_cdf = cv::Mat::zeros(1,256,CV_64FC1);<br />
cv::Mat Mv(1,256,CV_8UC1);<br />
uchar* M = Mv.ptr();</p>
<p>for(int i=0;i&lt;3;i++)<br />
{<br />
	src_hist.setTo(0);<br />
	dst_hist.setTo(0);<br />
	src_cdf.setTo(0);<br />
	src_cdf.setTo(0);</p>
<p>	double* _src_cdf = src_cdf.ptr();<br />
	double* _dst_cdf = dst_cdf.ptr();<br />
	double* _src_hist = src_hist.ptr();<br />
	double* _dst_hist = dst_hist.ptr();</p>
<p>	do1ChnHist(chns[i], src_mask, _src_hist, _src_cdf);<br />
	do1ChnHist(chns1[i], dst_mask, _dst_hist, _dst_cdf);</p>
<p>	uchar last = 0;</p>
<p>	for(int j=0;j&lt;src_cdf.cols;j++)<br />
	{<br />
		double F1j = _src_cdf[j];</p>
<p>		for(uchar k = last; k (F1j &#8211; HISTMATCH_EPSILON))<br />
			{<br />
				M[j] = k;<br />
				last = k;<br />
				break;<br />
			}<br />
		}<br />
	}</p>
<p>	cv::Mat lut(1,256,CV_8UC1,M);<br />
	cv::LUT(chns[i],lut,chns[i]);<br />
	}</p>
<p>cv::Mat res;<br />
cv::merge(chns,res);</p>
<p>res.copyTo(src);<br />
}</p>
<p>// Compute histogram and CDF for an image with mask<br />
void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf)<br />
{<br />
cv::Mat _t = _i.reshape(1,1);</p>
<p>// Get the histogram with or without the mask<br />
if (mask)<br />
{<br />
	cv::Mat _tm;<br />
	mask-&gt;copyTo(_tm);<br />
	_tm = _tm.reshape(1,1);<br />
	for(int p=0; p&lt;_t.cols; p++)<br />
	{<br />
		CvPoint po;<br />
		po.x = 0;<br />
		po.y = p;<br />
		uchar m = _tm.at(po);</p>
<p>		if(m &gt; 0)<br />
		{ // Mask value<br />
			uchar c = _t.at(0,p); // Image value<br />
			h += 1.0;    // Histogram<br />
        }<br />
    }<br />
}<br />
else<br />
{<br />
	//uchar* Uptr = _t.ptr(0);<br />
	for(int p = 0; p &lt; _t.cols; p++)<br />
	{<br />
		//Uptr[p] = saturate_cast((Uptr[p]-128)/2 + 128);<br />
        uchar c = _t.at(0, p);<br />
		//Vxy = saturate_cast((Vxy-128)/2 + 128);</p>
<p>		//uchar c = _t(0,p);   // Image value<br />
		h+= 1.0; // Histogram<br />
	}<br />
}</p>
<p>//normalize hist to a max value of 1.0<br />
cv::Mat _tmp(1,256,CV_64FC1,h);<br />
double minVal,maxVal;<br />
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);<br />
_tmp = _tmp / maxVal;</p>
<p>// Calculate the Cumulative Distribution Function<br />
cdf[0] = h[0];<br />
for(int j=1; j&lt;256; j++)<br />
{<br />
	cdf[j] = cdf[j-1]+h[j];<br />
}</p>
<p>//normalize CDF to a max value of 1.0<br />
_tmp.data = (uchar*)cdf; // Array of doubles, but gets a byte pointer.<br />
cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);<br />
_tmp = _tmp / maxVal;<br />
}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Shervin Emami</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-5819</link>
		<dc:creator>Shervin Emami</dc:creator>
		<pubDate>Sun, 24 Apr 2011 15:30:49 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-5819</guid>
		<description>Hi Roy,

Thanks for this nice code example. But like others had noted, it has some problems with most compilers, so here is a working version of the code (tested on GCC):


void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf);

// Match Red, Green and Blue histograms of &#039;src&#039; to that of &#039;dst&#039;, according to both masks.
// Based on: http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/
// Modified by Shervin Emami so it can also pass NULL for the masks if you want to process the whole image.
void histMatchRGB(cv::Mat&amp; src, const cv::Mat* src_mask, const cv::Mat&amp; dst, const cv::Mat* dst_mask)
{
	vector chns;
	cv::split(src,chns);
	vector chns1;
	cv::split(dst,chns1);
	cv::Mat src_hist = cv::Mat::zeros(1,256,CV_64FC1);
	cv::Mat dst_hist = cv::Mat::zeros(1,256,CV_64FC1);
	cv::Mat src_cdf = cv::Mat::zeros(1,256,CV_64FC1);
	cv::Mat dst_cdf = cv::Mat::zeros(1,256,CV_64FC1);
	cv::Mat Mv(1,256,CV_8UC1);
	uchar* M = Mv.ptr();
	
	for(int i=0;i&lt;3;i++) {
		src_hist.setTo(cvScalar(0));
		dst_hist.setTo(cvScalar(0));
		src_cdf.setTo(cvScalar(0));
		src_cdf.setTo(cvScalar(0));
		
		double* _src_cdf = src_cdf.ptr();
		double* _dst_cdf = dst_cdf.ptr();
		double* _src_hist = src_hist.ptr();
		double* _dst_hist = dst_hist.ptr();

		do1ChnHist(chns[i], src_mask, _src_hist, _src_cdf);
		do1ChnHist(chns1[i], dst_mask, _dst_hist, _dst_cdf);
		
		uchar last = 0;
		double const HISTMATCH_EPSILON = 0.000001;
		
		for(int j=0;j&lt;src_cdf.cols;j++) {
			double F1j = _src_cdf[j];
			
			for(uchar k = last; k&lt;dst_cdf.cols; k++) {
				double F2k = _dst_cdf[k];
				// Note: Two tests were combined into one for efficiency, by Shervin Emami, Apr 24th 2011.
				//if (abs(F2k - F1j)  F1j) {
				if (F2k &gt; F1j - HISTMATCH_EPSILON) {
					M[j] = k;
					last = k;
					break;
				}
			}
		}
		
		cv::Mat lut(1,256,CV_8UC1,M);
		cv::LUT(chns[i],lut,chns[i]);
	}
	
	cv::Mat res;
	cv::merge(chns,res);
	
	res.copyTo(src);
}

// Compute histogram and CDF for an image with mask
void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf)
{
	cv::Mat _t = _i.reshape(1,1);

	// Get the histogram with or without the mask
	if (mask) {
		cv::Mat _tm;
		mask-&gt;copyTo(_tm);
		_tm = _tm.reshape(1,1);
		for(int p=0; p&lt;_t.cols; p++) {
			uchar m = _tm.at(0,p);
			if(m &gt; 0) {	// Mask value
				uchar c = _t.at(0,p);	// Image value
				h[c][/c] += 1.0;	// Histogram
			}
		}
	}
	else {
		for(int p=0; p&lt;_t.cols; p++) {
			uchar c = _t.at(0,p);	// Image value
			h[c][/c] += 1.0;	// Histogram
		}
	}
	
	//normalize hist to a max value of 1.0
	cv::Mat _tmp(1,256,CV_64FC1,h);
	double minVal,maxVal;
	cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);
	_tmp = _tmp / maxVal;
	
	// Calculate the Cumulative Distribution Function
	cdf[0] = h[0];
	for(int j=1; j&lt;256; j++) {
		cdf[j] = cdf[j-1]+h[j];
	}
	
	//normalize CDF to a max value of 1.0
	_tmp.data = (uchar*)cdf;	// Array of doubles, but gets a byte pointer.
	cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);
	_tmp = _tmp / maxVal;
}</description>
		<content:encoded><![CDATA[<p>Hi Roy,</p>
<p>Thanks for this nice code example. But like others had noted, it has some problems with most compilers, so here is a working version of the code (tested on GCC):</p>
<p>void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf);</p>
<p>// Match Red, Green and Blue histograms of &#8216;src&#8217; to that of &#8216;dst&#8217;, according to both masks.<br />
// Based on: <a href="http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/" rel="nofollow">http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/</a><br />
// Modified by Shervin Emami so it can also pass NULL for the masks if you want to process the whole image.<br />
void histMatchRGB(cv::Mat&amp; src, const cv::Mat* src_mask, const cv::Mat&amp; dst, const cv::Mat* dst_mask)<br />
{<br />
	vector chns;<br />
	cv::split(src,chns);<br />
	vector chns1;<br />
	cv::split(dst,chns1);<br />
	cv::Mat src_hist = cv::Mat::zeros(1,256,CV_64FC1);<br />
	cv::Mat dst_hist = cv::Mat::zeros(1,256,CV_64FC1);<br />
	cv::Mat src_cdf = cv::Mat::zeros(1,256,CV_64FC1);<br />
	cv::Mat dst_cdf = cv::Mat::zeros(1,256,CV_64FC1);<br />
	cv::Mat Mv(1,256,CV_8UC1);<br />
	uchar* M = Mv.ptr();</p>
<p>	for(int i=0;i&lt;3;i++) {<br />
		src_hist.setTo(cvScalar(0));<br />
		dst_hist.setTo(cvScalar(0));<br />
		src_cdf.setTo(cvScalar(0));<br />
		src_cdf.setTo(cvScalar(0));</p>
<p>		double* _src_cdf = src_cdf.ptr();<br />
		double* _dst_cdf = dst_cdf.ptr();<br />
		double* _src_hist = src_hist.ptr();<br />
		double* _dst_hist = dst_hist.ptr();</p>
<p>		do1ChnHist(chns[i], src_mask, _src_hist, _src_cdf);<br />
		do1ChnHist(chns1[i], dst_mask, _dst_hist, _dst_cdf);</p>
<p>		uchar last = 0;<br />
		double const HISTMATCH_EPSILON = 0.000001;</p>
<p>		for(int j=0;j&lt;src_cdf.cols;j++) {<br />
			double F1j = _src_cdf[j];</p>
<p>			for(uchar k = last; k&lt;dst_cdf.cols; k++) {<br />
				double F2k = _dst_cdf[k];<br />
				// Note: Two tests were combined into one for efficiency, by Shervin Emami, Apr 24th 2011.<br />
				//if (abs(F2k &#8211; F1j)  F1j) {<br />
				if (F2k &gt; F1j &#8211; HISTMATCH_EPSILON) {<br />
					M[j] = k;<br />
					last = k;<br />
					break;<br />
				}<br />
			}<br />
		}</p>
<p>		cv::Mat lut(1,256,CV_8UC1,M);<br />
		cv::LUT(chns[i],lut,chns[i]);<br />
	}</p>
<p>	cv::Mat res;<br />
	cv::merge(chns,res);</p>
<p>	res.copyTo(src);<br />
}</p>
<p>// Compute histogram and CDF for an image with mask<br />
void do1ChnHist(const cv::Mat&amp; _i, const cv::Mat* mask, double* h, double* cdf)<br />
{<br />
	cv::Mat _t = _i.reshape(1,1);</p>
<p>	// Get the histogram with or without the mask<br />
	if (mask) {<br />
		cv::Mat _tm;<br />
		mask-&gt;copyTo(_tm);<br />
		_tm = _tm.reshape(1,1);<br />
		for(int p=0; p&lt;_t.cols; p++) {<br />
			uchar m = _tm.at(0,p);<br />
			if(m &gt; 0) {	// Mask value<br />
				uchar c = _t.at(0,p);	// Image value<br />
				h += 1.0;	// Histogram<br />
			}<br />
		}<br />
	}<br />
	else {<br />
		for(int p=0; p&lt;_t.cols; p++) {<br />
			uchar c = _t.at(0,p);	// Image value<br />
			h += 1.0;	// Histogram<br />
		}<br />
	}</p>
<p>	//normalize hist to a max value of 1.0<br />
	cv::Mat _tmp(1,256,CV_64FC1,h);<br />
	double minVal,maxVal;<br />
	cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);<br />
	_tmp = _tmp / maxVal;</p>
<p>	// Calculate the Cumulative Distribution Function<br />
	cdf[0] = h[0];<br />
	for(int j=1; j&lt;256; j++) {<br />
		cdf[j] = cdf[j-1]+h[j];<br />
	}</p>
<p>	//normalize CDF to a max value of 1.0<br />
	_tmp.data = (uchar*)cdf;	// Array of doubles, but gets a byte pointer.<br />
	cv::minMaxLoc(_tmp, &amp;minVal, &amp;maxVal);<br />
	_tmp = _tmp / maxVal;<br />
}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ingo</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-5336</link>
		<dc:creator>Ingo</dc:creator>
		<pubDate>Thu, 10 Feb 2011 23:55:42 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-5336</guid>
		<description>Hey there,

I&#039;m trying your code with the new OpenCV 2.2 C++ API and I have discovered some difficulties. First, I need to specify the data type of some template calls as in _tm.at(0, p). I changed it to _tm.at(0, p) and now it seems ok.

The second issue is with the calls of the do1ChnHist function. You are calling this function with variables of type cv::Mat as third and fourth parameter, but it is specified to take double* instead. Could you please explain to me how that is supposed to work?

I&#039;m really only beginning with using C++ and OpenCV, so maybe it&#039;s quite obvious how to fix this, but I wasn&#039;t able to figure it out by now.

Thanks a lot in advance for your answer and of course for sharing your work with us!</description>
		<content:encoded><![CDATA[<p>Hey there,</p>
<p>I&#8217;m trying your code with the new OpenCV 2.2 C++ API and I have discovered some difficulties. First, I need to specify the data type of some template calls as in _tm.at(0, p). I changed it to _tm.at(0, p) and now it seems ok.</p>
<p>The second issue is with the calls of the do1ChnHist function. You are calling this function with variables of type cv::Mat as third and fourth parameter, but it is specified to take double* instead. Could you please explain to me how that is supposed to work?</p>
<p>I&#8217;m really only beginning with using C++ and OpenCV, so maybe it&#8217;s quite obvious how to fix this, but I wasn&#8217;t able to figure it out by now.</p>
<p>Thanks a lot in advance for your answer and of course for sharing your work with us!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Roy</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-5331</link>
		<dc:creator>Roy</dc:creator>
		<pubDate>Thu, 10 Feb 2011 18:10:33 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-5331</guid>
		<description>@Umar, The masks tell the algorithm which pixels in the source and target images should change colors. In the mask, every pixel that has a 255 value is included, and 0 value is excluded.
If you are looking for global color-transfer, just make the masks be white (255) all over.</description>
		<content:encoded><![CDATA[<p>@Umar, The masks tell the algorithm which pixels in the source and target images should change colors. In the mask, every pixel that has a 255 value is included, and 0 value is excluded.<br />
If you are looking for global color-transfer, just make the masks be white (255) all over.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Umar</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-5321</link>
		<dc:creator>Umar</dc:creator>
		<pubDate>Wed, 09 Feb 2011 17:01:39 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-5321</guid>
		<description>i need to match the histogram of one image to with another so that the histogram of first image looks like the histogram of second image.
We can do this in matlab in this way
imgA=imread(some img);
[hist x]=imhist(imgB);
imgA_new= histeq(imgA,hist);

Here we just need two images and there histograms. But I am unable to understand that what is the purpose of following images in the code above
Mat src_mask = cvLoadImage(&quot;image008_mask.bmp&quot;,0);
Mat dst_mask = cvLoadImage(&quot;image003_mask.bmp&quot;,0);
Can u plz elaborate it a lil bit more. I am new in computer vision and opencv. And kindly also explain dat wat do u mean by image mask in the code above</description>
		<content:encoded><![CDATA[<p>i need to match the histogram of one image to with another so that the histogram of first image looks like the histogram of second image.<br />
We can do this in matlab in this way<br />
imgA=imread(some img);<br />
[hist x]=imhist(imgB);<br />
imgA_new= histeq(imgA,hist);</p>
<p>Here we just need two images and there histograms. But I am unable to understand that what is the purpose of following images in the code above<br />
Mat src_mask = cvLoadImage(&#8220;image008_mask.bmp&#8221;,0);<br />
Mat dst_mask = cvLoadImage(&#8220;image003_mask.bmp&#8221;,0);<br />
Can u plz elaborate it a lil bit more. I am new in computer vision and opencv. And kindly also explain dat wat do u mean by image mask in the code above</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Andrea</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-640</link>
		<dc:creator>Andrea</dc:creator>
		<pubDate>Tue, 06 Jul 2010 21:44:46 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-640</guid>
		<description>Hi, this code is great, i&#039;m using it but i have some trouble with some artifacts, when there is a great chromatic difference betwen the images some strange halo, with wrong colors, appears :( 

How i can solve it?</description>
		<content:encoded><![CDATA[<p>Hi, this code is great, i&#8217;m using it but i have some trouble with some artifacts, when there is a great chromatic difference betwen the images some strange halo, with wrong colors, appears <img src='http://www.morethantechnical.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  </p>
<p>How i can solve it?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Roy</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-294</link>
		<dc:creator>Roy</dc:creator>
		<pubDate>Fri, 30 Apr 2010 09:52:51 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-294</guid>
		<description>Hi Basilio,
Thanks
Just saw your online portfolio - some awesome stuff you got there!
R.</description>
		<content:encoded><![CDATA[<p>Hi Basilio,<br />
Thanks<br />
Just saw your online portfolio &#8211; some awesome stuff you got there!<br />
R.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Basilio</title>
		<link>http://www.morethantechnical.com/2010/01/28/recoloring-via-histogram-matching-with-opencv-w-code/comment-page-1/#comment-290</link>
		<dc:creator>Basilio</dc:creator>
		<pubDate>Thu, 29 Apr 2010 06:48:14 +0000</pubDate>
		<guid isPermaLink="false">http://www.morethantechnical.com/?p=563#comment-290</guid>
		<description>Thanks a lot for your effort! there&#039;s a couple of hiccups that needed to be fixed (at least for me) for the code to run but it does, and very smoothly! Very nice and elegant! (and it finally got me to switch to proper cv2.0...)

Much appreciated!</description>
		<content:encoded><![CDATA[<p>Thanks a lot for your effort! there&#8217;s a couple of hiccups that needed to be fixed (at least for me) for the code to run but it does, and very smoothly! Very nice and elegant! (and it finally got me to switch to proper cv2.0&#8230;)</p>
<p>Much appreciated!</p>
]]></content:encoded>
	</item>
</channel>
</rss>

