OpenCV基本函數2

(本文包括函數:內存拷貝函數memcpy ();Mat構造函數Mat();多通道分離函數split ();多通道合併函數merge ())

此次用實現照片底片化的例子介紹一些基本函數

所謂照片底片化,就是將圖像每個像素的RGB三個通道取反,如果是256色,就是R』=255-R, G』=255-G, B』=255-B,如果是0.0-1.0的顏色空間,就是R』=1.0-R,nG』=1.0-G, B』=1.0-B。通過上述描述,可得出演算法:遍歷每個像素點RGB值-重新計算-生成圖像,因此可有

t//設置圖片路徑ntstring path = "..//chicago.jpg";nt//生成Mat型圖像矩陣ntMat I = imread(path);nt//轉化Mat內部數據類型ntI.convertTo(I, CV_32FC3, 1 / 255.0);nnt//構建像素值數組ntfloat *img_data = new float[I.cols*I.rows * 3];nt//像素值拷貝ntmemcpy(img_data, I.data, I.cols*I.rows * 3 * sizeof(float));nt//遍歷像素並計算ntfor (int i = 0; i < I.cols*I.rows * 3; i++)nt{nttimg_data[i] = 1 - img_data[i];nt}nt//通過像素數組重新生成圖像ntMat result1(I.rows, I.cols, CV_32FC3, img_data);nt//顯示結果ntimshow("result1", result1);n

函數void *memcpy(void *dest, const void *src, size_t n);n

該函數在OpenGL部分文章中有提及,該函數並非OpenCV函數而是C++函數,作用是從源src所指的內存地址的起始位置開始拷貝n個位元組到目標dest所指的內存地址的起始位置中,n

參數void *dest:目標指針,文中為新創建空數組img_data

參數const void *src:源內存地址起始位置,Mat型圖像起始指針表示為Mat.data,因此文中為I.data

參數size_t n:內存長度,文中為像素個數*3通道(圖像長*寬*3),再乘以數據種類所佔空間(sizeof(float)),最終形式為I.cols*I.rows * 3 * sizeof(float)

Mat構造函數n1. Mat(int rows, int cols, int type, const Scalar& s);n2. Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);n

Mat類型的構造函數有很多種(20種左右吧),目的是為了滿足不同作用矩陣的構造需求。對於圖像處理和一般操作來說,主要應用上述兩種類型構造函數

參數int rows, int cols:矩陣長寬,文中構造與原圖尺寸相同的矩陣以存儲結果圖像,因此設為I.rows, I.cols

參數int type:設置矩陣內數據類型,雖說該參數為int類型,但是為了直觀,通常不用單一的數字表示。如文中需要創建數據為3通道float類型,所以參數設為CV_32FC3

1中參數const Scalar&ns:設置矩陣每個數據的初始值。實際上,構造函數1通常用在空白圖像的初始化,可將圖像設為全白Scalar(1.0f,1.0f,1.0f)或全黑Scalar(0.0f,0.0f,0.0f),當然也可將圖像設為其他顏色。三通道時該參數用Scalar(x,x,x)表示,四通道用Scalar(x,x,x,x)表示,單通道直接用數字表示即可

nnnnnnnnnnnnnn2中參數void* data:設置矩陣內數據,將data數組中的數據作為矩陣元素的值。由於矩陣的長寬通過構造函數設定,數組的長度也是認為設定的,因此只要矩陣尺寸和數組長度相對應即可成功構造矩陣。文中該參數為進行遍歷運算之後的像素數組img_data

程序運行結果:

除了對每個像素進行遍歷操作外,OpenCV還提供了分通道對圖像進行操作的方法:

t//劃分BGR三通道ntvector<Mat> channels;ntsplit(I, channels);nnt//分別處理三通道ntvector<Mat> newChannels;ntnewChannels.push_back(1 - channels[0]);ntnewChannels.push_back(1 - channels[1]);ntnewChannels.push_back(1 - channels[2]);nnt//融合BGR三通道ntMat result2;ntmerge(newChannels, result2);nt//顯示結果ntimshow("result2", result2);n

