近期在做幾個圖像處理相關的項目。裡面有一個操作就是須要先将彩色圖像轉換為灰階圖像。
QImage 有一個convertToFormat方法。最開始一直用這個函數來實作。
可是今天細緻看了看,發現這個函數轉換出的灰階圖與原始圖像的亮度似乎是有差别的。比方說以下這副圖像:

QImage image2 = image.convertToFormat(QImage::Format_Indexed8);
image2.setColorCount(256);
for(int i = 0; i < 256; i++)
{
image2.setColor(i, qRgb(i, i, i));
}
得到的結果是這種:
明顯轉換之後的圖像要暗一些,對照度也差非常多。說明這種方法是錯誤的。事實上想想也能知道,convertToFormat 僅僅是選取了原始圖像中出現最多的那些顔色,并以此生成了colorTable。這個colorTable 的順序與亮度事實上不一定具有線性關系。我這樣任意的轉換從原理上就是說不通的。
後來花了點時間,自己寫了個轉換代碼:
QImage toGray( QImage image )
{
int height = image.height();
int width = image.width();
QImage ret(width, height, QImage::Format_Indexed8);
ret.setColorCount(256);
for(int i = 0; i < 256; i++)
{
ret.setColor(i, qRgb(i, i, i));
}
switch(image.format())
{
case QImage::Format_Indexed8:
for(int i = 0; i < height; i ++)
{
const uchar *pSrc = (uchar *)image.constScanLine(i);
uchar *pDest = (uchar *)ret.scanLine(i);
memcpy(pDest, pSrc, width);
}
break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
for(int i = 0; i < height; i ++)
{
const QRgb *pSrc = (QRgb *)image.constScanLine(i);
uchar *pDest = (uchar *)ret.scanLine(i);
for( int j = 0; j < width; j ++)
{
pDest[j] = qGray(pSrc[j]);
}
}
break;
}
return ret;
}
利用這個代碼的轉換結果例如以下: