第一件事:HighGUI 模塊學(xué)習(xí)
1. OpenCV 命名空間
之前的代碼每一個(gè) OpenCV 類和函數(shù)之前都會(huì)加上 cv:: 专筷,這是因?yàn)?OpenCV 的代碼都是定義在命名空間 cv 之內(nèi)的墩邀,需要通過在類和函數(shù)之前加上 cv:: 對(duì) cv 命名空間內(nèi)的類和函數(shù)進(jìn)行調(diào)用俏蛮。但是還有一種更方便的用法,是在代碼開頭的適當(dāng)位置加上 using namespace cv;
這句代碼趣倾。規(guī)定之后的程序都位于此命名空間之內(nèi)。
比如:
#include <opencv2/opencv.cpp>
using namespace cv;
這樣,之后的程序都不需要再加 cv:: 前綴超陆。
2. 圖像載入: imread 函數(shù)
imread 函數(shù)用于讀取文件中的圖片到 OpenCV 中。原型如下:
Mat imread(const string& filename, int flags = 1);
- 第一個(gè)參數(shù),const string& 類型的變量时呀,需要填入圖片的路徑名张漂。
支持如下類型的圖像輸入:
類型 | 后綴 |
---|---|
位圖 | *.bmp,*.dib |
JPEG文件 | *.jpeg谨娜,*.jpg航攒,*.jpe |
JPEG 2000 文件 | *.jp2 |
PNG圖片 | *.png |
便攜文件格式 | *.pbm,*.pgm趴梢,*ppm |
Sun rasters 光柵文件 | *.sr漠畜,*.ras |
TIFF 文件 | *.tiff,*.tif |
- 第二個(gè)參數(shù)坞靶,int 類型的變量憔狞,指定一個(gè)加載圖像的顯示顏色類型。默認(rèn)值為 1彰阴,表示載入三通道的彩色圖瘾敢。我們可以在 imgcodecs_c.h( OpenCV2 中,被定義在 higui_c.h 文件中) 文件中找到這個(gè)枚舉的定義:
enum
{
/* 8bit, color or not */
CV_LOAD_IMAGE_UNCHANGED =-1,
/* 8bit, gray */
CV_LOAD_IMAGE_GRAYSCALE =0,
/* ?, color */
CV_LOAD_IMAGE_COLOR =1,
/* any depth, ? */
CV_LOAD_IMAGE_ANYDEPTH =2,
/* ?, any color */
CV_LOAD_IMAGE_ANYCOLOR =4,
/* ?, no rotate */
CV_LOAD_IMAGE_IGNORE_ORIENTATION =128
};
參數(shù)名 | 介紹 |
---|---|
CV_LOAD_IMAGE_UNCHANGED | 和 CV_LOAD_IMAGE_ANYCOLOR 相比尿这,除了會(huì)載入Alpha通道外基本是同等效果的簇抵,所以這個(gè)參數(shù)漸漸使用的很少了。 |
CV_LOAD_IMAGE_GRAYSCALE | 將圖像轉(zhuǎn)為灰度再返回射众。 |
CV_LOAD_IMAGE_COLOR | 將圖像轉(zhuǎn)換為3通道彩色再返回碟摆。 |
CV_LOAD_IMAGE_ANYDEPTH | 若載入圖像深度為 16 位 或 32 位,就返回對(duì)應(yīng)深度的圖像责球,否則將圖像深度轉(zhuǎn)為8位再返回焦履。 |
CV_LOAD_IMAGE_ANYCOLOR | 保持顏色通道不變 |
CV_LOAD_IMAGE_IGNORE_ORIENTATION | 忽略圖片文件中的 orientation 旋轉(zhuǎn)參數(shù)載入 |
注意:如果輸入的參數(shù)之間有沖突,則會(huì)采用較小的值雏逾。如 CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR
將按照 CV_LOAD_IMAGE_COLOR
載入三通道圖嘉裤。
若這個(gè)參數(shù)不取這個(gè)枚舉值,那么將會(huì)按照:
- flags > 0 返回 3 通道彩色圖(CV_LOAD_IMAGE_COLOR)栖博;
- flags = 0 返回灰度圖(CV_LOAD_IMAGE_GRAYSCALE)屑宠;
- flags < 0 返回包含Alpha通道的彩色圖(CV_LOAD_IMAGE_UNCHANGED);
這個(gè)規(guī)則載入圖像仇让。
3.圖像顯示: imshow 函數(shù)
imshow 用于在指定窗口顯示圖像典奉,原型如下:
void imshow(const string& winname, InputArray Mat);
- 第一個(gè)參數(shù):const string& 類型的變量,需要顯示的窗口名丧叽。
- 第二個(gè)參數(shù):InputArray 類型的變量卫玖,需要顯示的圖像。如果窗口是用 CV_WINDOW_AUTOSIZE(默認(rèn)值) 創(chuàng)建的踊淳,那么就按圖像原始大小顯示(窗口會(huì)自動(dòng)適應(yīng)圖片大屑偎病)。否則縮放圖像適應(yīng)窗口大小。而 imshow 函數(shù)對(duì)圖像深度的縮放會(huì)規(guī)范到[0,255] 區(qū)間脱茉,即 8 位深度剪芥。
InputArray 類型:
在 opencv_core 模塊中的 mat.hpp 頭文件中可以找到該類型定義:
typedef const _InputArray& InputArray;
class CV_EXPORTS _InputArray
{
public:
enum {
KIND_SHIFT = 16,
FIXED_TYPE = 0x8000 << KIND_SHIFT,
FIXED_SIZE = 0x4000 << KIND_SHIFT,
KIND_MASK = 31 << KIND_SHIFT,
NONE = 0 << KIND_SHIFT,
MAT = 1 << KIND_SHIFT,
MATX = 2 << KIND_SHIFT,
STD_VECTOR = 3 << KIND_SHIFT,
STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
STD_VECTOR_MAT = 5 << KIND_SHIFT,
EXPR = 6 << KIND_SHIFT,
OPENGL_BUFFER = 7 << KIND_SHIFT,
CUDA_HOST_MEM = 8 << KIND_SHIFT,
CUDA_GPU_MAT = 9 << KIND_SHIFT,
UMAT =10 << KIND_SHIFT,
STD_VECTOR_UMAT =11 << KIND_SHIFT,
STD_BOOL_VECTOR =12 << KIND_SHIFT,
STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT
};
_InputArray();
_InputArray(int _flags, void* _obj);
_InputArray(const Mat& m);
_InputArray(const MatExpr& expr);
_InputArray(const std::vector<Mat>& vec);
template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
template<typename _Tp> _InputArray(const std::vector<_Tp>& vec);
_InputArray(const std::vector<bool>& vec);
template<typename _Tp> _InputArray(const std::vector<std::vector<_Tp> >& vec);
template<typename _Tp> _InputArray(const std::vector<Mat_<_Tp> >& vec);
template<typename _Tp> _InputArray(const _Tp* vec, int n);
template<typename _Tp, int m, int n> _InputArray(const Matx<_Tp, m, n>& matx);
_InputArray(const double& val);
_InputArray(const cuda::GpuMat& d_mat);
_InputArray(const std::vector<cuda::GpuMat>& d_mat_array);
_InputArray(const ogl::Buffer& buf);
_InputArray(const cuda::HostMem& cuda_mem);
template<typename _Tp> _InputArray(const cudev::GpuMat_<_Tp>& m);
_InputArray(const UMat& um);
_InputArray(const std::vector<UMat>& umv);
Mat getMat(int idx=-1) const;//常成員函數(shù),不能改變成員變量值的函數(shù)
Mat getMat_(int idx=-1) const;
UMat getUMat(int idx=-1) const;
void getMatVector(std::vector<Mat>& mv) const;
void getUMatVector(std::vector<UMat>& umv) const;
void getGpuMatVector(std::vector<cuda::GpuMat>& gpumv) const;
cuda::GpuMat getGpuMat() const;
ogl::Buffer getOGlBuffer() const;
int getFlags() const;
void* getObj() const;
Size getSz() const;
int kind() const;
int dims(int i=-1) const;
int cols(int i=-1) const;
int rows(int i=-1) const;
Size size(int i=-1) const;
int sizend(int* sz, int i=-1) const;
bool sameSize(const _InputArray& arr) const;
size_t total(int i=-1) const;
int type(int i=-1) const;
int depth(int i=-1) const;
int channels(int i=-1) const;
bool isContinuous(int i=-1) const;
bool isSubmatrix(int i=-1) const;
bool empty() const;
void copyTo(const _OutputArray& arr) const;
void copyTo(const _OutputArray& arr, const _InputArray & mask) const;
size_t offset(int i=-1) const;
size_t step(int i=-1) const;
bool isMat() const;
bool isUMat() const;
bool isMatVector() const;
bool isUMatVector() const;
bool isMatx() const;
bool isVector() const;
bool isGpuMatVector() const;
~_InputArray();
protected:
int flags;
void* obj;
Size sz;
void init(int _flags, const void* _obj);
void init(int _flags, const void* _obj, Size _sz);
};
可以看出這是一個(gè)代理類并通過 c++ 的轉(zhuǎn)換構(gòu)造函數(shù)機(jī)制琴许,實(shí)現(xiàn)傳入 Mat 類型并轉(zhuǎn)為 InputArray 的相應(yīng)構(gòu)造函數(shù) _InputArray(const Mat& m);
税肪,構(gòu)造出一個(gè) InputArray 類型的對(duì)象。
代理類:目標(biāo)類(可多個(gè))為其內(nèi)部的 private榜田、protected 類型成員變量益兄,并通過創(chuàng)建同名方法以及對(duì)目標(biāo)類相應(yīng)方法的調(diào)用,完成對(duì)目標(biāo)類的代理行為串慰。
簡(jiǎn)而言之偏塞,就是替目標(biāo)類傳話的一個(gè)類。
4. 創(chuàng)建窗口:namedWindow 函數(shù)
namedWindow 的函數(shù)原型如下:
void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE);
- 第一個(gè)參數(shù)邦鲫,const string& 類型的變量灸叼,窗口標(biāo)識(shí)符。
- 第二個(gè)參數(shù)庆捺,int 類型的變量古今,窗口類型。
類型 | 介紹 |
---|---|
WINDOW_NORMAL | 用戶可以改變窗口的大小 |
WINDOW_AUTOSIZE | 窗口自動(dòng)調(diào)整滔以,以顯示所顯示的圖像捉腥。用戶不可以手動(dòng)設(shè)置。 |
WINDOW_OPENGL | 使創(chuàng)建的窗口支持OpenGL |
5. 輸出圖像到文件:imwrite 函數(shù)
imwrite 函數(shù)原型如下:
bool imwrite(const string& filename,InputArray img, vector<int> params=vector<int>());
- 第一個(gè)參數(shù):const string& 類型的變量你画,文件名(需要后綴)抵碟。
- 第二個(gè)參數(shù):InputArray 類型的數(shù)據(jù),一般是 Mat 類型的圖像數(shù)據(jù)坏匪。
- 第三個(gè)參數(shù):vector<int> 類型的變量拟逮,特定格式保存的參數(shù)編碼。它有默認(rèn)值适滓。
圖片格式 | 介紹 |
---|---|
JPEG | 這個(gè)參數(shù)表示從 0 到 100 的圖片質(zhì)量敦迄,默認(rèn)值95。 |
PNG | 這個(gè)參數(shù)表示壓縮級(jí)別(CV_IMWRITE_PNG)從 0 到 9凭迹。值越高意味著罚屋,尺寸越小,壓縮時(shí)間越長(zhǎng)嗅绸。 默認(rèn)值是 3 |
PPM脾猛,PGM,PBM | 表示二進(jìn)制格式標(biāo)志(CV_IMWRITE_PXM_BINARY)鱼鸠,取值為 0 或者 1尖滚。 |
支持保存的幾種圖片格式與支持讀取的幾種圖片格式一致喉刘。
6. 圖像載入瞧柔、顯示與輸出的綜合程序
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, const char * argv[]) {
//載入圖像
cv::Mat image = cv::imread("1.jpg");
cv::Mat logo = cv::imread("Code_r_Wang.jpg");
//顯示原圖像
cv::namedWindow("1.jpg");
cv::imshow("1.jpg", image);
//顯示logo圖像
cv::namedWindow("Code_r_Wang.jpg");
cv::imshow("Code_r_Wang.jpg", logo);
//選取部分圖像
cv::Mat imageROI;
imageROI = image(cv::Rect(image.cols - logo.cols - 10, image.rows - logo.rows - 10, logo.cols, logo.rows));
//混合圖像(這個(gè)函數(shù)放到后面學(xué))
cv::addWeighted(imageROI, 0.5, logo, 0.5, 0.0, imageROI);
//展示結(jié)果圖
cv::namedWindow("result");
cv::imshow("result", image);
//圖像輸出到文件
cv::imwrite("疊加的結(jié)果圖像.jpg", image);
cv::waitKey();
return 0;
}
7. 滑動(dòng)條
- 創(chuàng)建滑動(dòng)條
createTrackbar 函數(shù)漆弄,用于創(chuàng)建一個(gè)可以調(diào)整數(shù)值的滑動(dòng)條,并將滑動(dòng)條依附至指定窗口造锅。函數(shù)原型如下:
int createTrackbar(const String& trackbarname, const String& winname, int *value, int count, TrackbarCallback onChange = 0, void* userdata = 0);
第一個(gè)參數(shù):const String& 類型變量撼唾,滑動(dòng)條的標(biāo)識(shí)符。
第二個(gè)參數(shù):const String& 類型變量哥蔚,要依附的窗口的標(biāo)識(shí)符倒谷。
第三個(gè)參數(shù):int* 類型變量,一個(gè)指向整型的指針糙箍,表示滑塊的位置渤愁。
第四個(gè)參數(shù):int 類型變量,表示滑塊滑塊可以到達(dá)的最大位置深夯《陡瘢滑塊最小位置為 0。
第五個(gè)參數(shù):TrackbarCallback 類型的 onChange咕晋,默認(rèn)值為 0雹拄。一個(gè)指向回調(diào)函數(shù)的指針。每次滑動(dòng)條位置改變掌呜,都會(huì)回調(diào)這個(gè)函數(shù)滓玖。可以在 highgui.hpp 頭文件中找到定義 typedef void (*TrackbarCallback)(int pos, void* userdata);
指向的指針必須為 void (int ,void*)類型质蕉。第一個(gè)參數(shù)為滑塊的位置势篡,第二個(gè)參數(shù)為用戶想要傳遞的數(shù)據(jù)。
第六個(gè)參數(shù):void* 類型的變量模暗,默認(rèn)值為 0禁悠。這個(gè)參數(shù)會(huì)作為回調(diào)函數(shù)的第二個(gè)參數(shù)。
- 測(cè)試程序
#include <iostream>
#include <opencv2/opencv.hpp>
//窗口宏
#define WINDOW_NAME "Trackbar Demo"
//滑動(dòng)條最大值
const int g_nMaxAlphaValue = 100;
//滑動(dòng)條對(duì)應(yīng)變量
int g_nAlphaValueSlider;
double g_dAlphaValue;
double g_dBetaValue;
//圖像
cv::Mat g_srcImage1;
cv::Mat g_srcImage2;
cv::Mat g_dstImage;
void on_Trackbar(int count, void* userdata){
//計(jì)算 alpha 值
g_dAlphaValue = (double) g_nAlphaValueSlider/g_nMaxAlphaValue;
//計(jì)算 beta 值
g_dBetaValue = 1 - g_dAlphaValue;
//線性混合(這個(gè)函數(shù)放到后面學(xué))
cv::addWeighted(g_srcImage1, g_dAlphaValue, g_srcImage2, g_dBetaValue, 0.0, g_dstImage);
//顯示效果圖
cv::imshow(WINDOW_NAME, g_dstImage);
}
int main(int argc, const char * argv[]) {
//載入圖像
g_srcImage1 = cv::imread("1.jpg");
g_srcImage2 = cv::imread("2.jpg");
//判斷是否載入成功汰蓉,失敗返回 -1
if ( !g_srcImage1.data || !g_srcImage2.data) {
return -1;
}
//賦最大參數(shù)值
g_nAlphaValueSlider = 70;
//創(chuàng)建窗口
cv::namedWindow(WINDOW_NAME);
//創(chuàng)建滑動(dòng)條
cv::createTrackbar("TrackBar", WINDOW_NAME, &g_nAlphaValueSlider, g_nMaxAlphaValue, on_Trackbar);
//初次混合
on_Trackbar(g_nAlphaValueSlider, NULL);
cv::waitKey();
return 0;
}
8. 鼠標(biāo)操作:setMouseCallback 函數(shù)
鼠標(biāo)操作的消息傳遞和滑動(dòng)條的消息傳遞方式很類似绷蹲。setMouseCallback 函數(shù)原型如下:
void setMouseCallback(const String &winname, MouseCallBack onMouse, void* userdata);
- 第一個(gè)參數(shù)窗口標(biāo)識(shí)符。
- 第二個(gè)參數(shù) MouseCallback 類型函數(shù)指針
//highgui.hpp 頭文件中
/** @brief Callback function for mouse events. see cv::setMouseCallback
@param event one of the cv::MouseEventTypes constants.
@param x The x-coordinate of the mouse event.
@param y The y-coordinate of the mouse event.
@param flags one of the cv::MouseEventFlags constants.
@param userdata The optional parameter.
*/
typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
第一個(gè)參數(shù):int 類型變量對(duì)應(yīng)枚舉值
enum MouseEventTypes {
EVENT_MOUSEMOVE = 0, //!< indicates that the mouse pointer has moved over the window.
EVENT_LBUTTONDOWN = 1, //!< indicates that the left mouse button is pressed.
EVENT_RBUTTONDOWN = 2, //!< indicates that the right mouse button is pressed.
EVENT_MBUTTONDOWN = 3, //!< indicates that the middle mouse button is pressed.
EVENT_LBUTTONUP = 4, //!< indicates that left mouse button is released.
EVENT_RBUTTONUP = 5, //!< indicates that right mouse button is released.
EVENT_MBUTTONUP = 6, //!< indicates that middle mouse button is released.
EVENT_LBUTTONDBLCLK = 7, //!< indicates that left mouse button is double clicked.
EVENT_RBUTTONDBLCLK = 8, //!< indicates that right mouse button is double clicked.
EVENT_MBUTTONDBLCLK = 9, //!< indicates that middle mouse button is double clicked.
EVENT_MOUSEWHEEL = 10,//!< positive and negative values mean forward and backward scrolling, respectively.
EVENT_MOUSEHWHEEL = 11 //!< positive and negative values mean right and left scrolling, respectively.
};
從枚舉的名稱不難看出其所代表的意義顾孽。
int x, int y 參數(shù)代表鼠標(biāo)指針在圖像坐標(biāo)系中的坐標(biāo)祝钢。
int flags 參數(shù)代表物理按鍵類型。對(duì)應(yīng)枚舉值如下:
//! Mouse Event Flags see cv::MouseCallback
enum MouseEventFlags {
EVENT_FLAG_LBUTTON = 1, //!< indicates that the left mouse button is down.
EVENT_FLAG_RBUTTON = 2, //!< indicates that the right mouse button is down.
EVENT_FLAG_MBUTTON = 4, //!< indicates that the middle mouse button is down.
EVENT_FLAG_CTRLKEY = 8, //!< indicates that CTRL Key is pressed.
EVENT_FLAG_SHIFTKEY = 16,//!< indicates that SHIFT Key is pressed.
EVENT_FLAG_ALTKEY = 32 //!< indicates that ALT Key is pressed.
};
*void userdata 參數(shù)代表自定義參數(shù)若厚。
- 第三個(gè)參數(shù):*void userdata 參數(shù)代表自定義參數(shù)拦英。