画像のHSV色空間調節

解説

 通常用いられるRGB処理系ではR(赤)、G(緑)、B(青)の個別調節は容易にできるが色相などの調節は難しい。 しかし色を色相(Hue)、彩度(Saturation・Chroma)、明度(Brightness・Lightness・Value)の3値で処理する HSV色空間に変換すると容易に色相などを変えることができる。
 ここではRGBからHSVへの変換を担うクラスCDnpColorSpaceHSVを作成し、GDI+を扱うクラスから簡単に利用できる ようにした。


実行例

 画像処理として以下のコードでHSV色調整を行った。

		_cImage2.AdjustHSV(10,-0.25,-0.20);





ソースコード

 GDI+を利用した画像処理テストのスケルトン2を 元に拡張する。


 以下のソースコードを「DnpColorSpaceHSV.h」のファイル名で保存する。


#pragma	once

//
//	RGB-HSV色空間変換クラス
//
//色相(Hue)、彩度(Saturation・Chroma)、明度(Brightness・Lightness・Value)
//Hは0.0から360.0。LとSは0.0~1.0の範囲で変化する。
//
//■■Hの閾値処理にバグがあるような...
//
class	CDnpColorSpaceHSV
{
public:

	//
	//	RGB->HSV
	//
	void	RGBtoHSV(RGBTRIPLE rgb,double& dH,double& dS,double& dV)
	{
		double	dR;
		double	dG;
		double	dB;
		double	dMax;
		double	dMin;
		double	dDiff;

		//RGB->HSV変換時のR,G,Bは 0.0~1.0
		dR = rgb.rgbtRed	/ 255.0;
		dG = rgb.rgbtGreen	/ 255.0;
		dB = rgb.rgbtBlue	/ 255.0;

		dMax = max(max(dR,dG),dB);
		dMin = min(min(dR,dG),dB);

		if(dMax == 0)		//巷のコードではdMax==dMinで処理していることがあるがそれはNG
		{
			dS = 0.0;
			dV = 0.0;
			return;
		}

		dDiff = dMax - dMin;
		dV = dMax;
		dS = dDiff / dMax;
		//dS = dMax - dMin;			//円錐色空間時のS

		if(dR == dMax)
			dH = 60.0 * (dG - dB) / dDiff;
		else if(dG == dMax)
			dH = 60.0 * (dB - dR) / dDiff + 120;
		else
			dH = 60.0 * (dR - dG) / dDiff + 240;

		//上の計算ではdHが負になることがある
		if(dH < 0)
			dH = dH + 360.0;
		if(dH > 360)
			dH = dH - 360.0;

		return;
	}



	//
	//	HSV->RGB
	//
	void	HSVtoRGB(double dH,double dS,double dV,RGBTRIPLE& rgb)
	{
		if(dS == 0.0)
		{
			rgb.rgbtRed		= (BYTE)(dV * 255);
			rgb.rgbtGreen	= rgb.rgbtRed;
			rgb.rgbtRed		= rgb.rgbtRed;
			return;
		}

		double	f;
		double	p;
		double	q;
		double	t;
		int		nHi;

		nHi = (int)(dH / 60) % 6;
		if(nHi < 0)
			nHi *= -1;		//dHが負のときの対策

		f = dH / 60.0 - nHi;
		p = dV * (1.0 - dS);
		q = dV * (1.0 - f * dS);
		t = dV * (1.0 - (1.0 - f) * dS);

		//計算結果のR,G,Bは0.0~1.0なので255倍
		dV = dV * 255.0;
		p = p * 255.0;
		q = q * 255.0;
		t = t * 255.0;

		if(dV > 255.0)
			dV = 255.0;
		if(t > 255.0)
			t = 255.0;
		if(p > 255.0)
			p = 255.0;
		if(q > 255.0)
			q = 255.0;

		if(nHi == 0)
		{
			rgb.rgbtRed		= (BYTE)dV;
			rgb.rgbtGreen	= (BYTE)t;
			rgb.rgbtBlue	= (BYTE)p;
			return;
		}
		if(nHi == 1)
		{
			rgb.rgbtRed		= (BYTE)q;
			rgb.rgbtGreen	= (BYTE)dV;
			rgb.rgbtBlue	= (BYTE)p;
			return;
		}
		if(nHi == 2)
		{
			rgb.rgbtRed		= (BYTE)p;
			rgb.rgbtGreen	= (BYTE)dV;
			rgb.rgbtBlue	= (BYTE)t;
			return;
		}
		if(nHi == 3)
		{
			rgb.rgbtRed		= (BYTE)p;
			rgb.rgbtGreen	= (BYTE)q;
			rgb.rgbtBlue	= (BYTE)dV;
			return;
		}
		if(nHi == 4)
		{
			rgb.rgbtRed		= (BYTE)t;
			rgb.rgbtGreen	= (BYTE)p;
			rgb.rgbtBlue	= (BYTE)dV;
			return;
		}

		//if(nHi == 5)
		//{
			rgb.rgbtRed		= (BYTE)dV;
			rgb.rgbtGreen	= (BYTE)p;
			rgb.rgbtBlue	= (BYTE)q;
			return;
		//}
	}

};



 前に作成した「DnpImage.h」に変更を加える。派生元クラスとしてCDnpColorSpaceHSVを入れ、 HVS色空間調整処理関数を追加する。


#pragma once

#include "DnpImageBase.h"
#include "DnpImageConvolution.h"
#include "DnpColorSpaceHLS.h"
#include "DnpColorSpaceHSV.h"



class	CDnpImage : public CDnpImageBase
	,public CDnpImageConvolution
	,public CDnpColorSpaceHLS
	,public CDnpColorSpaceHSV
{
public:

	//
	//	HSV色空間調整処理
	//
	//色相(Hue)、彩度(Saturation・Chroma)、明度(Brightness・Lightness・Value)の調節ができる
	//調整は指定された値をH,S,Vそれぞれに加算する単純な方法を採用した。
	//指定範囲はHが±360、SとVは±1.0。
	//
	//■■Hの閾値処理にバグがあるような...
	//
	bool	AdjustHSV(double dAdjH,double dAdjS,double dAdjV)
	{
		if(IsValidImage() == false)
			return	false;
		if(dAdjH == 0 && dAdjS == 0 && dAdjV == 0)
			return	true;

		int			nStrideBytes;
		bool		ret;
		UINT		x;
		UINT		y;
		UINT		nWidth;
		UINT		nHeight;
		BYTE*		pData;
		RGBTRIPLE*	pRGB;

		nWidth	= GetWidth();
		nHeight	= GetHeight();

		ret = LockBits(&pData,&nStrideBytes);
		if(ret == false)
			return	false;

		for(y = 0; y < nHeight; y++)
		{
			pRGB = (RGBTRIPLE*)pData;
			for(x = 0; x < nWidth; x++)
			{
				double	H;
				double	S;
				double	V;

				RGBtoHSV(pRGB[x],H,S,V);

				H += dAdjH;
				S += dAdjS;
				V += dAdjV;

				//SとVは0.0~1.0の範囲にする
				//Hは円形なので範囲を限定しない
				if(S > 1.0)
					S = 1.0;
				if(S < 0)
					S = 0;
				if(V > 1.0)
					V = 1.0;
				if(V < 0)
					V = 0;

				HSVtoRGB(H,S,V,pRGB[x]);
			}
			pData += nStrideBytes;
		}

		UnlockBits();

		return	true;
	}


	。。。。省略。。。。

};

カテゴリー「VC++ TIPS」 のエントリー