目錄
一、前言
二、圖像像素基本操作
1、擷取圖像像素指針
1.擷取圖像像素指針是什麼?
2.相應API
3.擷取目的
2、像素範圍處理saturate_cast
1.像素範圍處理是什麼?
2.像素範圍處理API
3、掩膜操作
1.掩膜是什麼?
2.掩膜操作是什麼?
3.掩膜操作的作用?
4.API
三、全部代碼及結果展示
1、代碼
2、運作效果圖
一、前言
欠下的總是要還的,繼續給大家更新有關于OpenCV的教程,很久沒給大家更新,希望能得到大家的諒解。
今天要講的是圖像像素比較簡單的幾個基本操作,包括圖像矩陣的掩膜操作,擷取像素的指針、圖像像素範圍處理以filter2D的介紹。
圖像處理很大程度上是對像素的處理,通過對比像素,修改像素,可以實作降噪、平滑、檢測等功能。
二、圖像像素基本操作
1、擷取圖像像素指針
1.擷取圖像像素指針是什麼?
二維圖像儲存在電腦中,大家可以了解為矩陣,一個二維數組,每個位置都會有一個像素值。
通路像素值,就是通路二維數組中某個位置的值。
2.相應API
通路的時候,我們先通路行,後通路列,通過如下方式,我們擷取行指針,索引i表示第幾行,從0開始計行數。
Mat.ptr<uchar>(int i=0) //擷取像素矩陣的指針,索引i表示第幾行,從0開始計行數。
我們通過行指針,可以擷取到該行的的所有點,即所有像素。
const uchar* current= myImage.ptr<uchar>(row); //獲得目前行指針
p(row, col) =current[col] //擷取目前像素點P(row, col)的像素值。
3.擷取目的
擷取到像素點,我們就可以對這個像素點進行操作,如果我們加上循環嵌套,還可以周遊所有的像素點,即對所有的像素點進行操作。
2、像素範圍處理saturate_cast<uchar>
1.像素範圍處理是什麼?
我們在設定圖像像素的灰階值或者RGB值時候,如果不了解,會随意設定,以RGB為例,他們的取值範圍是從0 到255,是以如果我們輸入範圍以外的資料,為防止程式出錯,我們需要控制範圍,保證我們輸入非法資料時候,不會導緻程式出現問題。
處理的原則如下:
如果我們輸入小于0的值,它會傳回0,
如果我們輸入大于255的值,它會傳回255,
如果我們輸入0-255之間的值,它會正常傳回。
2.像素範圍處理API
像素範圍處理的API是saturate_cast<uchar>:
saturate_cast<uchar>(-100) //傳回 0
saturate_cast<uchar>(288) //傳回255
saturate_cast<uchar>(100) //傳回100
3、掩膜操作
1.掩膜是什麼?
在講掩膜操作之前,先給大家說一下什麼是掩膜。
我們不考慮别的地方什麼是掩膜,我也不會給大家講掩膜的标準定義,我們既然說圖像的掩膜操作,那麼我們就說在圖像掩膜操作中的這個掩膜到底是什麼。
這個掩膜就是一個n*n的矩陣。通過掩膜去周遊圖像,
圖像與掩膜
2.掩膜操作是什麼?
接下來我們講掩膜操作,我們用數字模拟一個圖像,左邊是一個10*10的圖像矩陣,右邊是一個掩膜,他們兩個做操作。
首先,左邊黃色的3*3方塊與掩膜對應位置相乘,求得的值,存放在新圖像上的對應于原圖上的中心位置的中間的位置。就像下圖一樣:
下圖的操作是:
5 * 0 + 5 * (-1) + 5 * 0 + 5 * (-1) + 5 * 5 + 5 * (-1) + 5 * 0 + 5 * (-1) + 5 * 0 = 5
掩膜操作
由于圖像所有都是5,是以上面這個經過掩膜操作并沒有什麼太明顯的變化。
全部做掩膜操作
做完掩膜操作,邊上的像素是做不到的,對于不同的算法,邊上的像素做法不同,在這裡先不說,以後會給大家詳細講解。
我們再看一個示例:
全部做掩膜操作
對于外層一圈,不同算法不同,有的算法是将最外層全部設為0,有的是設為與其距離最近的像素點一緻,有的是在原圖外層加一層,這樣經過掩膜的圖像就是與原圖一樣尺寸了。
3.掩膜操作的作用?
掩膜操作實作圖像對比度調整。
4.API
掩膜操作的API是filter2D,函數原型是:
void filter2D(
InputArray src,
OutputArray dst,
int ddepth,
InputArray kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT
);
函數參數含義如下:
(1)InputArray類型的src ,輸入圖像。
(2)OutputArray類型的dst ,輸出圖像,圖像的大小、通道數和輸入圖像相同。
(3)int類型的ddepth,目标圖像的所需深度。
(4)InputArray類型的kernel,卷積核(或者更确切地說是相關核)是一種單通道浮點矩陣;如果要将不同的核應用于不同的通道,請使用split将圖像分割成不同的顔色平面,并分别對其進行處理。。
(5)Point類型的anchor,表示錨點(即被平滑的那個點),注意他有預設值Point(-1,-1)。如果這個點坐标是負值的話,就表示取核的中心為錨點,是以預設值Point(-1,-1)表示這個錨點在核的中心。。
(6)double類型的delta,在将篩選的像素存儲到dst中之前添加到這些像素的可選值。說的有點專業了其實就是給所選的像素值添加一個值delta。
(7)int類型的borderType,用于推斷圖像外部像素的某種邊界模式。有預設值BORDER_DEFAULT。
如下面這個例子:
filter2D( src, dst, src.depth(), kernel );
三、全部代碼及結果展示
1、代碼
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
int main(int argc, char** argv) {
Mat src, dst;
src = imread("D:/hand.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
/*
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]));
}
}
*/
double t = getTickCount();
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
double timeconsume = (getTickCount() - t) / getTickFrequency();
printf("tim consume %.2f\n", timeconsume);
imshow("input image", src);
imshow("contrast image demo", dst);
waitKey(0);
return 0;
}
2、運作效果圖
原圖
掩膜操作後的圖像
今天的内容就講到這裡啦,有什麼問題,大家可以在下面留言哦!