iT邦幫忙

2023 iThome 鐵人賽

DAY 7
0

一、 介紹

將彩色圖片轉換為灰階圖是影像處理中常見的步驟之一。這個過程之所以重要,是因為彩色圖片通常包含豐富的色彩信息,但在某些情況下,我們可能更關心影像的細節、結構和特徵,而不是顏色。將圖片轉換為灰階能夠去除色彩的影響,使得我們能夠更專注於影像的亮度變化。

除此之外,灰階圖片也更加節省數據儲存空間和記憶體,因為每個像素只需要一個數值來表示亮度,而不需要分別表示紅、綠、藍三個通道的數值。這種數據的簡化有助於加速影像處理運算,降低計算成本。

二、原理

在將彩色圖片轉換為灰階圖時,我們需要將每個像素的紅、綠、藍三個顏色通道的數值組合成一個單一的灰階值。為了達到這個目的,我們通常使用加權平均的方式,將這些通道的數值相應地加權組合起來。

灰階值是介於0和255之間的一個數值,代表了像素的亮度。而彩色影像的每個像素都由紅、綠、藍三個通道的顏色數值組成。在計算灰階值時,我們可以使用以下的加權平均公式:

https://ithelp.ithome.com.tw/upload/images/20230918/20161732jNR1bzd7uN.png

這裡的0.299、0.587和0.114代表了紅、綠、藍三個顏色加權係數,加權值的總和等於1。這種加權平均的方式考慮了人眼對不同顏色的敏感度,因此可以得到比較自然的灰階影像。

三、程式碼

1. 逐行解釋

這個程式碼提供了兩種運算方式,一個是使用OpenCV內建的函式,另一個是使用蜂巢迴圈實現的演算法,兩者效果一樣。你可以透過設定USE_OPENCV10來決定你要使用前者還是後者的實現方式。

#define USE_OPENCV 1

1) 使用OpenCV作色彩轉換

cv::cvtColor 函數用於影像的顏色空間的轉換,不只可以將圖片轉成灰階,還可以轉換到其他的色彩空間像是HSV、HSL,之後的主題會講解到這個函式的其他應用。

cv::cvtColor(colorImage, grayImage, cv::COLOR_BGR2GRAY);
  • colorImage:原始彩色影像。
  • grayImage:用於儲存轉換後的灰階影像。
  • cv::COLOR_BGR2GRAY:表示從 BGR 彩色空間轉換到灰階空間的轉換方式。

2) 使用自己寫的灰階演算法

  1. 建立一個空的灰階影像,與原始彩色影像具有相同的寬度和高度。
  2. 遍歷原始彩色影像的每個像素,對於每個像素:
    • 提取紅色、綠色和藍色通道的值。
    • 使用特定的權重組合這些通道值,計算灰階值。
  3. 在新的灰階影像中,將每個像素的灰階值設定為上一步計算得到的灰階值。
int width = colorImage.cols;
int height = colorImage.rows;

grayImage=cv::Mat(height, width, CV_8UC1);

for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
        cv::Vec3b pixel = colorImage.at<cv::Vec3b>(y, x);
        uchar grayValue = 0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0];
        grayImage.at<uchar>(y, x) = grayValue;
    }
}

2. 完整程式碼

  1. 設定OpenCV的日誌級別為LOG_LEVEL_SILENT,使OpenCV不輸出任何日誌訊息。
  2. 讀取一張彩色影像,並將其存儲在名為colorImagecv::Mat中。
  3. 將彩色影像轉換為灰階影像根據您在程式碼中定義的USE_OPENCV的值,有兩種不同的轉換方式:
    • 如果USE_OPENCV為1,則使用OpenCV的cv::cvtColor函式將colorImage轉換為灰階影像
    • 如果USE_OPENCV為0,則使用自己編寫的程式碼遍歷每個像素,按照灰度化公式計算灰階值,並將其存儲在grayImage中。
  4. 顯示原始彩色影像和轉換後的灰階影像,分別使用cv::imshow函式。原始彩色影像顯示在窗口"Color Image"中,而灰階影像則顯示在窗口"Gray Image"中。
  5. 使用cv::waitKey(0)等待使用者按下鍵盤按鈕,直到使用者關閉窗口,然後程式結束運行。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/utils/logger.hpp>

#define USE_OPENCV 1

int main() {
    cv::utils::logging::setLogLevel(cv::utils::logging::LogLevel::LOG_LEVEL_SILENT);

    // 讀取圖片
    cv::Mat colorImage = cv::imread("C:\\Users\\vince\\Downloads\\Lenna.png", cv::IMREAD_UNCHANGED);

    // 創建灰階影像
    cv::Mat grayImage;
#if USE_OPENCV
	// 使用OpenCV轉換彩色影像為灰階
    cv::cvtColor(colorImage, grayImage, cv::COLOR_BGR2GRAY); 
#else
    int width = colorImage.cols;
    int height = colorImage.rows;
    grayImage = cv::Mat(height, width, CV_8UC1); 
    // 遍歷每個像素,手動計算灰階值
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
			// 獲取彩色影像中的像素值
            cv::Vec3b pixel = colorImage.at<cv::Vec3b>(y, x); 
			// 計算灰階值
            uchar grayValue = 0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0];
            // 將灰階值設置到對應位置
            grayImage.at<uchar>(y, x) = grayValue; 
        }
    }
#endif

    // 顯示原始彩色圖和轉換後的灰階圖
    cv::imshow("Color Image", colorImage); 
    cv::imshow("Gray Image", grayImage); 
    cv::waitKey(0); 
    return 0;
}

3. 輸出結果

一張灰階的Lenna圖就這樣顯示出來啦!
https://ithelp.ithome.com.tw/upload/images/20230918/20161732PoFiHxvmiy.png


上一篇
【Day6】寫出你的第一個OpenCV程式 解析圖片的組成
下一篇
【Day8】影像處理的數學基礎:深入解析影像摺積原理
系列文
圖解C++影像處理與OpenCV應用:從基礎到高階,深入學習超硬核技術!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言