彩色圖像自動色階調整和自動對比度調整

1.自動色階調整

算法原理:

(1)分別統計每個通道的灰度直方圖;
(2)對每個通道,利用LowCut和HighCut,計算灰度最小值min和最大值max;
(3)對每個通道分別建立分段線性拉伸查找表,
f(g) = 0 g<=min
f(g) = 255 g>=max
f(g) = ((g-min)/(max-min)) * 255 min<g<max
(4)對每個通道利用相應的查找表進行分段線性拉伸,得到效果圖。

2.自動對比度調整

算法原理:

(1)分別統計每個通道的灰度直方圖;
(2)對每個通道,利用LowCut和HighCut,分別計算灰度最小值和最大值,取三個通道最小值中最小者作爲最小值min,取三個通道最大值中最大者爲最大值max;
(3)對每個通道建立統一的分段線性拉伸查找表,
f(g) = 0 g<=min
f(g) = 255 g>=max
f(g) = ((g-min)/(max-min)) * 255 min<g<max

(4)對每個通道利用統一的查找表進行分段線性拉伸,得到效果圖。


3.區別

兩者的區別主要是取最大值最小值的不同,自動色階每個通道取的是當前通道的最大值最小值,而自動對比度取的是三個通道之最。

根據這個區別,不難推測出它們在效果上的一個區別:自動對比度不會改變RGB之間的大小順序,而自動色階有可能改變RGB之間的大小順序。

參考博客:

http://www.cnblogs.com/Imageshop/archive/2011/11/13/2247614.html

博客中提到這兩個算法主要是參考PS中的功能。做圖像處理的,不會PS,確實有點說不過去,有時間我還是要學習一下PS。

然後針對其中的一些功能,用opencv實現一下,肯定能有很多收穫。(待做事件)


4.OpenCV實現

(1)自動色階

/*
	*函數功能:自動色階調整(仿照PS功能)
	*輸入參數:src	輸入彩色圖像
	*輸出參數:dst	輸出調整色階之後的彩色圖像
	*返回值:void
	*算法步驟:
		(1)分別統計每個通道的灰度直方圖;
		(2)對每個通道,利用LowCut和HighCut,計算灰度最小值min和最大值max;
		(3)對每個通道分別建立分段線性拉伸查找表,
			f(g) = 0		g<=min
			f(g) = 255		g>=max
			f(g) = ((g-min)/(max-min)) * 255		min<g<max
		(4)對每個通道利用相應的查找表進行分段線性拉伸,得到效果圖。
		http://www.cnblogs.com/Imageshop/archive/2011/11/13/2247614.html
*/
void AutoLevelsAdjust(cv::Mat &src, cv::Mat &dst)
{
	CV_Assert(!src.empty() && src.channels() == 3);

	//統計灰度直方圖
	int BHist[256] = { 0 };	//B分離
	int GHist[256] = { 0 };	//G分量
	int RHist[256] = { 0 };	//R分量
	cv::MatIterator_<Vec3b> its, ends;
	for (its = src.begin<Vec3b>(), ends = src.end<Vec3b>(); its != ends; its++)
	{
		BHist[(*its)[0]]++;
		GHist[(*its)[1]]++;
		RHist[(*its)[2]]++;
	}

	//設置LowCut和HighCut
	float LowCut = 0.5;
	float HighCut = 0.5;

	//根據LowCut和HighCut查找每個通道最大值最小值
	int BMax = 0, BMin = 0;
	int GMax = 0, GMin = 0;
	int RMax = 0, RMin = 0;

	int TotalPixels = src.cols * src.rows;
	float LowTh = LowCut * 0.01 * TotalPixels;
	float HighTh = HighCut * 0.01 * TotalPixels;

	//B通道查找最小最大值
	int sumTempB = 0;
	for (int i = 0; i < 256; i++)
	{
		sumTempB += BHist[i];
		if (sumTempB >= LowTh)
		{
			BMin = i;
			break;
		}
	}
	sumTempB = 0;
	for (int i = 255; i >= 0; i--)
	{
		sumTempB += BHist[i];
		if (sumTempB >= HighTh)
		{
			BMax = i;
			break;
		}
	}

	//G通道查找最小最大值
	int sumTempG = 0;
	for (int i = 0; i < 256; i++)
	{
		sumTempG += GHist[i];
		if (sumTempG >= LowTh)
		{
			GMin = i; 
			break;
		}
	}
	sumTempG = 0;
	for (int i = 255; i >= 0; i--)
	{
		sumTempG += GHist[i];
		if (sumTempG >= HighTh)
		{
			GMax = i;
			break;
		}
	}

	//R通道查找最小最大值
	int sumTempR = 0;
	for (int i = 0; i < 256; i++)
	{
		sumTempR += RHist[i];
		if (sumTempR >= LowTh)
		{
			RMin = i;
			break;
		}
	}
	sumTempR = 0;
	for (int i = 255; i >= 0; i--)
	{
		sumTempR += RHist[i];
		if (sumTempR >= HighTh)
		{
			RMax = i;
			break;
		}
	}

	//對每個通道建立分段線性查找表
	//B分量查找表
	int BTable[256] = { 0 };
	for (int i = 0; i < 256; i++)
	{
		if (i <= BMin)
			BTable[i] = 0;
		else if (i > BMin && i < BMax)
			BTable[i] = cvRound((float)(i - BMin) / (BMax - BMin) * 255);
		else
			BTable[i] = 255;
	}

	//G分量查找表
	int GTable[256] = { 0 };
	for (int i = 0; i < 256; i++)
	{
		if (i <= GMin)
			GTable[i] = 0;
		else if (i > GMin && i < GMax)
			GTable[i] = cvRound((float)(i - GMin) / (GMax - GMin) * 255);
		else
			GTable[i] = 255;
	}

	//R分量查找表
	int RTable[256] = { 0 };
	for (int i = 0; i < 256; i++)
	{
		if (i <= RMin)
			RTable[i] = 0;
		else if (i > RMin && i < RMax)
			RTable[i] = cvRound((float)(i - RMin) / (RMax - RMin) * 255);			
		else
			RTable[i] = 255;
	}

	//對每個通道用相應的查找表進行分段線性拉伸
	cv::Mat dst_ = src.clone();
	cv::MatIterator_<Vec3b> itd, endd;
	for (itd = dst_.begin<Vec3b>(), endd = dst_.end<Vec3b>(); itd != endd; itd++)
	{
		(*itd)[0] = BTable[(*itd)[0]];
		(*itd)[1] = GTable[(*itd)[1]];
		(*itd)[2] = RTable[(*itd)[2]];
	}

	dst = dst_;	
}

