天天看點

Qt 中彩色圖像轉換為灰階圖

近期在做幾個圖像處理相關的項目。裡面有一個操作就是須要先将彩色圖像轉換為灰階圖像。

QImage 有一個convertToFormat方法。最開始一直用這個函數來實作。

可是今天細緻看了看,發現這個函數轉換出的灰階圖與原始圖像的亮度似乎是有差别的。比方說以下這副圖像:

Qt 中彩色圖像轉換為灰階圖
用以下這三行代碼轉換:

QImage image2 = image.convertToFormat(QImage::Format_Indexed8);
    image2.setColorCount(256);
    for(int i = 0; i < 256; i++)
    {
        image2.setColor(i, qRgb(i, i, i));
}      

得到的結果是這種:

Qt 中彩色圖像轉換為灰階圖

明顯轉換之後的圖像要暗一些,對照度也差非常多。說明這種方法是錯誤的。事實上想想也能知道,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;
}      

利用這個代碼的轉換結果例如以下:

Qt 中彩色圖像轉換為灰階圖