CUDA opencv 彩色圖轉(zhuǎn)灰度圖

前言

幾乎絕大部分圖像操作的前置處理都會(huì)把rgb彩色圖轉(zhuǎn)為灰度圖,然后再進(jìn)行二值化操作等等。opencv讀取圖像,一般都是彩色圖,即包含bgr三通道,而灰度圖則只包含一個(gè)通道,只含亮度信息,不含色彩信息的圖象,就象我們平時(shí)看到的黑白照片:亮度由暗到明,變化是連續(xù)的。因此,要表示灰度圖,就需要把亮度值進(jìn)行量化。通常劃分成0到255共256個(gè)級(jí)別,其中0最暗(全黑),255最亮(全白)。在表示顏色的方法中,除了RGB外,還有一種叫YUV的表示方法,應(yīng)用也很多。電視信號(hào)中用的就是一種類(lèi)似于YUV的顏色表示方法。在這種表示方法中,Y分量的物理含義就是亮度,Y分量包含了灰度圖的所有信息,只用Y分量就能完全能夠表示出一幅灰度圖來(lái)。

彩色圖轉(zhuǎn)灰度圖方法

一般而言,將彩色圖轉(zhuǎn)換為灰度圖有以下幾種方法:
(1)最大值法
將彩色圖像中每個(gè)像素的rgb分量中亮度的最大值作為灰度圖的灰度值

(2)平均值法
將彩色圖像中的每個(gè)像素的rgb三分量求平均得到一個(gè)灰度圖的灰度值

(3)加權(quán)平均法
由于人眼對(duì)紅綠藍(lán)三種顏色的敏感程度不同,在灰度轉(zhuǎn)換時(shí),每個(gè)顏色分配的權(quán)重也是不同的,由此得到色彩心理學(xué)公式:
Gray=0.299red+0.587green+0.114*blue

第三種的加權(quán)平均法也是使用最為廣泛的方法,本次試驗(yàn)也是使用這個(gè)方法

cuda試驗(yàn)

還是首先上代碼

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda.h>
#include <device_functions.h>
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

//輸入圖像為BGR圖,將其轉(zhuǎn)化為gray圖
__global__ void rgb2grayInCuda(uchar3* dataIn, unsigned char* dataOut, int imgHeight, int imgWidth)
{
    int xIndex = threadIdx.x + blockIdx.x * blockDim.x;
    int yIndex = threadIdx.y + blockIdx.y * blockDim.y;

    if (xIndex < imgWidth && yIndex < imgHeight)
    {
        uchar3 rgb = dataIn[yIndex * imgWidth + xIndex];

        dataOut[yIndex * imgWidth + xIndex] = 0.299f * rgb.x + 0.587f * rgb.y + 0.114f * rgb.z;
    }
}


int main()
{
    Mat srcImg = imread("D:\\work\\code\\blog\\bin\\win64\\Release\\20140702104508726.jpg");//輸入圖片

    int imgHeight = srcImg.rows;
    int imgWidth = srcImg.cols;    

    Mat grayImg(imgHeight, imgWidth, CV_8UC1, Scalar(0));//輸出灰度圖

    double time1 = static_cast<double>(cv::getTickCount());
    cvtColor(srcImg, grayImg, CV_BGR2GRAY);
    double time2 = static_cast<double>(cv::getTickCount());
    std::cout << "cpu Time use: " << 1000 * (time2 - time1) / cv::getTickFrequency() << "ms" << std::endl;//輸出運(yùn)行時(shí)間
    cv::imwrite("gray_cpu.jpg", grayImg);

    //在GPU中開(kāi)辟輸入輸出空間
    uchar3* d_in;
    unsigned char* d_out;
    int* d_hist;
    
    cudaMalloc((void**)&d_in, imgHeight * imgWidth * sizeof(uchar3));
    cudaMalloc((void**)&d_out, imgHeight * imgWidth * sizeof(unsigned char));

    //將圖像數(shù)據(jù)傳入GPU中
    cudaMemcpy(d_in, srcImg.data, imgHeight * imgWidth * sizeof(uchar3), cudaMemcpyHostToDevice);

    dim3 threadsPerBlock(32, 32);
    dim3 blocksPerGrid((imgWidth + threadsPerBlock.x - 1) / threadsPerBlock.x, (imgHeight + threadsPerBlock.y - 1) / threadsPerBlock.y);

    //記錄起始時(shí)間 
    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start, 0);
    //灰度化
    rgb2grayInCuda << <blocksPerGrid, threadsPerBlock >> > (d_in, d_out, imgHeight, imgWidth);

    //將數(shù)據(jù)從GPU傳回CPU
    cudaMemcpy(grayImg.data, d_out, imgHeight * imgWidth * sizeof(unsigned char), cudaMemcpyDeviceToHost);

    cudaEventRecord(stop, 0);
    cudaEventSynchronize(stop);

    float elapsedTime;
    cudaEventElapsedTime(&elapsedTime, start, stop);
    printf("gpu time cost: %3.5f ms", elapsedTime);

    cv::imwrite("gray_gpu.jpg", grayImg);
    cudaFree(d_in);
    cudaFree(d_out);
    cudaFree(d_hist);
 
    return 0;
}

得出的cpu和gpu的灰度化圖片肉眼可見(jiàn)的有些許差別,詳細(xì)見(jiàn)下圖

gray_cpu.jpg
gray_gpu.jpg

時(shí)間的測(cè)試如下:


時(shí)間測(cè)試.jpg

基本上cpu所耗時(shí)間是gpu的21倍左右

對(duì)比cpu和gpu的輸出的灰度圖,可以發(fā)現(xiàn),gpu的版本會(huì)略微暗一些,所以猜測(cè)opencv不是直接用的這個(gè)公式
Gray=0.299red+0.587green+0.114*blue

經(jīng)過(guò)查閱,發(fā)現(xiàn)還有其他的灰度圖計(jì)算公式,比如為了避免浮點(diǎn)運(yùn)算,將上面的公式改為:
Gray=(30red+59green+11*blue + 50 )/ 100

將代碼改成這個(gè)整數(shù)計(jì)算公式后,輸出的gpu和cpu的灰度圖則完全一模一樣
最終gpu版本計(jì)算灰度值的代碼改為(這里要注意opencv讀取的圖片,通道順序?yàn)锽GR):

dataOut[yIndex * imgWidth + xIndex] = (11 * rgb.x+ 59 * rgb.y + 30 * rgb.z + 50)/100;

最終輸出效果圖為:


gray_cpu.jpg
gray_gpu.jpg

參考

【圖像筆記】RGB圖像轉(zhuǎn)灰度圖像
RGB轉(zhuǎn)化灰度圖公式
CUDA精進(jìn)之路(三):圖像處理——圖像灰度化、灰度直方圖統(tǒng)計(jì)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容