画像のHLS色空間調節

解説

 通常用いられるRGB処理系ではR(赤)、G(緑)、B(青)の個別調節は容易にできるが色相などの調節は難しい。 しかし色をHue(色相)、Lightness(明度)、Saturation(彩度)の3値で処理するHLS色空間に変換すると容易に 色相などを変えることができる。
 ここではMicrosoftのホームページに掲載されていたソースコードをほぼそのまま用いてRGBからHLSへの変換を 担うクラスCDnpColorSpaceHLSを作成し、GDI+を扱うクラスから簡単に利用できるようにした。


実行例

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

		_cImage2.AdjustHLS(10,-25,20);





ソースコード

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


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


#pragma once


//
//	RGB-HLS色空間変換クラス
//
//HLS関連の変換処理はMicrosoftのソースをそのまま利用している
//	http://support.microsoft.com/kb/q29240/
//
//
class	CDnpColorSpaceHLS
{

	////////////////////////////////////////////
	//HLS用定義

	#define  HLSMAX   252	//H,L,Sの最大値(取りうる値は0~HLSMAX)HLSは6で割れる方がいいので255でなく252(=42*6)にした
	#define  RGBMAX   255   //R,G,Bの最大値(取りうる値は0~RGBMAX)

	/* Hue is undefined if Saturation is 0 (grey-scale) */
	/* This value determines where the Hue scrollbar is */
	/* initially set for achromatic colors */
	#define HLSUNDEFINED (HLSMAX*2/3)

	////////////////////////////////////////////

public:

	//
	//	RGB->HLS変換
	//
	void  RGBtoHLS(RGBTRIPLE sRGBColor,int& H,int& L,int& S)
	{
		WORD	R,G,B;          /* input RGB values */
		BYTE	cMax,cMin;      /* max and min RGB values */
		WORD	Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max*/

		/* get R, G, and B out of DWORD */
		R = sRGBColor.rgbtRed;
		G = sRGBColor.rgbtGreen;
		B = sRGBColor.rgbtBlue;

		/* calculate lightness */
		cMax = (BYTE)max( max(R,G), B);
		cMin = (BYTE)min( min(R,G), B);
		L = (((cMax + cMin) * HLSMAX) + RGBMAX) / (2 * RGBMAX);

		if(cMax == cMin)
		{
			/* r=g=b --> achromatic case */

			S = 0;                     /* saturation */
			H = HLSUNDEFINED;          /* hue */
			return;
		}


		/* chromatic case */

		/* saturation */
		if (L <= (HLSMAX/2))
			S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);
		else
			S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) ) / (2*RGBMAX-cMax-cMin);

		/* hue */
		Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
		Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
		Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

		if (R == cMax)
			H = Bdelta - Gdelta;
		else if (G == cMax)
			H = (HLSMAX/3) + Rdelta - Bdelta;
		else /* B == cMax */
			H = ((2*HLSMAX)/3) + Gdelta - Rdelta;

		if (H < 0)
			H += HLSMAX;
		if (H > HLSMAX)
			H -= HLSMAX;
	}

protected:

	/* utility routine for HLStoRGB */
	int HueToRGB(int n1,int n2,int hue)
	{
		/* range check: note values passed add/subtract thirds of range */
		if (hue < 0)
			hue += HLSMAX;

		if (hue > HLSMAX)
			hue -= HLSMAX;

		/* return r,g, or b value from this tridrant */
		if (hue < (HLSMAX/6))
			return ( n1 + (((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) );
		if (hue < (HLSMAX/2))
			return ( n2 );
		if (hue < ((HLSMAX*2)/3))
			return ( n1 +    (((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6)));
		else
			return ( n1 );
	}

public:

	//
	//	HLS->RGB変換
	//
	bool	HLStoRGB(int hue,int lum,int sat,RGBTRIPLE& sRGB)
	{
		WORD  Magic1,Magic2;       /* calculated magic numbers (really!) */

		ZeroMemory(&sRGB,sizeof(RGBTRIPLE));

		if(sat == 0)
		{            /* achromatic case */
			sRGB.rgbtRed	= (lum * RGBMAX) / HLSMAX;;
			sRGB.rgbtGreen	= sRGB.rgbtRed;
			sRGB.rgbtBlue	= sRGB.rgbtBlue;
			if(hue != HLSUNDEFINED)
			{
				/* ERROR */
				return	false;
			}

			return	true;
		}

		/* set up magic numbers */
		if (lum <= (HLSMAX/2))
			Magic2 = (lum*(HLSMAX + sat) + (HLSMAX/2))/HLSMAX;
		else
			Magic2 = lum + sat - ((lum*sat) + (HLSMAX/2))/HLSMAX;
		Magic1 = 2*lum-Magic2;

		/* get RGB, change units from HLSMAX to RGBMAX */
		sRGB.rgbtRed	= (HueToRGB(Magic1,Magic2,hue+(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX;
		sRGB.rgbtGreen	= (HueToRGB(Magic1,Magic2,hue)*RGBMAX + (HLSMAX/2)) / HLSMAX;
		sRGB.rgbtBlue	= (HueToRGB(Magic1,Magic2,hue-(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX;

		return	true;
	}
};




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


#pragma once

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



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



	//
	//	HLS色空間調整処理
	//
	//Hue(色相)、Lightness(明度)、Saturation(彩度)の調節ができる
	//調整は指定された値をH,L,Sそれぞれに加算する単純な方法を採用した。
	//指定範囲は±255。0のときは処理しない
	//
	bool	AdjustHLS(int nAdjH,int nAdjL,int nAdjS)
	{
		if(IsValidImage() == false)
			return	false;
		if(nAdjH == 0 && nAdjL == 0 && nAdjS == 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++)
			{
				int			H;
				int			L;
				int			S;

				RGBtoHLS(pRGB[x],H,L,S);

				H += nAdjH;
				L += nAdjL;
				S += nAdjS;

				if(H > HLSMAX)
					H = HLSMAX;
				if(H < 0)
					H = 0;
				if(L > HLSMAX)
					L = HLSMAX;
				if(L < 0)
					L = 0;
				if(S > HLSMAX)
					S = HLSMAX;
				if(S < 0)
					S = 0;

				HLStoRGB(H,L,S,pRGB[x]);
			}
			pData += nStrideBytes;
		}

		UnlockBits();

		return	true;
	}



	。。。。省略。。。。

};

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