(2)自動對比度

/*
	*函數功能:自動對比度調整(仿照PS功能)
	*輸入參數:src	輸入彩色圖像
	*輸出參數:dst	輸出調整色階之後的彩色圖像
	*返回值:void
	*算法步驟:
	(1)分別統計每個通道的灰度直方圖;
	(2)對每個通道,利用LowCut和HighCut,分別計算灰度最小值和最大值,取三個通道最小值中
	最小者作爲最小值min,取三個通道最大值中最大者爲最大值max;
	(3)對每個通道建立統一的分段線性拉伸查找表,
		f(g) = 0		g<=min
		f(g) = 255		g>=max
		f(g) = ((g-min)/(max-min)) * 255		min<g<max
	(4)對每個通道利用統一的查找表進行分段線性拉伸,得到效果圖。
	http://www.cnblogs.com/Imageshop/archive/2011/11/13/2247614.html
*/
void AutoContrastAdjust(cv::Mat &src, cv::Mat &dst)
{
	CV_Assert(!src.empty() && src.channels() == 3);

	//統計灰度直方圖
	int BHist[256] = { 0 };
	int GHist[256] = { 0 };
	int RHist[256] = { 0 };
	cv::MatIterator_<Vec3b> its, ends;
	for (its = src.begin<Vec3b>(), ends = src.end<Vec3b>(); its != ends; its++)
	{
		BHist[(*its)[0]]++;
		GHist[(*its)[1]]++;
		RHist[(*its)[2]]++;
	}

	//設置LowCut和HighCut
	float LowCut = 0.5;
	float HighCut = 0.5;

	//根據LowCut和HighCut查找每個通道最大值最小值
	int BMax = 0, BMin = 0;
	int GMax = 0, GMin = 0;
	int RMax = 0, RMin = 0;

	int TotalPixels = src.cols * src.rows;
	float LowTh = LowCut * 0.01 * TotalPixels;
	float HighTh = HighCut * 0.01 * TotalPixels;

	//B通道查找最小最大值
	int sumTempB = 0;
	for (int i = 0; i < 256; i++)
	{
		sumTempB += BHist[i];
		if (sumTempB >= LowTh)
		{
			BMin = i; 
			break;
		}
	}
	sumTempB = 0;
	for (int i = 255; i >= 0; i--)
	{
		sumTempB += BHist[i];
		if (sumTempB >= HighTh)
		{
			BMax = i;
			break;
		}
	}

	//G通道查找最小最大值
	int sumTempG = 0;
	for (int i = 0; i < 256; i++)
	{
		sumTempG += GHist[i];
		if (sumTempG >= LowTh)
		{
			GMin = i;
			break;
		}
	}
	sumTempG = 0;
	for (int i = 255; i >= 0; i--)
	{
		sumTempG += GHist[i];
		if (sumTempG >= HighTh)
		{
			GMax = i;
			break;
		}
	}

	//R通道查找最小最大值
	int sumTempR = 0;
	for (int i = 0; i < 256; i++)
	{
		sumTempR += RHist[i];
		if (sumTempR >= LowTh)
		{
			RMin = i;
			break;
		}
	}
	sumTempR = 0;
	for (int i = 255; i >= 0; i--)
	{
		sumTempR += RHist[i];
		if (sumTempR >= HighTh)
		{
			RMax = i;
			break;
		}
	}

	//獲取最大值,最小值,與自動色階的不同之處主要在此,取的是三通道之最
	int Max = std::max(std::max(BMax, GMax), RMax);
	int Min = std::min(std::min(BMin, GMin), RMin);

	//建立統一的分段線性查找表
	int Table[256] = { 0 };
	for (int i = 0; i < 256; i++)
	{
		if (i <= Min)
			Table[i] = 0;
		else if (i > Min && i < Max)
			Table[i] = (int)((float)(i - Min) / (Max - Min) * 255);
		else
			Table[i] = 255;
	}
	
	//對每個通道用統一的查找表進行分段線性拉伸
	cv::Mat dst_ = src.clone();
	cv::MatIterator_<Vec3b> itd, endd;
	for (itd = dst_.begin<Vec3b>(), endd = dst_.end<Vec3b>(); itd != endd; itd++)
	{
		(*itd)[0] = Table[(*itd)[0]];
		(*itd)[1] = Table[(*itd)[1]];
		(*itd)[2] = Table[(*itd)[2]];
	}
	
	dst = dst_;
}

(3)效果


原圖


自動色階效果圖


自動對比度效果圖

單從這幅圖的測試效果來看,沒法說自動色階和自動對比度哪個效果更好。但是兩者之間確實存在區別,爲了對比一下兩者的不同,利用ImageWatch觀察一下內部像素值的變化


原圖,位置(0000,0416)處的像素值 B |G|R = 213|231|160,    大小關係 G>B>R


自動色階,位置(0000,0416)處的像素值 B |G|R = 255|254|157,    大小關係 B>G>R,改變了B和G的大小關係


自動對比度,位置(0000,0416)處的像素值 B |G|R = 226|248|160,    大小關係 G>B>R,RGB大小關係不變

小結:如果在圖像處理的過程中比較關心RGB之間的大小關係,就不能用自動色階,而應該用自動對比度。如果不關心RGB的大小關係,就根據實際測試對後續的影響來判斷使用哪種處理。

5.擴展

在查詢相關資料的時候,看到很多資料提到了彩色圖像的直方圖均衡化。於是,決定也瞭解一下彩色圖像直方圖均衡化的效果,並且與自動對比度進行一下比對。

參考博客:

https://blog.csdn.net/frank_xu_0818/article/details/39232157

(1)RGB空間下分通道直方圖均衡化

/*
	 *函數功能:對彩色圖像進行直方圖均衡化
	 *輸入參數:src	輸入彩色圖像
	 *輸出參數:dst	輸出均衡化之後的圖像
	 *返回值:void
	 *備註:先通道分離,然後對每一通道進行直方圖均衡化,最後融合
 */
void ColorEqualizeHist(cv::Mat &src, cv::Mat &dst)
{
	CV_Assert(!src.empty() && src.channels() == 3);
	
	//通道分離
	cv::Mat channels[3];
	cv::split(src, channels);

	//每個通道進行直方圖均衡化
	cv::Mat equalizeHistImg[3];
	for (int i = 0; i < 3; i++)
		cv::equalizeHist(channels[i], equalizeHistImg[i]);

	//通道融合
	cv::Mat dst_;
	cv::merge(equalizeHistImg, 3, dst_);

	dst = dst_;
}

(2)轉到YCbCr空間下單獨對Y通道直方圖均衡化

/*
	*函數功能:對彩色圖像進行直方圖均衡化
	*輸入參數:src	輸入彩色圖像
	*輸出參數:dst	輸出均衡化之後的圖像
	*返回值:void
	*備註:先轉到YCbCr顏色空間,然後通道分離,只對灰度通道進行直方圖均衡化,
	進行通道融合,最後轉回到BGR空間
*/
void EqualizeHistByYCbCr(cv::Mat &src, cv::Mat &dst)
{
	CV_Assert(!src.empty() && src.channels() == 3);

	//BGR顏色空間轉換到YCbCr顏色空間
	cv::Mat srcYCbCr;
	cv::cvtColor(src, srcYCbCr, CV_BGR2YCrCb);

	//對YCbCr進行通道分離
	cv::Mat channels[3];
	cv::split(srcYCbCr, channels);

	//對亮度通道進行直方圖均衡化
	cv::equalizeHist(channels[0], channels[0]);

	//圖像融合
	cv::Mat dst_;
	cv::merge(channels, 3, dst_);

	//將YCbCr顏色空間轉換回BGR顏色空間
	cv::cvtColor(dst_, dst_, CV_YCrCb2BGR);

	dst = dst_;
}

(3)效果


RGB直方圖均衡化


YCbCr直方圖均衡化

小結:RGB分通道均衡化再融合,顏色容易失真,實用性很低。轉換爲YCbCr再進行對亮度通道均衡化,融合後轉回RGB,效果不夠穩定。參考博客中的lena圖我自己也測了,效果確實不錯,但是我測gakki還有別的一幅圖,效果不好。

根據我測得一些圖,可以發現自動對比度與直方圖均衡化相比,自動對比度效果更好,更穩定。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章