函數void split(const Mat& m, vector<Mat>& mv )n

該函數作用是將多通道矩陣m中的每個通道單獨提取,分別存入mv中

參數const Mat& m:多通道Mat型矩陣。文中要將彩色BGR三通道圖像I分離通道,因此參數設為I

參數vector<Mat>& mv:vector<Mat>結構,用來存儲分離後的單通道矩陣。文中將彩色圖像矩陣I拆分為三個單通道矩陣,這三個矩陣存於未初始化的vector<Mat> channels中

nnnnnnnn注意,參數vector<Mat>& mv不必初始化,參數const Mat& m有幾個通道,mv就有幾個,可用[n]來獲取某通道的矩陣。如文中Mat I為三通道彩色圖像,所以vector<Mat> channels中共有3個Mat型,其中channels[0]代表I的B通道(藍色),channels[1]代表I的G通道(綠色),channels[2]代表I的R通道(紅色)

函數void merge(const vector<Mat>& mv, OutputArray dst )n

該函數作用和split相反,是將若干個單通道Mat型合成一個多通道矩陣

參數const vector<Mat>& mv:vector<Mat>型若干個單通道Mat組成的vector。文中將分離的vector<Mat>nchannels每個通道進行取反計算,因此該參數設為處理後的channels

參數OutputArray dst:輸出矩陣,OutputArray類型可以用Mat類型表示。文中將分別處理之後的三通道合併回三通道BGR彩色圖像,因此該參數設為未初始化的Mat result2以存儲結果

程序運行結果:

兩種處理方法結果相同

針對該問題,還有一種更為簡單的處理方法,直接應用矩陣運算:

tMat result3 = Scalar(1,1,1) - I;ntimshow("result3", result3);n

最終結果和前兩種方法相同,並且花費時間最短。第一種方法時間花費在遍歷全圖像素點;第二種方法時間花費在split和merge兩個函數上

完整代碼:

#include <opencv.hpp>n#include <iostream>nusing namespace std;nusing namespace cv;nnvoid main()n{nt//設置圖片路徑ntstring path = "..//chicago.jpg";nt//生成Mat型圖像矩陣ntMat I = imread(path);nt//轉化Mat內部數據類型ntI.convertTo(I, CV_32FC3, 1 / 255.0);nnt//構建像素值數組ntfloat *img_data = new float[I.cols*I.rows * 3];nt//像素值拷貝ntmemcpy(img_data, I.data, I.cols*I.rows * 3 * sizeof(float));nt//遍歷像素並計算ntfor (int i = 0; i < I.cols*I.rows * 3; i++)nt{nttimg_data[i] = 1 - img_data[i];nt}nt//通過像素數組重新生成圖像ntMat result1(I.rows, I.cols, CV_32FC3, img_data);nt//顯示結果ntimshow("result1", result1);nnt//劃分BGR三通道ntvector<Mat> channels;ntsplit(I, channels);nnt//分別處理三通道ntchannels[0] = 1 - channels[0];ntchannels[1] = 1 - channels[1];ntchannels[2] = 1 - channels[2];nnt//融合BGR三通道ntMat result2;ntmerge(channels, result2);nt//顯示結果ntimshow("result2", result2);nntMat result3 = Scalar(1,1,1) - I;ntimshow("result3", result3);nnt//圖像顯示ntimshow("ori", I);nt//程序掛起等待ntwaitKey();n}n

推薦閱讀:

如何對指定文件夾進行簡單加密?
假如要黑掉越南機場並播放廣播,該如何實現呢?
為什麼CPU越來越多地採用硅脂而不是焊錫散熱?
Windows快速啟動背後的功臣:休眠
Steam的「遊戲內界面」是什麼原理,為什麼在自己添加的非 Steam 遊戲下也可以打開?

TAG:OpenCV | 图形图像 | 计算机技术 |