OpenCV4之C++入門詳解

語言: CN / TW / HK

OpenCV之C++入門

1、Visual Studio安裝及環境配置與搭建

  1. 下載地址: https://my.visualstudio.com/Downloads?q=Visual,下載後按照說明安裝即可

    登入賬號下載即可,建議下載Visual Studio 2017 專業版,本教程使用該版本完成

    該教程筆記是本人整理的OpenCV學堂影片教程內容,感謝賈志剛老師的影片教程,下面是OpenCV 4.5.4及原始碼下載連結

    連結: https://pan.baidu.com/s/1HmWrX35P774rr6tlfUXB2A 提取碼:urtd

  2. 配置系統環境變數,滑鼠右鍵我的電腦,選擇屬性,之後按下圖操作,複製opencv目錄下的bin目錄,vs2017選擇vc15

  3. 安裝完畢後,新建第一個專案如下圖

  4. 右鍵原始檔選擇新建項新建一個main.cpp

  5. 新增包含目錄、庫目錄及附加依賴項

  6. 在D盤下新建一個images資料夾,放入一張圖片,圖片名與下面程式碼段中的圖片名字一致

  7. 在main.cpp中輸入以下程式碼

    #include<opencv2/opencv.hpp>
    #include<iostream>
    
    using namespace cv;
    using namespace std;
    
    int main(int argc, char**argv) {
    	Mat src = imread("D:/images/lena.jpg");
    	imshow("input", src);
    	waitKey(0);
    	destroyAllWindows();
    	return 0;
    }
  8. 點選 除錯開始除錯 ,如果出現下圖則表示執行成功,配置成功

至此,Visual Studio的準備工作完成!

2、影象基本操作

多行註釋快捷鍵:Ctrl + K + Ctrl + C

2.1、影象讀取與顯示

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
    //imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	Mat src = imread("D:/images/lena.jpg",IMREAD_GRAYSCALE);   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()){
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("輸入視窗",WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名,imshow()只支援顯示8點陣圖像及浮點影象
	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

2.2、影象色彩空間轉換

新建一個頭檔案quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
};

新增該專案包含目錄為當前資料夾,操作如下

新建一個原始檔quickdemo.cpp

#include<quickopencv.h>

void QuickDemo::colorSpace_Demo(Mat ℑ) {
	Mat gray, hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	// H 0~180 S 0~255 V 0~255
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("HSV", hsv);
	imshow("灰度", gray);
	imwrite("D:/images/hsv.png", hsv);
	imwrite("D:/images/gray.png", gray);
}

修改原始檔test440,進行除錯

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	//imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

    //引入類QuickDemo,呼叫方法
	QuickDemo qd;
	qd.colorSpace_Demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.3、影象物件的建立與賦值

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
};

quickdemo.cpp

#include<quickopencv.h>

void QuickDemo::colorSpace_Demo(Mat ℑ) {
	Mat gray, hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	// H 0~180 S 0~255 V 0~255
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("HSV", hsv);
	imshow("灰度", gray);
	imwrite("D:/images/hsv.png", hsv);
	imwrite("D:/images/gray.png", gray);
}

void QuickDemo::mat_creation_demo() {
	//克隆和複製才會建立新的物件,賦值不會建立新的物件
	//Mat m1, m2;
	//m1 = image.clone();
	//image.copyTo(m2);

	// 建立空白影象
	Mat m3 = Mat::ones(Size(512, 512), CV_8UC3);
	m3 = Scalar(127, 127, 127); // 為畫素賦予指定的值 B,G,R順序

	std::cout << "width: " << m3.cols << " height: " << m3.rows << " channels: " << m3.channels() << std::endl;
	//std::cout << m3 << std::endl;

	Mat m4 = m3; //賦值後m4改變,會引起m3改變,clone或copyTo則會建立新物件,不影響原物件
	m4 = Scalar(0, 255, 255);

	imshow("建立影象", m3);

	Mat kernel = (Mat_<char>(3, 3) << 0,-1,0, // 3*3卷積核
		-1,5,-1,
		0,-1,0);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.mat_creation_demo();

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.4、影象畫素的讀寫操作

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
    	void pixel_visit_demo(Mat ℑ);
};

quickdemo.cpp

#include<quickopencv.h>

void QuickDemo::pixel_visit_demo(Mat ℑ) {
	int w = image.cols;
	int h = image.rows;
	int dims = image.channels();
	//for (int row = 0; row < h; row++) {
	//	for (int col = 0; col < w; col++) {
	//		if (dims == 1) { //灰度影象
	//			int pv = image.at<uchar>(row, col); //row,col → y,x
	//			image.at<uchar>(row, col) = 255 - pv; //對畫素值反轉,image.at<uchar>為獲取某點格式為uchar的畫素值
	//		}
	//		if (dims == 3) { //彩色影象
	//			Vec3b bgr = image.at<Vec3b>(row, col); //Vec3b為bgr影象畫素點儲存格式,對畫素值進行反轉
	//			image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
	//			image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
	//			image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
	//		}
	//	}
	//}

	for (int row = 0; row < h; row++) {
		uchar* current_row = image.ptr<uchar>(row); //獲取當前行最初位置的指標
		for (int col = 0; col < w; col++) {
			if (dims == 1) { //灰度影象
				int pv = *current_row;
				*current_row++ = 255 - pv; //每次運算完,指標右移一位
			}
			if (dims == 3) { //彩色影象
				*current_row++ = 255 - *current_row; //由於bgr影象矩陣是連續的,所以指標直接指向下一位
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
			}
		}
	}

	imshow("畫素讀寫演示", image);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.pixel_visit_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.5、影象畫素的算數操作

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
    	void pixel_visit_demo(Mat ℑ);
    	void operators_demo(Mat ℑ);
};

