1. 程式人生 > >C++影象處理 -- 亮度/對比度調整

C++影象處理 -- 亮度/對比度調整

閱讀提示

    《C++影象處理》系列以程式碼清晰,可讀性為主,全部使用C++程式碼。

    《Delphi影象處理》系列以效率為側重點,一般程式碼為PASCAL,核心程式碼採用BASM。

    儘可能保持二者內容一致,可相互對照。

文章中的BmpData.h標頭檔案。

    在《》一文實現了Photoshop的亮度/對比度調整功能,這是其C/C++版。

    還是先簡單介紹一下Photoshop影象亮度/對比度調整的原理:

    一、對比度演算法公式。

    Photoshop對於對比度增量,是按給定值的正負分別處理的。

    如果用newRGB表示影象畫素新的R、G、B分量,RGB表示影象畫素R、G、B分量,Threshold為給定的閥值,Contrast為對比度增量,當Contrast大於0時:

         1) newRGB = RGB + (RGB - Threshold) * (1 / (1 - Contrast / 255) - 1)

    其中,當Contrast等於255時(RGB - Threshold) * (1 / (1 - Contrast / 255) - 1)為無限(±),由於RGB最大最小值分別為255和0,因此,只能按Threshold來確定newRGB,即newRGB = RGB >= Threshold? 255 : 0,這實際就是設定影象閥值,影象由最多八種顏色組成,即紅、黃、綠、青、藍、紫及黑與白,在灰度圖上也只有最多8條線。

    當Contrast小於0時:

        2) newRGB = RGB + (RGB - Threshold) * Contrast / 255

    其中,當Contrast等於-255時,影象RGB各分量都等於閥值,影象呈全灰色,灰度圖上只有1條線,即閥值灰度。

    二、影象亮度調整。本文采用的是最常用的非線性亮度調整(Phoposhop CS3以下版本也是這種亮度調整方式,CS3及以上版本也保留了該亮度調整方式的選項)。

    三、影象亮度/對比度綜合調整演算法。這個很簡單,當亮度、對比度同時調整時,如果對比度大於0,現調整亮度,再調整對比度;當對比度小於0時,則相反,先調整對比度,再調整亮度。

    下面是用BCB2007和GDI+點陣圖資料寫的Photoshop影象亮度/對比度調整程式碼,包括例子程式碼:

//---------------------------------------------------------------------------

FORCEINLINE
INT CheckValue(INT value)
{
	return (value & ~0xff) == 0? value : value > 255? 255 : 0;
}
//---------------------------------------------------------------------------

// 亮度/對比度調整
VOID BrightAndContrast(BitmapData *data, INT bright, INT contrast, BYTE threshold)
{
	if (bright == 0 && contrast == 0)
		return;
	FLOAT cv = contrast <= -255? -1.0f : contrast / 255.0f;
	if (contrast > 0 && contrast < 255)
		cv = 1.0f / (1.0f - cv) - 1.0f;

	BYTE values[256];
	for (INT i = 0; i < 256; i ++)
	{
		INT v = contrast > 0? CheckValue(i + bright) : i;
		if (contrast >= 255)
			v = v >= threshold? 255 : 0;
		else
			v = CheckValue(v + (INT)((v - threshold) * cv + 0.5f));
		values[i] = contrast <= 0? CheckValue(v + bright) : v;
	}

	PARGBQuad p = (PARGBQuad)data->Scan0;
	INT offset = data->Stride - data->Width * sizeof(ARGBQuad);

	for (UINT y = 0; y < data->Height; y ++, (BYTE*)p += offset)
	{
		for (UINT x = 0; x < data->Width; x ++, p ++)
		{
			p->Blue		= values[p->Blue];
			p->Green	= values[p->Green];
			p->Red		= values[p->Red];
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Gdiplus::Bitmap *bmp =  new Gdiplus::Bitmap(L"..\\..\\media\\source1.jpg");

	Gdiplus::Graphics *g = new Gdiplus::Graphics(Canvas->Handle);
	g->DrawImage(bmp, 0, 0);

	BitmapData data;
	LockBitmap(bmp, &data);
	BrightAndContrast(&data, 0, 255, 121);
	UnlockBitmap(bmp, &data);

	g->DrawImage(bmp, data.Width, 0);

	delete g;
	delete bmp;
}
//---------------------------------------------------------------------------

    在亮度/對比度調整函式BrightAndContrast中,首先按前面介紹的原理製造了一個256個元素大小的查詢表,然後對影象資料逐畫素按R、G、B分量值在查詢表中取得調整後的資料,因此處理速度相當快。

    下面是例子程式執行介面截圖(對比度255時):