矩陣的掩膜操作
- 影像的通道
- 掩膜
- 1.掩膜的定義
- 2.利用掩膜提高影像的對比度
- opencv實作掩膜操作
- 1.opencv對影像像素的處理
- 用到的函式
- (1)、CV_Assert(myImage.depth() == CV_8U)
- (2)、Mat.ptr(int i=0)
- (3)、saturate_cast()處理像素值的范圍
- (4)、setTo()
- 代碼實作(帶注釋)
- 2、函式呼叫-filter2D功能
- (1)定義掩膜矩陣
- (2)呼叫filter2D()函式
- 完整代碼(詳細注釋)
影像的通道
影像的通道就是把影像分解成一個或多個顏色成分,常見的有單通道,三通道和四通道
-
單通道:灰度影像,一個像素點只需要一個數值即可表示,0-255(0為黑色,255為白色)
-
三通道:RGB影像,為紅綠藍三種顏色通道的疊加,三個通道缺一不可,每個通道由0-255的數值表示,當使用矩陣表示三個通道時,三個通道是并串列示的,所以rgb的影像矩陣列數為單個通道的列數乘以通道數,

-
四通道:在三通道的基礎上加上了透明度(0是完全透明,255是完全不透明)
掩膜
1.掩膜的定義
掩模(Mask)是由0和1組成的一個二進制影像,當在某一功能中應用掩模時,1值區域被處理,被屏蔽的0值區域不被包括在計算中,通過指定的資料值、資料范圍、有限或無限值、感興趣區和注釋檔案來定義影像掩模,也可以應用上述選項的任意組合作為輸入來建立掩模,
建立掩膜后,通過影像與掩膜相乘得到的影像就是掩膜操作后的影像
通過掩膜可以屏蔽某些不需要的區域,或者對某些區域的影像數值進行特殊運算,實際上就是利用掩膜矩陣對原來的影像矩陣重新進行運算
2.利用掩膜提高影像的對比度
下面這個公式表示用5倍當前像素的值減去該像素上、下、左、右四個像素值和,得到的結果賦值給當前像素,
使用該公式可以用于提升影像的對比度,調節I(i,j)的系數權重可以得到不同的對比度提升效果,

