從前有空沒事就在用影像處理軟體,很方便且輕易地按了「灰階」這個功能,軟體馬上就將影像轉換為灰階,因此會直覺以為轉換過程很簡單,直至今日,自己用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由Red和Yellow組成,V由Blue和Yellow組成,而Yellow又由Red和Green,也就是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; }
程式一共分為三個步驟:
- 將影像的RGB取出,
- 接著轉成Gray,然後將Gray分別寫入RGB,
- 最後儲存成影像檔。
為何影像的widthStep要先*i再+j呢?+j的原因是,顏色以BGRBGR…的順序儲存成數位影像,*i的原因則是,一維陣列要模擬二維影像。
灰階影像每個pixel只有一個值。
彩色影像每個pixel有三個值,以BGR的順序排列,如此一來可以加速掃描過程。
首先按照程式設定0.299*Red[i][j] + 0.587*Green[i][j] + 0.114*Blue[i][j],跑出結果如下:
接著嘗試0.33*Red[i][j] + 0.33*Green[i][j] + 0.33*Blue[i][j],影像結果如下,似乎沒有太大的差異:
再來試(Red[i][j] + Green[i][j] + Blue[i][j])/3,影像結果如下,改變超誇張,因為uchar有溢位的狀況:
參考:資料結構操作與運算-IplImage資料結構(2)、程式寫法效能測試-圖片灰階處理、Grayscale。
Comments on: "[OpenCV] 轉換影像為灰階 (Transform Image to Gray Level)" (37)
您好 請問這篇文章的方法如何寫成python呢?
讚讚
你有寫程式的經驗嗎?若有的話,學習寫Python會很容易上手喔!
讚讚
[…] 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 互轉 […]
讚讚