quickdemo.cpp

#include<quickopencv.h>

void QuickDemo::operators_demo(Mat ℑ) {
	Mat dst;
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(2, 2, 2); //Scalar標量

	//dst = image + Scalar(50, 50, 50);
	//dst = image - Scalar(50, 50, 50);
	//dst = image / Scalar(2, 2, 2);


	//加法手寫實現,主要使用saturate_cast函式,運算可使用對應函式快速實現
	/*
	int w = image.cols;
	int h = image.rows;
	int dims = image.channels();
	for (int row = 0; row < h; row++) {
		for (int col = 0; col < w; col++) {
			Vec3b p1 = image.at<Vec3b>(row, col);
			Vec3b p2 = m.at<Vec3b>(row, col);
			//saturate_cast函式,將大於255的數轉換為255,小於0的數轉換為0
			dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
			dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
			dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
		}
	}
	imshow("加法操作", dst);
	*/
	//add(image, m, dst); //add(操作的圖,對圖片操作的引數,輸出的結果)
	//subtract(image, m, dst); //減法
	//divide(image, m, dst); //除法
	multiply(image, m, dst); //乘法
	
	//imshow("加法操作", dst);
	//imshow("減法操作", dst);
	//imshow("除法操作", dst);
	imshow("乘法操作", dst);

}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/dark_face.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.operators_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.6、使用滾動條調整影象亮度(TrackBar)

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
};

quickdemo.cpp

Mat src, dst, m;
int lightness = 50;

//回撥函式兩個形參,第一個int為createTrackbar中當前滑塊所在位置,初始為lightness,第二個為userdata,為createTrackbar最後一個引數,預設為0
static void on_track(int, void*) {
	m = Scalar(lightness, lightness, lightness);
	add(src, m, dst);
	imshow("亮度調整", dst);
}
void QuickDemo::tracking_bar_demo(Mat ℑ) {
	namedWindow("亮度調整", WINDOW_AUTOSIZE);
	dst = Mat::zeros(image.size(), image.type());
	m = Mat::zeros(image.size(), image.type());
	src = image;
	int max_value = 100;

	//createTrackbar(滑動條名,滑動條所在的視窗,滑動塊初始位置,滑動條最大值,回撥函式(滑塊滑動時的處理))
	createTrackbar("Value Bar:", "亮度調整", &lightness, max_value, on_track); 
	on_track(50, 0);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/dark_face.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.tracking_bar_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.7、滾動條操作-通過引數傳遞度

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
};

quickdemo.cpp 對上一節函式優化

//回撥函式兩個形參,第一個int為createTrackbar中的當前滑塊所在位置,第二個為userdata,為createTrackbar最後一個引數,預設為0
static void on_lightness(int b, void* userdata) {
	Mat image = *((Mat*)userdata);  //指標轉換成Mat型別資料
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	addWeighted(image, 1.0, m, 0, b, dst);  //dst = image*1.0 + m*0 + b
	imshow("亮度與對比度調整", dst);
}
static void on_contrast(int b, void* userdata) {
	Mat image = *((Mat*)userdata);  //指標轉換成Mat型別資料
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	double contrast = b / 100.0;
	//addWeighted()函式可以實現兩張圖片混合
	addWeighted(image, contrast, m, 0, 0, dst);  //dst = image*contrast + m*0 + 0
	imshow("亮度與對比度調整", dst);
}
void QuickDemo::tracking_bar_demo(Mat ℑ) {
	namedWindow("亮度與對比度調整", WINDOW_AUTOSIZE);
	int lightness = 50;
	int light_max_value = 100;
	int contrast_value = 100;
	int contrast_max = 200;
	//createTrackbar(滑動條名,滑動條所在的視窗,滑動塊初始位置,滑動條最大值,回撥函式(滑塊滑動時的處理),userdata(傳遞給回撥函式的資料))
	createTrackbar("Value Bar:", "亮度與對比度調整", &lightness, light_max_value, on_lightness, (void*)(ℑ));
	createTrackbar("Contrast Bar:", "亮度與對比度調整", &contrast_value, contrast_max, on_contrast, (void*)(ℑ));
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/dark_face.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.tracking_bar_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.8、滾動條操作-鍵盤響應操作

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::key_demo(Mat ℑ) {
	Mat dst = Mat::zeros(image.size(), image.type());
	while (true) {
		int c = waitKey(1); //waitKey(影象重新整理時間間隔)不斷重新整理影象,重新整理間隔時間為1ms,影片處理時儘量設定1ms
		if (c == 27) { // 退出
			break;
		}
		if (c == 49) { // Key #1
			cvtColor(image, dst, COLOR_BGR2GRAY);
			imshow("鍵盤響應01", dst);
		}
		if (c == 50) { // Key #2
			cvtColor(image, dst, COLOR_BGR2HSV);
			imshow("鍵盤響應02", dst);
		}
		if (c == 51) { // Key #3
			dst = Scalar(50, 50, 50);
			add(image, dst, dst);
			imshow("鍵盤響應03", dst);
		}
		//imshow("鍵盤響應", dst);
	}
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.key_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.9、OpenCV自帶顏色表操作

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
    	void color_style_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::color_style_demo(Mat ℑ) {
	int colormap[] = {
		COLORMAP_AUTUMN,
		COLORMAP_BONE,
		COLORMAP_JET,
		COLORMAP_WINTER,
		COLORMAP_RAINBOW,
		COLORMAP_OCEAN,
		COLORMAP_SUMMER,
		COLORMAP_SPRING,
		COLORMAP_COOL,
		COLORMAP_PINK,
		COLORMAP_HOT,
		COLORMAP_PARULA,
		COLORMAP_MAGMA,
		COLORMAP_INFERNO,
		COLORMAP_PLASMA,
		COLORMAP_VIRIDIS,
		COLORMAP_CIVIDIS,
		COLORMAP_TWILIGHT,
		COLORMAP_TWILIGHT_SHIFTED
	};

	Mat dst;
	int index = 0;
	while (true) {
		int c = waitKey(2000);
		if (c == 27) {
			break;
		}
		applyColorMap(image, dst, colormap[index%19]);
		index++;
		imshow("顏色風格", dst);
	}
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.color_style_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.10、影象畫素的邏輯操作

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::bitwise_demo(Mat ℑ) {
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);

	//rectangle()函式第四個引數小於0表示填充,大於0表示繪製
	//rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), 2, LINE_8, 0);
	//rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), 2, LINE_8, 0);
	rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
	rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
	imshow("m1", m1);
	imshow("m2", m2);
	Mat dst;
	//bitwise_and(m1, m2, dst);
	//bitwise_or(m1, m2, dst);
	//dst = ~image;  //也可以實現影象取反操作
	//bitwise_not(image, dst);  //當前影象取反操作
	bitwise_xor(m1, m2, dst);  //異或((非m1 與 m2) 或 (m1 與 非m2)),相當於 m1或m2,相交的部分(非(m1 與 m2))
	imshow("畫素位操作", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.bitwise_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.11、通道分離與合併

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
    	void channels_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::channels_demo(Mat ℑ) {
	std::vector<Mat> mv;  //Mat陣列
	split(image, mv);
	imshow("藍色", mv[0]);
	imshow("綠色", mv[1]);
	imshow("紅色", mv[2]);

	Mat dst;
	//mv[1] = 0;
	//mv[2] = 0;
	//merge(mv, dst);
	//imshow("藍色", dst);
	//mv[0] = 0;
	//mv[2] = 0;
	//merge(mv, dst);
	//imshow("綠色", dst);
	mv[0] = 0;
	mv[1] = 0;
	merge(mv, dst);
	imshow("紅色", dst);

	//from_to[]複製列表
	int from_to[] = { 0,2,1,1,2,0 };  //通道0複製到通道2,通道1複製到通道1,通道2複製到通道0
	//mixChannels(輸入矩陣,輸入矩陣數量,輸出矩陣,輸出矩陣數量,複製列表,複製列表中複製幾次)
	mixChannels(ℑ, 1, &dst, 1, from_to, 3);
	imshow("通道混合", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/flower.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.channels_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.12、影象色彩空間轉換

HSV顏色空間表

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::inrange_demo(Mat ℑ) {
	Mat hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	Mat mask;
	inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);
	imshow("mask01", mask);

	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(40, 40, 200);
	bitwise_not(mask, mask);  //畫素邏輯運算,mask取反
	imshow("mask02", mask);
	//image.copyTo(拷貝到的影象,mask為1的部分拷貝為0的部分不拷貝)
	image.copyTo(redback, mask);  //將image拷貝到其他影象中
	imshow("roi區域提取", redback);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.inrange_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.13、影象畫素值統計

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::pixel_statistic_demo(Mat ℑ) {
	double minv, maxv;
	Point minLoc, maxLoc;
	Mat mean, stddev;
	std::vector<Mat> mv;
	split(image, mv);
	for (int i = 0; i < mv.size(); i++) {
		//第一個引數需要是單通道的影象,可以先把多通道分離;最後一個引數為mask
		minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
		std::cout << "No.channels: " << i << " min value: " << minv << " max value: " << maxv << std::endl;
		//第一個引數是單通道影象則計算一組均值、方差,如果是多通道影象,則同時計算多組均值、方差
		meanStdDev(mv[i], mean, stddev);
		std::cout << "means: " << mean << std::endl;
		std::cout << "stddev: " << stddev << std::endl;
	}
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.pixel_statistic_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.14、影象幾何形狀繪製,隨機數與隨機顏色

基本繪圖

1 Point:
 2     Point pt;
 3     pt.x = 10;
 4     pt.y = 8;
 5     或者
 6     Point pt =  Point(10, 8);
 7  
 8 Scalar:
 9     Scalar( B, G, R )   //定義的RGB顏色值為:Blue,Green, Red
10     
11 line 繪直線:
12     line( img,   //輸出影象
13         start,   //起始點
14         end,     //結束點
15         Scalar( 0, 0, 0 ),  //顏色
16         thickness=2,    //線條粗細
17         lineType=8 );   //線條型別
18  
19 ellipse 繪橢圓:
20     ellipse( img,   //輸出影象
21            Point( w/2.0, w/2.0 ),   //中心為點 (w/2.0, w/2.0) 
22            Size( w/4.0, w/16.0 ),     //大小位於矩形 (w/4.0, w/16.0) 內
23            angle,    //旋轉角度為 angle
24            0,
25            360,     //擴充套件的弧度從 0 度到 360 度
26            Scalar( 255, 0, 0 ),   //顏色
27            thickness,   //線條粗細
28            lineType );    //線條型別
29  
30 circle 繪圓:
31     circle( img,   //輸出影象
32          center,    //圓心由點 center 定義
33          w/32.0,     /圓的半徑為: w/32.0
34          Scalar( 0, 0, 255 ),   //顏色
35          thickness,   //線條粗細
36          lineType );   //線條型別
37          
38 rectangle 繪矩形:
39     rectangle( rook_image,
40            Point( 0, 7*w/8.0 ),
41            Point( w, w),    //矩形兩個對角頂點為 Point( 0, 7*w/8.0 ) 和 Point( w, w)
42            Scalar( 0, 255, 255 ),
43            thickness = -1,
44            lineType = 8 );
45  
46 fillPoly 繪填充的多邊形:
47     fillPoly( img,
48             ppt,   //多邊形的頂點集為 ppt
49             npt,   //要繪製的多邊形頂點數目為 npt
50             1,   //要繪製的多邊形數量僅為 1
51             Scalar( 255, 255, 255 ),
52             lineType );

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
};

quickdemo.cpp

void QuickDemo::form_paint_random() {
	Mat image_line = Mat::zeros(512, 512, CV_8UC3);  //新建兩個512*512的三通道矩陣
	Mat image_rect = Mat::zeros(512, 512, CV_8UC3);
	Rect rect;  //新建一個矩形物件
	RNG rng(0xFFFFFF);  //生成隨機數的類RNG,隨機數產生器,用數值0xFFFFFF來例項化一個RNG物件
	image_line.setTo(Scalar(0, 0, 0));  //將影象使用另一種顏色覆蓋
	image_rect.setTo(Scalar(0, 0, 0));  //將影象使用另一種顏色覆蓋

	for (int i = 0; i < 100000; i++) {
		int x1 = rng.uniform(0, 512);  //獲取[0,512)的均勻分佈的隨機數
		int y1 = rng.uniform(0, 512);
		int x2 = rng.uniform(0, 512);
		int y2 = rng.uniform(0, 512);

		int b = rng.uniform(0, 256);
		int g = rng.uniform(0, 256);
		int r = rng.uniform(0, 256);
		//void line(繪製線段的影象,起點座標,終點座標,線段的顏色通過Scalar()定義,線段的寬度(線寬為負數時表示填充),線段的型別,座標點小數點位數)
		line(image_line, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_AA, 0);  //線段的型別。可以取值LINE_8,LINE_4和LINE_AA,分別代表8鄰接連線線,4鄰接連線線和反鋸齒連線線。預設值為8鄰接。為了獲得更好地效果可以選用LINE_AA(採用了高斯濾波)。
		imshow("image_line", image_line);
		rect.x = x1;  //定義矩形的左上頂點座標及寬高
		rect.y = y1;
		rect.width = x2 - x1;
		rect.height = y2 - y1;
		rectangle(image_rect, rect, Scalar(b, g, r), 1, LINE_AA, 0);
		imshow("image_rect", image_rect);
		char c = waitKey(20);
		if (c == 27)
			break;
	}
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	//imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.form_paint_random();

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.15、多邊形填充與繪製

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
};

quickdemo.cpp

void QuickDemo::polyline_drawing_demo() {
	Mat canvas01 = Mat::zeros(Size(512, 512), CV_8UC3);
	Mat canvas02 = Mat::zeros(Size(512, 512), CV_8UC3);
	Point p1(100, 100);
	Point p2(350, 100);
	Point p3(450, 280);
	Point p4(320, 450);
	Point p5(80, 400);
	std::vector<Point> pts;
	pts.push_back(p1);
	pts.push_back(p2);
	pts.push_back(p3);
	pts.push_back(p4);
	pts.push_back(p5);
	fillPoly(canvas01, pts, Scalar(255, 255, 0), 8, 0);
	//polylines(繪製所在影象,要繪製的頂點集合,圖形是否閉合,線的顏色,線寬,線的型別)
	//polylines(canvas, pts, true, Scalar(0, 0, 255), 3, LINE_8, 0);  //不能設定線寬為負數進行填充
	polylines(canvas01, pts, true, Scalar(0, 0, 255), 3, LINE_AA, 0);  //使用LINE_AA抗鋸齒
	std::vector<std::vector<Point>> contours;
	contours.push_back(pts);
	//drawContours(繪製所在的影象,繪製的點集的集合,繪製第幾個點集-1表示全部繪製,線段顏色,線寬-1表示填充)
	drawContours(canvas02, contours, -1, Scalar(255, 0, 0), -1);
	imshow("多邊形繪製01", canvas01);
	imshow("多邊形繪製02", canvas02);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	//imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.polyline_drawing_demo();

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.16、滑鼠操作與響應

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
};

quickdemo.cpp

Point sp(-1, -1);  //起點
Point ep(-1, -1);  //終點
//新建一個temp矩陣儲存原影象,沒有繪製的
Mat temp;
static void on_draw(int event, int x, int y, int flags, void *userdata) {
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {
		sp.x = x;
		sp.y = y;
		std::cout << "start point: " << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {
		ep.x = x;
		ep.y = y;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {
			Rect box(sp.x, sp.y, dx, dy);
			temp.copyTo(image);  //去除繪製目標區域的邊框
			imshow("ROI區域", image(box));  //將繪製區域中的影象單獨顯示出來
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			imshow("滑鼠繪製", image);
			//ready for next drawing
			sp.x = -1;
			sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
		if (sp.x > 0 && sp.y > 0) {
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(image);  //每次都重新載入沒有繪製的原圖,實現擦除過程中繪製的圖形
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("滑鼠繪製", image);
			}
		}
	}
}

void QuickDemo::mouse_drawing_demo(Mat ℑ) {
	namedWindow("滑鼠繪製", WINDOW_AUTOSIZE);
	setMouseCallback("滑鼠繪製", on_draw, (void*)(ℑ));
	imshow("滑鼠繪製", image);
	temp = image.clone();  //將載入的原圖克隆到臨時矩陣temp中
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	//imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.mouse_drawing_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.17、影象畫素型別轉換與歸一化

影象為什麼要進行歸一化:

歸一化就是要把需要處理的資料經過處理後(通過某種演算法)限制在你需要的一定範圍內。首先歸一化是為了後面資料處理的方便,其次是保證程式執行時收斂加快。歸一化的具體作用是歸納統一樣本的統計分佈性。歸一化在0-1之間是統計的概率分佈,歸一化在某個區間上是統計的座標分佈。歸一化有同一、統一和合一的意思。

歸一化的目的簡而言之,是使得沒有可比性的資料變得具有可比性,同時又保持相比較的兩個資料之間的相對關係,如大小關係;或是為了作圖,原來很難在一張圖上作出來,歸一化後就可以很方便的給出圖上的相對位置等。

四種歸一化方式:

其中的NORM_L2計算方式例項如下公式,其他歸一化方式根據圖片中的內容即可理解

\[2.0\div \sqrt {{{2}^{2}+{8}^{2}+10}^{2}}\approx 0.15 \]

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
};

quickdemo.cpp

//image.type()返回的數值與型別對應關係,第一行為通道數,第一列為資料型別
+--------+----+----+----+----+------+------+------+------+
|        | C1 | C2 | C3 | C4 | C(5) | C(6) | C(7) | C(8) |
+--------+----+----+----+----+------+------+------+------+
| CV_8U  |  0 |  8 | 16 | 24 |   32 |   40 |   48 |   56 |
| CV_8S  |  1 |  9 | 17 | 25 |   33 |   41 |   49 |   57 |
| CV_16U |  2 | 10 | 18 | 26 |   34 |   42 |   50 |   58 |
| CV_16S |  3 | 11 | 19 | 27 |   35 |   43 |   51 |   59 |
| CV_32S |  4 | 12 | 20 | 28 |   36 |   44 |   52 |   60 |
| CV_32F |  5 | 13 | 21 | 29 |   37 |   45 |   53 |   61 |
| CV_64F |  6 | 14 | 22 | 30 |   38 |   46 |   54 |   62 |
+--------+----+----+----+----+------+------+------+------+


void QuickDemo::norm_demo(Mat ℑ) {
	Mat dst;
	std::cout << image.type() << std::endl;
	image.convertTo(image, CV_32F);  //將8UC3 Integer資料轉換成32F float資料,以便用於後續歸一化操作
	std::cout << image.type() << std::endl;

	//值歸一化與範圍歸一化:值歸一化L1,L2,MINMAX;範圍歸一化可以自己設定歸一化範圍如[0,255]
	//normalize(輸入陣列,輸出陣列,1用來規範值2規範範圍下限,0值歸一化其他範圍歸一化上限,歸一化選擇的數學公式型別)
	normalize(image, dst, 1.0, 0, NORM_MINMAX);  //轉換為浮點數型別後必須進行歸一化操作
	std::cout << dst.type() << std::endl;
	imshow("影象資料歸一化前", image);
	imshow("影象資料歸一化後", dst);
	//CV_8UC3, CV_32FC3
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.norm_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.18、影象放縮與插值

OpenCV影象放縮的五種插值演算法:最近鄰、雙線性、雙三次、基於畫素區域關係、蘭索斯插值。

1、最近鄰:選取離目標點最近的點作為新的插入點;

2、雙線性:由相鄰的四畫素(2 * 2)計算得出;

  • 原理公式及矩陣

  • 計算過程示意圖

3、雙三次:由相鄰的4 * 4畫素計算得出,公式類似於雙線性插值;

4、基於畫素區域關係:共分三種情況,影象放大時類似於雙線性插值,影象縮小(x軸、y軸同時縮小)又分兩種情況,此情況下可以避免波紋出現;

5、蘭索斯插值:由相鄰的8 * 8畫素計算得出,公式類似於雙線性

總結:

  • 速度比較:INTER_NEAREST(最近鄰插值)>INTER_LINEAR(雙線性插值)>INTER_CUBIC(三次樣條插值)>INTER_AREA(區域插值)
  • OpenCV推薦:如果要 縮小 影象,通常推薦使用 INTER_AREA 插值效果最好;而要 放大 影象,通常使用 INTER_CUBIC (速度較慢,但效果最好),或者使用 INTER_LINEAR (速度較快,效果還可以)。至於最近鄰插值 INTER_NEAREST,一般不推薦使用

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::resize_demo(Mat ℑ) {
	Mat zoomin, zoomout;
	int h = image.rows;
	int w = image.cols;

	//resize(輸入影象,輸出影象,大小變換方法Size(),x方向縮放係數,y方向縮放係數,插值演算法)
	//如果size有值,使用size做放縮插值,否則根據fx與fy卷積
	resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);
	imshow("zoomin", zoomin);
	resize(image, zoomout, Size(w * 1.5, h * 1.5), 0, 0, INTER_LINEAR);
	imshow("zoomout", zoomout);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.resize_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.19、影象翻轉

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::flip_demo(Mat ℑ) {
	Mat dst;
	flip(image, dst, 0);  //上下翻轉
	imshow("影象上下翻轉", dst);
	flip(image, dst, 1);  //左右翻轉
	imshow("影象左右翻轉", dst);
	flip(image, dst, -1);  //180°旋轉
	imshow("影象180°翻轉", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/greenback.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.flip_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.20、影象旋轉

公式:

\[i'\, =\, icosθ\, -\, j\sin {\theta } \]

\[i'\, =\, i\sin {\theta }\, +\, jcosθ \]

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::rotate_demo(Mat ℑ) {
	Mat dst, M;
	int w = image.cols;
	int h = image.rows;
	M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);
	double cos = abs(M.at<double>(0, 0));
	double sin = abs(M.at<double>(0, 1));
	int nw = cos * w + sin * h;
	int nh = sin * w + cos * h;
	M.at<double>(0, 2) += (nw / 2 - w / 2);
	M.at<double>(1, 2) += (nh / 2 - h / 2);
	warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 255, 0));
	imshow("旋轉展示", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.rotate_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.21、影片檔案攝像頭使用

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::video_demo(Mat ℑ) {
	//VideoCapture capture(0);  //獲取當前裝置攝像頭影片
	VideoCapture capture("D:/images/video/example.mp4");  //獲取該地址下的影片
	Mat frame;

	while (true) {
		capture.read(frame);

		int h = frame.rows;  //獲取影片每一幀的寬高
		int w = frame.cols;

		//flip(frame, frame, 1);  //攝像頭需要翻轉,影片不需要翻轉
		if (frame.empty()) {
			break;
		}

		resize(frame, frame, Size(w / 4, h / 4), 0, 0, INTER_LINEAR);  //縮放影片

		imshow("frame", frame);  //顯示縮放後的影片

		colorSpace_Demo(frame);  //呼叫色彩空間轉換函式,將影片轉換為灰度影象及HSV影象並顯示

		// TODO: do something....
		int c = waitKey(10);
		if (c == 27) {  //退出
			break;
		}
	}
	
	//release
	capture.release();
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	//imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.video_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.22、影片處理與儲存

解析度清晰度對照:

影片顯示格式 解析度尺寸名 漢語簡稱
480p、576p SD(Standard Definition) 標清
720p HD(High Definition) 高清
1080p FHD(Full High Definition) 全高清
2k QHD(Quad High Definition) 四倍HD
4k UHD(Ultra High Definition) 超高清 或 4k UHD
8k FUHD(Full Ultra High Definition) 8k超高清 或 8k UHD

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::video_demo(Mat ℑ) {
	//VideoCapture capture(0);  //獲取當前裝置攝像頭影片
	VideoCapture capture("D:/images/video/example.mp4");  //獲取該地址下的影片

	int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);  //獲取影片幀的寬高
	int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);
	int count = capture.get(CAP_PROP_FRAME_COUNT);  //獲取影片的全部幀數
	double fps = capture.get(CAP_PROP_FPS);  //獲取影片每秒幀數fps
	std::cout << "frame width: " << frame_width << std::endl;
	std::cout << "frame height: " << frame_height << std::endl;
	std::cout << "FPS: " << fps << std::endl;
	std::cout << "Number of Frames: " << count << std::endl;
	int fourcc = VideoWriter::fourcc('a','v','c','1');  //H264編碼格式的fourcc code
    
    //VideoWriter writer(儲存地址,fourcc編碼格式code,幀率,儲存影片的畫面寬高,是否是彩色);
	VideoWriter writer("D:/test.mp4", fourcc, fps, Size(frame_width, frame_height), true);

	Mat frame;
	Mat frame1;

	while (true) {
		capture.read(frame);

		int h = frame.rows;  //獲取影片每一幀的寬高
		int w = frame.cols;

		//flip(frame, frame, 1);  //攝像頭需要翻轉,影片不需要翻轉
		if (frame.empty()) {
			break;
		}

		resize(frame, frame1, Size(w / 4, h / 4), 0, 0, INTER_LINEAR);  //縮放影片

		imshow("frame", frame1);  //顯示縮放後的影片

		//colorSpace_Demo(frame);  //呼叫色彩空間轉換函式,將影片轉換為灰度影象及HSV影象並顯示
		writer.write(frame);  //將每一幀儲存到新的檔案中

		// TODO: do something....
		int c = waitKey(10);
		if (c == 27) {  //退出
			break;
		}
	}
	
	//release
	capture.release();
    writer.release();
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	//imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.video_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

執行過程中缺少H264編碼器:

1、出現錯誤

2、到給出的網站中下載對應的 dll 檔案

3、將該檔案下載解壓後放到opencv的bin目錄下

4、再次執行正常

注意: H264 對應的 fourcc codeavc1 ! 具體原因可以自行百度,與OpenCV遵守的開源協議有關

2.23、影象直方圖

影象直方圖解釋:

影象直方圖使影象畫素值的統計學特徵,計算代價較小,具有影象平移、旋轉、縮放不變性等眾多優點,廣泛地應用域影象處理的各個領域,特別是灰度影象的閾值分割、基於顏色的影象檢索以及影象分類、反向投影跟蹤。常見的分為 灰度直方圖顏色直方圖

Bins是指直方圖的大小範圍,對於畫素值取在0~255之間的,最少有256個bin,此外還可以有16、32、48、128等,256除以bin的大小應該是整數倍。

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::histogram_demo(Mat ℑ) {
	//三通道分離
	std::vector<Mat> bgr_plane;  //定義Mat型別的集合,用來儲存三通道資料
	split(image, bgr_plane);  //將影象三通道分離,儲存到定義的集合中
	//定義引數變數
	const int channels[1] = { 0 };
	const int bins[1] = { 256 };
	float hranges[2] = { 0,255 };
	const float* ranges[1] = { hranges };
	Mat b_hist;
	Mat g_hist;
	Mat r_hist;
	//計算Blue,Green,Red通道的直方圖
	calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
	calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
	calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
	//顯示直方圖
	int hist_w = 512;
	int hist_h = 400;
	int bin_w = cvRound((double)hist_w / bins[0]);
	Mat histImage = Mat::zeros(hist_h, hist_w,CV_8UC3);
	//歸一化直方圖資料
	normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	//繪製直方圖曲線
	for (int i = 1; i < bins[0]; i++) {
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA, 0);
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA, 0);
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA, 0);
	}
	//顯示直方圖
	namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
	imshow("Histogram Demo", histImage);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/flower.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.histogram_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.24、二維直方圖

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
    	        void histogram_2d_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::histogram_2d_demo(Mat ℑ) {
	//2D直方圖
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	int hbins = 30, sbins = 32;
	int hist_bins[] = { hbins,sbins };
	float h_range[] = { 0,180 };
	float s_range[] = { 0,256 };
	const float* hs_ranges[] = { h_range,s_range };
	int hs_channels[] = { 0,1 };
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);
	double maxVal = 0;
	minMaxLoc(hs_hist, 0, &maxVal, 0, 0);
	int scale = 10;
	Mat hist2d_image = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3);
	Mat hist2d_image_back = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3);
	for (int h = 0; h < hbins; h++) {
		for (int s = 0; s < sbins; s++) {
			float binVal = hs_hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(hist2d_image, Point(h*scale, s*scale), 
				Point((h + 1)*scale - 1, (s + 1)*scale - 1), 
				Scalar::all(intensity), 
				-1);
		}
	}

	applyColorMap(hist2d_image, hist2d_image_back, COLORMAP_JET);

	imshow("H-S Histogram", hist2d_image);
	imshow("H-S Histogram_back", hist2d_image_back);
	imwrite("D:/hist_2d.png", hist2d_image);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/flower.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.histogram_2d_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.25、直方圖均衡化

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
    	        void histogram_2d_demo(Mat ℑ);
    	        void histogram_eq_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::histogram_eq_demo(Mat ℑ) {
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("灰度影象", gray);
	Mat dst;
	equalizeHist(gray, dst);
	imshow("直方圖均衡化演示", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/flower.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.histogram_eq_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.26、影象卷積操作

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
    	        void histogram_2d_demo(Mat ℑ);
    	        void histogram_eq_demo(Mat ℑ);
    	        void blur_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::blur_demo(Mat ℑ) {
	Mat dst01, dst02, dst03, dst04, dst05;
	blur(image, dst01, Size(3, 3), Point(-1, -1));
	blur(image, dst02, Size(13, 13), Point(-1, -1));
	blur(image, dst03, Size(23, 23), Point(-1, -1));
	blur(image, dst04, Size(13, 1), Point(-1, -1));
	blur(image, dst05, Size(1, 13), Point(-1, -1));
	
	imshow("影象模糊01", dst01);
	imshow("影象模糊02", dst02);
	imshow("影象模糊03", dst03);
	imshow("影象模糊04", dst04);
	imshow("影象模糊05", dst05);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/flower.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.blur_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.27、高斯模糊

高斯模糊計算公式:

\[G(x,y)=\frac {1} {2π{σ}^{2}}{e}^{-({x}^{2}+{y}^{2})/(2{σ}^{2})} \]

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
    	        void histogram_2d_demo(Mat ℑ);
    	        void histogram_eq_demo(Mat ℑ);
    	        void blur_demo(Mat ℑ);
    	        void gaussian_blue_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::gaussian_blue_demo(Mat ℑ) {

	Mat dst01, dst02, dst03;
	GaussianBlur(image, dst01, Size(5, 5), 15);
	GaussianBlur(image, dst02, Size(3, 3), 15);
	GaussianBlur(image, dst03, Size(0, 0), 15);

	imshow("高斯模糊01",dst01);
	imshow("高斯模糊02",dst02);
	imshow("高斯模糊03",dst03);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/flower.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.gaussian_blue_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

2.28、高斯雙邊模糊

雙邊濾波原理:

  • 空間距離:當前點距離濾波模板中心點的歐式距離。

  • 灰度距離:當前點距離濾波模板中心點的灰度的差值的絕對值。

雙邊濾波的核函式是 空間域核畫素範圍域核 的綜合結果:

  1. 在影象的平坦區域,畫素值變化很小,那麼畫素差值接近於0,對應的畫素範圍域權重接近於1,此時空間域權重起主要作用,相當於進行高斯模糊;

  2. 在影象的邊緣區域,畫素值變化很大,那麼畫素差值大,對應的畫素範圍域權重變大,即使距離遠空間域權重小,加上畫素域權重總的係數也較大,從而保護了邊緣的資訊。

雙邊濾波在突變的邊緣上,使用了畫素差權重,很好的保留了邊緣。

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
    	        void histogram_2d_demo(Mat ℑ);
    	        void histogram_eq_demo(Mat ℑ);
    	        void blur_demo(Mat ℑ);
    	        void gaussian_blue_demo(Mat ℑ);
    	        void bifilter_demo(Mat ℑ);
};

quickdemo.cpp

void QuickDemo::bifilter_demo(Mat ℑ) {
	Mat dst;
	bilateralFilter(image, dst, 0, 100, 10);
	imshow("雙邊模糊", dst);
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.bifilter_demo(src);

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果

3、案例:實時人臉識別

先下載三個檔案置於opencv的face_detector路徑下:D:\environment\opencv\sources\samples\dnn\face_detector

下載地址及檔案如下:

quickopencv.h

#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
	public:
		void colorSpace_Demo(Mat ℑ);
		void mat_creation_demo();
		void pixel_visit_demo(Mat ℑ);
		void operators_demo(Mat ℑ);
		void tracking_bar_demo(Mat ℑ);
		void key_demo(Mat ℑ);
		void color_style_demo(Mat ℑ);
		void bitwise_demo(Mat ℑ);
		void channels_demo(Mat ℑ);
		void inrange_demo(Mat ℑ);
    	        void pixel_statistic_demo(Mat ℑ);
    	        void form_paint_random();
    	        void polyline_drawing_demo();
		void mouse_drawing_demo(Mat ℑ);
    	        void norm_demo(Mat ℑ);
    	        void resize_demo(Mat ℑ);
    	        void flip_demo(Mat ℑ);
    	        void rotate_demo(Mat ℑ);
    	        void video_demo(Mat ℑ);
    	        void histogram_demo(Mat ℑ);
    	        void histogram_2d_demo(Mat ℑ);
    	        void histogram_eq_demo(Mat ℑ);
    	        void blur_demo(Mat ℑ);
    	        void gaussian_blue_demo(Mat ℑ);
    	        void bifilter_demo(Mat ℑ);
    	        void face_detection_demo();
};

quickdemo.cpp

#include<quickopencv.h>
#include<opencv2/dnn.hpp>

using namespace cv;
using namespace std;

void QuickDemo::face_detection_demo() {
	std::string root_dir = "D:/environment/opencv/sources/samples/dnn/face_detector/";
	dnn::Net net = dnn::readNetFromTensorflow(root_dir + "opencv_face_detector_uint8.pb", root_dir + "opencv_face_detector.pbtxt");
	VideoCapture capture("D:/images/video/example_dsh.mp4");
	Mat frame;
	while (true) {
		capture.read(frame);
		if (frame.empty()) {
			break;
		}
		Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);
		net.setInput(blob);  //NCHW
		Mat probs = net.forward();
		Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>());
		//解析結果	
		for (int i = 0; i < detectionMat.rows; i++) {
			float confidence = detectionMat.at<float>(i, 2);
			if (confidence > 0.5) {
				int x1 = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols);
				int y1 = static_cast<int>(detectionMat.at<float>(i, 4)*frame.rows);
				int x2 = static_cast<int>(detectionMat.at<float>(i, 5)*frame.cols);
				int y2 = static_cast<int>(detectionMat.at<float>(i, 6)*frame.rows);
				Rect box(x1, y1, x2 - x1, y2 - y1);
				rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0);
			}
		}
		imshow("人臉檢測演示", frame);
		//TODO: do something...
		int c = waitKey(1);
		if (c == 27) { //退出
			break;
		}
		
	}
}

test440.cpp

#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char**argv) {
	// imread函式的第二個引數有很多,預設為IMREAD_COLOR,還有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,實現對不同圖片的讀取操作
	// B,G,R
	Mat src = imread("D:/images/lena.jpg");   //Mat為matrix,二維影象都是Mat型別,第一個引數為圖片絕對路徑
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	//namedWindow("輸入視窗", WINDOW_FREERATIO);   //不管圖片大小,都能進行調整,影象很小可以不使用這個函式
	//imshow("輸入視窗", src);                    //第一個引數為視窗名

	QuickDemo qd;
	qd.face_detection_demo();

	waitKey(0);                               //視窗停留時間,0為一直停留,數值為停留的毫秒數
	destroyAllWindows();                      //關閉所有開啟的視窗
	return 0;
}

效果