通過這種掩膜操作就可以提高影像的對比度
opencv實作掩膜操作
1.opencv對影像像素的處理
用到的函式
(1)、CV_Assert(myImage.depth() == CV_8U)
CV_Assert()函式判斷括號中是否為真,當括號中的結果為false時,回傳一個錯誤資訊,這里是為了保證輸入的影像是uchar型別的,
(2)、Mat.ptr(int i=0)
獲取影像矩陣的指標,其中小括號中的i表示的是影像矩陣的第幾行,從0開始計數,
(3)、saturate_cast()處理像素值的范圍
確保RGB影像的像素值在0-255之間
saturate_cast(-100),回傳0
saturate_cast(288),回傳255
saturate_cast(100),回傳100
其實就是一個型別轉換函式,將圓弧括號中的型別轉換成尖括號中的型別,
(4)、setTo()
opencv中的setTo函式是將指定的元素設定為指定的值
例如:
1、有一個Mat src,想將他的值全部設定成0,則可以src.setTo(0)
2、setTo還有更為高級的用法,對于一個已知的src,我們要將其中大于或者小于某個值的像素值設定為指定的值,則可以如下:src.setTo(0,src < 10);這句話的意思是,當src中的某個像素值小于10的時候,就將該值設定成0.
代碼實作(帶注釋)
CV_Assert(myImage.depth() == CV_8U); // CV_Assert()函式對括號內的內容進行判斷,若為false,則回傳錯誤資訊
//這里要確保輸入的影像是uchar型別的
const int nChannels = myImage.channels(); //影像的通道數
Result.create(myImage.size(), myImage.type()); //創建一個影像,第一個引數是影像的大小(和原影像一致),第二個引數是影像矩陣型別,和原影像一樣
for (int j = 1; j < myImage.rows - 1; ++j) //行掃描
{
const uchar* previous = myImage.ptr<uchar>(j - 1); //定義上一行
const uchar* current = myImage.ptr<uchar>(j); //定義當前行
const uchar* next = myImage.ptr<uchar>(j + 1); //定義下一行
uchar* output = Result.ptr<uchar>(j); //output指標在第j行行頭
for (int i = nChannels; i < nChannels*(myImage.cols - 1); ++i) //列掃描,從i=nChannels(第二組)開始
{
*output++ = saturate_cast<uchar>(5 * current[i]
- current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]); //對輸出影像處理,從第j行第i列開始加
}
2、函式呼叫-filter2D功能
(1)定義掩膜矩陣
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0); //定義掩膜矩陣
這里定義的矩陣就是進行掩膜操作的運算矩陣
(2)呼叫filter2D()函式
filter2D函式括號內包括4個引數
例如
filter2D(src, dst1, src.depth(), kernel);
其中第一個和第二個引數表示的是輸入影像和輸出影像
第三個引數表示的是位圖深度,有32、24、8等
第四個引數表示的是掩膜矩陣,就是上面定義的kernel
完整代碼(詳細注釋)
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
static void help(char* progName)
{
cout << endl
<< "This program shows how to filter images with mask: the write it yourself and the"
<< "filter2d way. " << endl
<< "Usage:" << endl
<< progName << " [image_path -- default lena.jpg] [G -- grayscale] " << endl << endl;
}
void Sharpen(const Mat& myImage, Mat& Result);
int main(int argc, char* argv[])
{
help(argv[0]);
Mat src, dst0, dst1;
src = imread("A:/opencvproject/pikaqiu.jpg", IMREAD_COLOR);
if (src.empty()) //判斷影像是否存在
{
cerr << "Can't open image"<< endl;
return EXIT_FAILURE;
}
namedWindow("Input", WINDOW_AUTOSIZE); //創建視窗input(輸入影像的視窗)
namedWindow("Output", WINDOW_AUTOSIZE); //創建視窗output(輸出影像的視窗)
imshow("Input", src); //顯示輸入影像src
//第一種方式,具體實作在Sharpen()函式中
double t = (double)getTickCount(); //開始記錄時間
Sharpen(src, dst0);
t = ((double)getTickCount() - t) / getTickFrequency(); //記錄轉換完成時間-轉換開始時間
cout << "Hand written function time passed in seconds: " << t << endl; //列印轉換所用時間
imshow("Output", dst0); //顯示輸出影像dst0
waitKey(); //等待鍵盤輸入
//下面是第二種方式,使用filter2D();
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0); //定義掩膜矩陣
t = (double)getTickCount(); //記錄第二種時間的開始時間
filter2D(src, dst1, src.depth(), kernel); //使用filter2D()函式實作影像掩膜操作
t = ((double)getTickCount() - t) / getTickFrequency(); //記錄影像轉換所用時間
cout << "Built-in filter2D time passed in seconds: " << t << endl; //列印使用filter2D函式所用的時間
imshow("Output", dst1); //展示第二種方式輸出的影像dst1
waitKey(); //等待鍵盤輸入
return EXIT_SUCCESS;
}
//第一種轉換方式的實作函式
void Sharpen(const Mat& myImage, Mat& Result)
{
CV_Assert(myImage.depth() == CV_8U); // CV_Assert()函式對括號內的內容進行判斷,若為false,則回傳錯誤資訊
//這里要確保輸入的影像是uchar型別的
const int nChannels = myImage.channels(); //影像的通道數
Result.create(myImage.size(), myImage.type()); //創建一個影像,第一個引數是影像的大小(和原影像一致),第二個引數是影像矩陣型別,和原影像一樣
for (int j = 1; j < myImage.rows - 1; ++j) //行掃描
{
const uchar* previous = myImage.ptr<uchar>(j - 1); //定義上一行
const uchar* current = myImage.ptr<uchar>(j); //定義當前行
const uchar* next = myImage.ptr<uchar>(j + 1); //定義下一行
uchar* output = Result.ptr<uchar>(j); //output指標在第j行行頭
for (int i = nChannels; i < nChannels*(myImage.cols - 1); ++i) //列掃描,從i=nChannels(第二組)開始
{
*output++ = saturate_cast<uchar>(5 * current[i]
- current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]); //對輸出影像處理,從第j行第i列開始加
}
}
// 使用這種方式最外面一圈無法進行矩陣運算
Result.row(0).setTo(Scalar(0)); //第0行矩陣值設定為0
Result.row(Result.rows - 1).setTo(Scalar(0)); //最后一行矩陣之設定為0
Result.col(0).setTo(Scalar(0)); //第0列矩陣值設定為0
Result.col(Result.cols - 1).setTo(Scalar(0)); //最后一行矩陣值設定為0
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/247734.html
標籤:其他
上一篇:C語言 新起點
下一篇:資料分析疫情圖——day1
