灰階圖轉僞彩色圖
數字圖像處理的作業,利用opencv實作通過灰階隐射将灰階圖轉化為僞彩色圖。
效果大概如下,在最後附帶opencv自帶函數處理的方法

原圖
周遊圖
opencv的 applyColorMap 函數處理圖像
1. 原理
根據色彩學方面的研究結果,将灰階圖像對應到red , green , blue三個通道上,最後将三個通道的顔色值合成為需要顯示的RGB顔色值即可。灰階值與三個通道的映射關系如下
粗略的分為四個區間,分别對rgb三種顔色對應的灰階進行映射。再簡單的調一下參數使其更加接近真實彩圖的樣子。
RGB=1:1:1
RGB=1:0.1:-1
具體的映射參數參照和後期的RGB參數調整一定會有更優的選擇,主要是掌握方法。
接下來就是具體的實作過程
2. 實作過程
2.1 使用到的方法/函數
2.1.1 imread與imshow
opencv裡面讀圖和現實圖像經常會用到的 imread()和imshow()函數
這裡隻有一點要注意,在讀入圖像的時候imread的flag參數要為0或者是CV_LOAD_IMAGE_GRAYSCALE
在這裡也逼逼一下參數的差別,flag<0是以原圖讀入 flag=0 是灰階圖 flag>0是RGB讀入
雖然這是一張灰階圖,而且我也隻需要單通道圖像的參數。opencv讀入的灰階圖是單通道的,這個可以使用img.channels()傳回的參數來驗證,當你沒有設定imread()參數的時候,雖然看起來是灰階圖,但實際上卻是3通道的圖像
2.1.2 split剝離通道方法
如果是三通道的圖像,那麼可以使用split()函數提取單通道圖像
Mat img = imread("lenna_gray.bmp", 0);
namedWindow("原圖", WINDOW_AUTOSIZE);
cv::imshow("原圖", img);
vector<Mat> dst(3);//構造容器,用于儲存提取的通道
split(img, dst);//使用split()函數提取
Mat grayImage = dst[0];//容器的儲存順序按照BGR的順序
imshow("gray", grayImage);//檢視單通道圖像是否成功提取
cout<<grayImage.channels()<<endl;//檢視通道數
2.1.3 圖檔容器
建立圖檔容器的方法
Mat imgBlue = Mat(grayImage.rows, grayImage.cols, CV_8UC3);
2.1.4 通道讀寫與周遊
建立一個名字為imgBlue的Mat類型,長寬與grayImage相同的8位(0-255)三通道Mat類型變量
int rows = grayImage.rows;;
int cols = grayImage.cols;
這兩個int類型是擷取Mat類型變量的行數和列數,用于稍後的周遊操作
接着就是重頭戲了,是對于單通道和三通道Mat類型的像素周遊,方法又很多種,我這邊選擇較為簡單的at方法。
2.1.4.1 單通道圖像反色
附上一個簡單的單通道圖像反色方法
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
grayImg.at<uchar>(row, col) = 255 - grayImg.at<uchar>(row, col);
}
}//grayImg是CV_8UC1類型
2.1.4.2 多通道周遊
Mat imgs;
img.copyTo(imgs);//将img的内容複制到imgs
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {//對BGR三通道周遊讀寫
imgs.at<Vec3b>(row, col)[2] = imgBlue.at<Vec3b>(row, col)[2];
imgs.at<Vec3b>(row, col)[1] = imgGreen.at<Vec3b>(row, col)[1];
imgs.at<Vec3b>(row, col)[0] = imgRed.at<Vec3b>(row, col)[0];
}
}//imgRed/Green/Blue都是CV_8UC3類型
單通道和三通道圖像的周遊操作大概就是這樣。多用幾次就熟悉了。
2.1.5 加運算
最後我選擇的是加運算,大緻原理以一個像素點來示範
point1 =[128,128,128] point2 =[1 ,1 ,1 ]
對point1和point2進行加運算 輸出到point3 = [129,129,129]
在opencv裡面使用add函數實作加運算
示範一下兩張圖像的加運算結果
2.2 通道讀寫與周遊簡單的思路小結
首先是提取出一個單通道的Mat,然後參考三張RGB對應gray的映射圖計算出RGB三色的參數
然後将其寫入到三通道的Mat對象中。輸出即可
3. 源碼
以下是全部代碼,需要opencv運作庫
#include<iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
//RGB通道參數,目前效果較好的為
//0.5 0.15 -0.9
#define REDCOLOR_POINT 0.5
#define GREENCOLOR_POINT 0.15
#define BLUECOLOR_POINT -0.9
//通道
#define RED_CHANNELS 2
#define GREEN_CHANNEL 1
#define BLUE_CHANNEL 0
int main() {
cout << "第八周圖像處理實驗" << endl;
Mat img = imread("lenna_gray.bmp", 0);
namedWindow("原圖", WINDOW_AUTOSIZE);
cv::imshow("原圖", img);
cout << "img的通道數為" << img.channels() << endl;;
Mat result;
//開始提取通道
vector<Mat> dst(3);
split(img, dst);
Mat grayImage = dst[0];
imshow("gray", grayImage);//單通道圖像
Mat imgBlue = Mat(grayImage.rows, grayImage.cols, CV_8UC3);
Mat imgRed = Mat(grayImage.rows, grayImage.cols, CV_8UC3);
Mat imgGreen = Mat(grayImage.rows, grayImage.cols, CV_8UC3);
int rows = grayImage.rows;;
int cols = grayImage.cols;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
//grayImg.at<uchar>(row, col) = 255 - grayImg.at<uchar>(row, col);
int grayColor = grayImage.at<uchar>(row, col);
int redColor = 0, greenColor = 0, blueColor = 0;
if (grayColor >= 0 && grayColor < 64)//區間1-green
{//r=0/g->up/b=255
redColor = 0;
blueColor = 255;
//greenColor = grayColor * GRAY2RGB_POINT;
greenColor = 255 / 64 * grayColor;
//greenColor = 0;
}
else if (grayColor >= 64 && grayColor < 128)//區間2-blue
{//r=0/g=255/b->down
redColor = 0;
greenColor = 255;
//blueColor = 255 - (grayColor - 64) * GRAY2RGB_POINT;
blueColor = -255 / 63 * (grayColor - 192) + 255;
}
else if (grayColor >= 128 && grayColor < 192)//區間3-red
{//r->up/g=255/b=0
greenColor = 255;
blueColor = 0;
//redColor = (grayColor - 128) * GRAY2RGB_POINT;
redColor = 255 / 64 * (grayColor - 128);
}
else if (grayColor >= 192 && grayColor < 255)//區間4-green
{//r=255/b=0/g->down
redColor = 255;
blueColor = 0;
//greenColor = 255 - ((grayColor - 192) * GRAY2RGB_POINT);
greenColor = -255 / 63 * (grayColor - 192) + 255;
}
//寫入部分
imgRed.at<Vec3b>(row, col)[RED_CHANNELS] = redColor*REDCOLOR_POINT;
imgRed.at<Vec3b>(row, col)[GREEN_CHANNEL] = 0;
imgRed.at<Vec3b>(row, col)[BLUE_CHANNEL] = 0;
imgGreen.at<Vec3b>(row, col)[RED_CHANNELS] = 0;
imgGreen.at<Vec3b>(row, col)[GREEN_CHANNEL] = greenColor*GREENCOLOR_POINT;
imgGreen.at<Vec3b>(row, col)[BLUE_CHANNEL] = 0;
imgBlue.at<Vec3b>(row, col)[RED_CHANNELS] = 0;
imgBlue.at<Vec3b>(row, col)[GREEN_CHANNEL] = 0;
imgBlue.at<Vec3b>(row, col)[BLUE_CHANNEL] = blueColor* BLUECOLOR_POINT;
}
}
cv::imshow("red", imgRed);
cv::imshow("green", imgGreen);
cv::imshow("blue", imgBlue);
//圖像周遊
Mat rgbImg = Mat(grayImage.rows, grayImage.cols, CV_8UC3);
cout << "rgbImg的通道數為"<<rgbImg.channels();
}
}
add(imgRed, imgGreen, result);
add(result, imgBlue, result);
imshow("rgbImg", result);
waitKey(0);
return 0;
}
4. 使用applyColorMap實作
效果
代碼
#include<iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main() {
Mat img = imread("lenna_gray.bmp", 0);
Mat dst;
applyColorMap(img, dst, COLORMAP_JET);
cv::imshow("dst", dst);
waitKey(0);
return 0;
}
參考:灰階圖像的僞彩色處理_Python_michaelhan3的部落格-CSDN部落格
原文位址:http://blog.twentyy.cn/index.php/CV/cv-gray2rgb.html
後續有修改可能隻會在原文更新