文章目錄
- 掩膜操作
- 什么是掩膜操作?
- 掩膜操作實作影像對比度調整
- 如何獲取影像像素指標?
- 如何像素范圍處理?
- 什么是像素范圍處理?
- 像素范圍處理API——`saturate_cast`
- 掩膜操作的API——filter2D
- 使用步驟
- 掩膜操作案例
掩膜操作
什么是掩膜操作?
掩膜操作是指根據掩膜矩陣(也稱作核kernel)重新計算影像中每個像素的值,掩膜矩陣中的值表示了鄰近像素值(包括該像素自身的值)對新像素值有多大的影響,從數學的觀點來看,我們用自己設定的權值,對像素領域內的值做了個加權平均,
比如,下面這個公式表示用5倍當前像素的值減去該像素上、下、左、右四個像素值和,得到的結果賦值給當前像素,使用該公式可以用于提升影像的對比度,調節I(i,j)的系數權重可以得到不同的對比度提升效果,

上面的公式可以用掩膜矩陣表示成如下的形式,

掩膜操作可以實作影像對比度的調整,使得影像可以銳化,提高影像對比度,
掩膜操作實作影像對比度調整
紅色是中心像素,從上到下,從左到右對每個像素做同樣的處理操作,得到最終結果就是對比度提高之后的輸出影像Mat物件

下面我們繼續探究,如果要想進行掩膜操作,就要先獲取影像像素指標和進行像素范圍處理
如何獲取影像像素指標?
CV_Assert(myImage.depth() == CV_8U);
Mat.ptr(int i=0) 獲取像素矩陣的指標,索引i表示第幾行,從0開始計行數,
獲得當前行指標const uchar* current=myImage.ptr(row );
獲取當前像素點P(row, col)的像素值 p(row, col) =current[col]
如何像素范圍處理?
什么是像素范圍處理?
我們在設定影像像素的灰度值或者RGB值時候,如果不了解,會隨意設定,以RGB為例,他們的取值范圍是從0 到255,所以如果我們輸入范圍以外的資料,為防止程式出錯,我們需要控制范圍,保證我們輸入非法資料時候,不會導致程式出現問題,
處理的原則如下:
如果我們輸入小于0的值,它會回傳0,
如果我們輸入大于255的值,它會回傳255,
如果我們輸入0-255之間的值,它會正常回傳,
那么我們用的時候怎么進行處理呢?
這里就要用到像素范圍處理函式saturate_cast<uchar>
像素范圍處理API——saturate_cast<uchar>
saturate_cast<uchar>(-100),回傳 0,
saturate_cast<uchar>(288),回傳255
saturate_cast<uchar>(100),回傳100
這個函式的功能是確保RGB值得范圍在0~255之間
掩膜操作的API——filter2D
掩膜操作的API是filter2D,函式原型是:
void filter2D(
InputArray src,
OutputArray dst,
int ddepth,
InputArray kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT
);
引數:
InputArray型別的src,輸入影像,OutputArray型別的dst,輸出影像,影像的大小、通道數和輸入影像相同,int型別的ddepth,目標影像的所需深度,InputArray型別的kernel,卷積核(或者更確切地說是相關核)是一種單通道浮點矩陣;如果要將不同的核應用于不同的通道,請使用split將影像分割成不同的顏色平面,并分別對其進行處理,,Point型別的anchor,表示錨點(即被平滑的那個點),注意他有默認值Point(-1,-1),如果這個點坐標是負值的話,就表示取核的中心為錨點,所以默認值Point(-1,-1)表示這個錨點在核的中心,,double型別的delta,在將篩選的像素存盤到dst中之前添加到這些像素的可選值,說的有點專業了其實就是給所選的像素值添加一個值delta,int型別的borderType,用于推斷影像外部像素的某種邊界模式,有默認值BORDER_DEFAULT,
使用步驟
- 定義掩膜:
Mat kernel = (Mat_<char>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); filter2D( src, dst, src.depth(), kernel );其中src與dst是Mat型別變數、src.depth表示位圖深度,有32、24、8等,
例如:
filter2D( src, dst, src.depth(), kernel );
掩膜操作案例

#include <iostream>
#include <math.h>
#include <opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("test2.jpg");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
// 矩陣計算 掩膜操作
int cols = (src.cols - 1) * src.channels();
int offsetx = src.channels();
int rows = src.rows;
dst = Mat::zeros(src.size(), src.type());
for (int row = 1; row < (rows - 1); row++) {
const uchar* previous = src.ptr<uchar>(row - 1);
const uchar* current = src.ptr<uchar>(row);
const uchar* next = src.ptr<uchar>(row + 1);
uchar* output = dst.ptr<uchar>(row);
for (int col = offsetx; col < cols; col++) {
output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
}
}
namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE);
imshow("contrast image demo", dst);
// 使用 掩膜操作API
Mat dst2;
double t = getTickCount();
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst2, src.depth(), kernel);
double timeconsume = (getTickCount() - t) / getTickFrequency();
printf("tim consume %.2f\n", timeconsume);
namedWindow("filter2D contrast image demo", CV_WINDOW_AUTOSIZE);
imshow("filter2D contrast image demo", dst2);
waitKey(0);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/323268.html
標籤:其他
