Just My Life & My Work

從前有空沒事就在用影像處理軟體,很方便且輕易地按了「灰階」這個功能,軟體馬上就將影像轉換為灰階,因此會直覺以為轉換過程很簡單,直至今日,自己用OpenCV來實驗,才發覺有些細節,跟我們人的眼睛有關係。

剛好也可以來練習如何取得影像中像素RGB的值,知道這一點之後,即可拿RGB的值來做更進一步的運算,像是調整亮度、對比、r值、色相、彩度、明亮度,甚至透過統計來風格化。

很直覺地猜想,彩色轉灰接的過程應該是灰階=(紅+綠+藍)/3,其實不然。實際上人眼對綠色的亮度感最大,而對藍色最小,於是Gray = 0.299 * Red + 0.587 * Green + 0.114 * Blue才能得到比較適合人類眼睛的灰階影像,久而久之已成為影像處理界所用來彩色轉灰階的標準。

Gray = 0.299 * Red + 0.587 * Green + 0.114 * Blue中RGB的權重跟YUB顏色空間有關係,Y代表luma(跟luminance有點差異,範圍[light, dark]),U由RedYellow組成,V由BlueYellow組成,而Yellow又由RedGreen,也就是Red有三次、Green有兩次、Blue有一次的表現,我想U中和V中的顏色比重不太一樣,才會有Gray(上述)的線性組合。詳情可見:RGB and YUV Color

RGB和YUV的轉換公式如下:

  • R = Y + (1.4075 * (V – 128))
    G = Y – (0.3455 * (U – 128) – (0.7169 * (V – 128))
    B = Y + (1.7790 * (U – 128)
  • Y = R * .299 + G * .587 + B * .114
    U = R * -.169 + G * -.332 + B * .500 + 128
    V = R * .500 + G * -.419 + B * -.0813 + 128
/**
	Theme: Transform Image to Gray Level
	Compiler: Dev C++ 4.9.9.2
	Date: 100/06/06
	Author: ShengWen
	Blog: https://cg2010studio.wordpress.com/
*/
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

// Image Size: 1000x669
uchar Blue[669][1000];
uchar Green[669][1000];
uchar Red[669][1000];
uchar Gray[669][1000];

int main(){
    IplImage *Image1;
    Image1 = cvLoadImage("HappyImage.jpg",1);
    /* Load Image RGB Values */
    for(int i=0;i<Image1->height;i++){
        for(int j=0;j<Image1->widthStep;j=j+3){
            Blue[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j];
            Green[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j+1];
            Red[i][(int)(j/3)]=Image1->imageData[i*Image1->widthStep+j+2];
        }
    }
    /* Implement Algorithms */
    for(int i=0;i<Image1->height;i++){
        for(int j=0;j<Image1->width;j++){
            Gray[i][j]=(uchar)(0.299*Red[i][j] + 0.587*Green[i][j] + 0.114*Blue[i][j]);
            Red[i][j]=Gray[i][j];
            Green[i][j]=Gray[i][j];
            Blue[i][j]=Gray[i][j];
        }
    }
    /* Save Image RGB Values */
    for(int i=0;i<Image1->height;i++){
        for(int j=0;j<Image1->widthStep;j=j+3){
            Image1->imageData[i*Image1->widthStep+j]=Blue[i][(int)(j/3)];
            Image1->imageData[i*Image1->widthStep+j+1]=Green[i][(int)(j/3)];
            Image1->imageData[i*Image1->widthStep+j+2]=Red[i][(int)(j/3)];
        }
    }

    cvSaveImage("HappyImage_gray.jpg",Image1);
    cvNamedWindow("Gray Level",1);
    cvShowImage("Gray Level",Image1);
    cvWaitKey(0);

    cvReleaseImage(&Image1);
    cvDestroyWindow("Gray Level");

    return EXIT_SUCCESS;
}

程式一共分為三個步驟:

  1. 將影像的RGB取出
  2. 接著轉成Gray,然後將Gray分別寫入RGB
  3. 最後儲存成影像檔

為何影像的widthStep先*i再+j呢?+j的原因是,顏色以BGRBGR…的順序儲存成數位影像,*i的原因則是,一維陣列要模擬二維影像。

灰階影像每個pixel只有一個值。

彩色影像每個pixel有三個值,以BGR的順序排列,如此一來可以加速掃描過程

初日

原始影像

首先按照程式設定0.299*Red[i][j] + 0.587*Green[i][j] + 0.114*Blue[i][j],跑出結果如下:

初日_gray

0.299*Red + 0.587*Green + 0.114*Blue

接著嘗試0.33*Red[i][j] + 0.33*Green[i][j] + 0.33*Blue[i][j],影像結果如下,似乎沒有太大的差異:

先除再加_gray

0.33*Red + 0.33*Green + 0.33*Blue

再來試(Red[i][j] + Green[i][j] + Blue[i][j])/3,影像結果如下,改變超誇張,因為uchar有溢位的狀況:

先加再除_gray

(Red + Green + Blue)/3

RGB_gray

RGB各通道的灰階影像。

參考:資料結構操作與運算-IplImage資料結構(2)程式寫法效能測試-圖片灰階處理Grayscale

Comments on: "[OpenCV] 轉換影像為灰階 (Transform Image to Gray Level)" (35)

  1. […] timeb typedef long long TIME_T; #endif using namespace cv; using namespace std; /* 資料來源: [OpenCV] 轉換影像為灰階 (Transform Image to Gray Level) https://blog.csdn.net/kuweicai/article/details/73414138 [OpenCV] IplImage 和 Mat 互轉 […]

隨意留個言吧:)~

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

標籤雲

%d 位部落客按了讚: