主頁 >  其他 > OpenCV4 三、四章函式合計

OpenCV4 三、四章函式合計

2021-08-05 08:46:39 其他

第3章 影像基本操作

3.1 影像顏色空間

3.1.1 顏色模型與轉換

  1. RGB顏色模型
  2. YUV顏色模型
  3. HSV顏色模型
  4. Lab顏色模型
  5. GRAY顏色模型

6.不同顏色模型間的互想轉換

cvtColor()函式用于將影像從一個顏色模型轉換為另一個顏色模型

void cv::cvtColor(InputArray src,
                 OutputArray dst,
                 int code,
                 int dstCn = 0
                 )
  • src:待轉換顏色模型原始影像
  • dst:轉換顏色模型后的目標影像
  • code:顏色空間轉換的標志,如由RGB空間到HSV空間
  • dstCn:目標影像中的通道數

代碼清單3-2 影像顏色模型相互轉換

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("E:/BaiduNetdiskDownload/data/lena.png");
    if (img.empty())
    {
        cout << "請確認影像檔案名稱師范正確" << endl;
        return -1;
    }
    Mat gray, HSV, YUV, Lab, img32;
    img.convertTo(img32, CV_32F, 1.0 / 255); //將CV_8U型別轉換成CV_32F型別
    //img32.convertTo(img,CV_8U,255); //將CV_32F型別轉換成CV_8U型別
    cvtColor(img32, HSV, COLOR_BGR2HSV);
    cvtColor(img32, YUV, COLOR_BGR2YUV);
    cvtColor(img32, Lab, COLOR_BGR2Lab);
    cvtColor(img32, gray, COLOR_BGR2GRAY);
    imshow("原圖", img32);
    imshow("HSV", HSV);
    imshow("YUV", YUV);
    imshow("Lab", Lab);
    imshow("gray", gray);
    waitKey(0);
    return 0;
}

convertTo()

3.1.2 多通道分離與合并

split()

merge()

代碼清單3-6 實作影像分離與合并

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat HSV;
	cvtColor(img, HSV, COLOR_RGB2HSV);
	Mat imgs0, imgs1, imgs2;  //用于存放陣列型別的結果
	Mat imgv0, imgv1, imgv2;  //用于存放vector型別的結果
	Mat result0, result1, result2;  //多通道合并的結果

									//輸入陣列引數的多通道分離與合并
	Mat imgs[3];
	split(img, imgs);
	imgs0 = imgs[0];
	imgs1 = imgs[1];
	imgs2 = imgs[2];
	imshow("RGB-B通道", imgs0);  //顯示分離后B通道的像素值
	imshow("RGB-G通道", imgs1);  //顯示分離后G通道的像素值
	imshow("RGB-R通道", imgs2);  //顯示分離后R通道的像素值
	imgs[2] = img;  //將陣列中的影像通道數變成不統一
	merge(imgs, 3, result0);  //合并影像
							  //imshow("result0", result0);  //imshow最多顯示4個通道,因此結果在Image Watch中查看
	Mat zero = cv::Mat::zeros(img.rows, img.cols, CV_8UC1);
	imgs[0] = zero;
	imgs[2] = zero;
	merge(imgs, 3, result1);  //用于還原G通道的真實情況,合并結果為綠色
	imshow("result1", result1);  //顯示合并結果

								 //輸入vector引數的多通道分離與合并
	vector<Mat> imgv;
	split(HSV, imgv);
	imgv0 = imgv.at(0);
	imgv1 = imgv.at(1);
	imgv2 = imgv.at(2);
	imshow("HSV-H通道", imgv0);  //顯示分離后H通道的像素值
	imshow("HSV-S通道", imgv1);  //顯示分離后S通道的像素值
	imshow("HSV-V通道", imgv2);  //顯示分離后V通道的像素值
	imgv.push_back(HSV);  //將vector中的影像通道數變成不統一
	merge(imgv, result2);  //合并影像
						   //imshow("result2", result2);  /imshow最多顯示4個通道,因此結果在Image Watch中查看
	waitKey(0);
	return 0;
}

3.2 影像像素操作處理

3.2.1 影像像素統計

1.尋找影像像素最大值與最小值

minMaxLoc()

資料型別 Point

CU::Mat::reshape()

代碼清單3-9 尋找矩陣中的最值

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	system("color F0");  //更改輸出界面顏色
	float a[12] = { 1, 2, 3, 4, 5, 10, 6, 7, 8, 9, 10, 0 };
	Mat img = Mat(3, 4, CV_32FC1, a);  //單通道矩陣
	Mat imgs = Mat(2, 3, CV_32FC2, a);  //多通道矩陣
	double minVal, maxVal;  //用于存放矩陣中的最大值和最小值
	Point minIdx, maxIdx;  用于存放矩陣中的最大值和最小值在矩陣中的位置

	/*尋找單通道矩陣中的最值*/
	minMaxLoc(img, &minVal, &maxVal, &minIdx, &maxIdx);
	cout << "img中最大值是:" << maxVal << "  " << "在矩陣中的位置:" << maxIdx << endl;
	cout << "img中最小值是:" << minVal << "  " << "在矩陣中的位置:" << minIdx << endl;

	/*尋找多通道矩陣中的最值*/
	Mat imgs_re = imgs.reshape(1, 4);  //將多通道矩陣變成單通道矩陣
	minMaxLoc(imgs_re, &minVal, &maxVal, &minIdx, &maxIdx);
	cout << "imgs中最大值是:" << maxVal << "  " << "在矩陣中的位置:" << maxIdx << endl;
	cout << "imgs中最小值是:" << minVal << "  " << "在矩陣中的位置:" << minIdx << endl;
	return 0;
}

2.計算影像的平均值和標準差

meanStdDev() 函式用于同時計算平均值和標準差

mean() 計算平均值

cv::Scalar 型別

代碼清單3-12 計算矩陣平均值和標準差

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	system("color F0");  //更改輸出界面顏色
	float a[12] = { 1, 2, 3, 4, 5, 10, 6, 7, 8, 9, 10, 0 };
	Mat img = Mat(3, 4, CV_32FC1, a);  //單通道矩陣
	Mat imgs = Mat(2, 3, CV_32FC2, a);  //多通道矩陣

	cout << "/* 用meanStdDev同時求取影像的均值和標準差 */" << endl;
	Scalar myMean;
	myMean = mean(imgs);
	cout << "imgs均值=" << myMean << endl;
	cout << "imgs第一個通道的均值=" << myMean[0] << "    "
		<< "imgs第二個通道的均值=" << myMean[1] << endl << endl;

	cout << "/* 用meanStdDev同時求取影像的均值和標準差 */" << endl;
	Mat myMeanMat, myStddevMat;

	meanStdDev(img, myMeanMat, myStddevMat);
	cout << "img均值=" << myMeanMat << "    " << endl;
	cout << "img標準差=" << myStddevMat << endl << endl;
	meanStdDev(imgs, myMeanMat, myStddevMat);
	cout << "imgs均值=" << myMeanMat << "    " << endl << endl;
	cout << "imgs標準差=" << myStddevMat << endl;
	return 0;
}

2.2.2 兩影像間的像素操作

1.兩幅影像的比較運算

max()

min()

代碼清單3-14 兩個矩陣或影像進行比較運算

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	float a[12] = { 1, 2, 3.3, 4, 5, 9, 5, 7, 8.2, 9, 10, 2 };
	float b[12] = { 1, 2.2, 3, 1, 3, 10, 6, 7, 8, 9.3, 10, 1 };
	Mat imga = Mat(3, 4, CV_32FC1, a);
	Mat imgb = Mat(3, 4, CV_32FC1, b);
	Mat imgas = Mat(2, 3, CV_32FC2, a);
	Mat imgbs = Mat(2, 3, CV_32FC2, b);

	//對兩個單通道矩陣進行比較運算
	Mat myMax, myMin;
	max(imga, imgb, myMax);
	min(imga, imgb, myMin);

	//對兩個多通道矩陣進行比較運算
	Mat myMaxs, myMins;
	max(imgas, imgbs, myMaxs);
	min(imgas, imgbs, myMins);

	//對兩張彩色影像進行比較運算
	Mat img0 = imread("len.png");
	Mat img1 = imread("noobcv.jpg");

	if (img0.empty() || img1.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat comMin, comMax;
	max(img0, img1, comMax);
	min(img0, img1, comMin);
	imshow("comMin", comMin);
	imshow("comMax", comMax);

	//與掩模進行比較運算
	Mat src1 = Mat::zeros(Size(512, 512), CV_8UC3);
	Rect rect(100, 100, 300, 300);
	src1(rect) = Scalar(255, 255, 255);  //生成一個低通300*300的掩模
	Mat comsrc1, comsrc2;
	min(img0, src1, comsrc1);
	imshow("comsrc1", comsrc1);

	Mat src2 = Mat(512, 512, CV_8UC3, Scalar(0, 0, 255));  //生成一個顯示紅色通道的低通掩模
	min(img0, src2, comsrc2);
	imshow("comsrc2", comsrc2);

	//對兩張灰度影像進行比較運算
	Mat img0G, img1G, comMinG, comMaxG;
	cvtColor(img0, img0G, COLOR_BGR2GRAY);
	cvtColor(img1, img1G, COLOR_BGR2GRAY);
	max(img0G, img1G, comMaxG);
	min(img0G, img1G, comMinG);
	imshow("comMinG", comMinG);
	imshow("comMaxG", comMaxG);
	waitKey(0);
	return 0;
}

2.兩幅影像的邏輯運算

biwise_and()

biwise_or()

biwise_xor()

biwise_not()

代碼清單3-16 兩個黑白影像像素邏輯運算

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	//創建兩個黑白影像
	Mat img0 = Mat::zeros(200, 200, CV_8UC1);
	Mat img1 = Mat::zeros(200, 200, CV_8UC1);
	Rect rect0(50, 50, 100, 100);
	img0(rect0) = Scalar(255);
	Rect rect1(100, 100, 100, 100);
	img1(rect1) = Scalar(255);
	imshow("img0", img0);
	imshow("img1", img1);

	//進行邏輯運算
	Mat myAnd, myOr, myXor, myNot, imgNot;
	bitwise_not(img0, myNot);
	bitwise_and(img0, img1, myAnd);
	bitwise_or(img0, img1, myOr);
	bitwise_xor(img0, img1, myXor);
	bitwise_not(img, imgNot);
	imshow("myAnd", myAnd);
	imshow("myOr", myOr);
	imshow("myXor", myXor);
	imshow("myNot", myNot);
	imshow("img", img);
	imshow("imgNot", imgNot);
	waitKey(0);
	return 0;
}

3.2.3 影像二值化

threshold()

adaptiveThreshold()

代碼清單3-19 影像二值化

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	Mat img_B, img_B_V, gray_B, gray_B_V, gray_T, gray_T_V, gray_TRUNC;

	//彩色影像二值化
	threshold(img, img_B, 125, 255, THRESH_BINARY);
	threshold(img, img_B_V, 125, 255, THRESH_BINARY_INV);
	imshow("img_B", img_B);
	imshow("img_B_V", img_B_V);

	//灰度圖BINARY二值化
	threshold(gray, gray_B, 125, 255, THRESH_BINARY);
	threshold(gray, gray_B_V, 125, 255, THRESH_BINARY_INV);
	imshow("gray_B", gray_B);
	imshow("gray_B_V", gray_B_V);

	//灰度影像TOZERO變換
	threshold(gray, gray_T, 125, 255, THRESH_TOZERO);
	threshold(gray, gray_T_V, 125, 255, THRESH_TOZERO_INV);
	imshow("gray_T", gray_T);
	imshow("gray_T_V", gray_T_V);

	//灰度影像TRUNC變換
	threshold(gray, gray_TRUNC, 125, 255, THRESH_TRUNC);
	imshow("gray_TRUNC", gray_TRUNC);

	//灰度影像大津法和三角形法二值化
	Mat img_Thr = imread("threshold.png", IMREAD_GRAYSCALE);
	Mat img_Thr_O, img_Thr_T;
	threshold(img_Thr, img_Thr_O, 100, 255, THRESH_BINARY | THRESH_OTSU);
	threshold(img_Thr, img_Thr_T, 125, 255, THRESH_BINARY | THRESH_TRIANGLE);
	imshow("img_Thr", img_Thr);
	imshow("img_Thr_O", img_Thr_O);
	imshow("img_Thr_T", img_Thr_T);

	//灰度影像自適應二值化
	Mat adaptive_mean, adaptive_gauss;
	adaptiveThreshold(img_Thr, adaptive_mean, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 55, 0);
	adaptiveThreshold(img_Thr, adaptive_gauss, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 55, 0);

	imshow("adaptive_mean", adaptive_mean);
	imshow("adaptive_gauss", adaptive_gauss);
	waitKey(0);
	return 0;
}

3.2.4 LUT

LUT()

代碼清單3-21 對影像進行查找表映射

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

using namespace std;
using namespace cv;

int main()
{
	//LUT查找表第一層
	uchar lutFirst[256];
	for (int i = 0; i<256; i++)
	{
		if (i <= 100)
			lutFirst[i] = 0;
		if (i > 100 && i <= 200)
			lutFirst[i] = 100;
		if (i > 200)
			lutFirst[i] = 255;
	}
	Mat lutOne(1, 256, CV_8UC1, lutFirst);

	//LUT查找表第二層
	uchar lutSecond[256];
	for (int i = 0; i<256; i++)
	{
		if (i <= 100)
			lutSecond[i] = 0;
		if (i > 100 && i <= 150)
			lutSecond[i] = 100;
		if (i > 150 && i <= 200)
			lutSecond[i] = 150;
		if (i > 200)
			lutSecond[i] = 255;
	}
	Mat lutTwo(1, 256, CV_8UC1, lutSecond);

	//LUT查找表第三層
	uchar lutThird[256];
	for (int i = 0; i<256; i++)
	{
		if (i <= 100)
			lutThird[i] = 100;
		if (i > 100 && i <= 200)
			lutThird[i] = 200;
		if (i > 200)
			lutThird[i] = 255;
	}
	Mat lutThree(1, 256, CV_8UC1, lutThird);

	//擁有三通道的LUT查找表矩陣
	vector<Mat> mergeMats;
	mergeMats.push_back(lutOne);
	mergeMats.push_back(lutTwo);
	mergeMats.push_back(lutThree);
	Mat LutTree;
	merge(mergeMats, LutTree);

	//計算影像的查找表
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	Mat gray, out0, out1, out2;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	LUT(gray, lutOne, out0);
	LUT(img, lutOne, out1);
	LUT(img, LutTree, out2);
	imshow("out0", out0);
	imshow("out1", out1);
	imshow("out2", out2);
	waitKey(0);
	return 0;
}

3.3 影像變換

3.3.1 影像連接

vconcat()

hconcat()

代碼清單3-26 影像拼接

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

using namespace std;
using namespace cv;

int main()
{
	//矩陣陣列的橫豎連接
	Mat matArray[] = { Mat(1, 2, CV_32FC1, cv::Scalar(1)),
		Mat(1, 2, CV_32FC1, cv::Scalar(2)) };
	Mat vout, hout;
	vconcat(matArray, 2, vout);
	cout << "影像陣列豎向連接:" << endl << vout << endl;
	hconcat(matArray, 2, hout);
	cout << "影像陣列橫向連接:" << endl << hout << endl;

	//矩陣的橫豎拼接
	Mat A = (cv::Mat_<float>(2, 2) << 1, 7, 2, 8);
	Mat B = (cv::Mat_<float>(2, 2) << 4, 10, 5, 11);
	Mat vC, hC;
	vconcat(A, B, vC);
	cout << "多個影像豎向連接:" << endl << vC << endl;
	hconcat(A, B, hC);
	cout << "多個影像橫向連接:" << endl << hC << endl;

	//讀取4個子影像,00表示左上角、01表示右上角、10表示左下角、11表示右下角
	Mat img00 = imread("lena00.png");
	Mat img01 = imread("lena01.png");
	Mat img10 = imread("lena10.png");
	Mat img11 = imread("lena11.png");
	if (img00.empty() || img01.empty() || img10.empty() || img11.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	//顯示4個子影像
	imshow("img00", img00);
	imshow("img01", img01);
	imshow("img10", img10);
	imshow("img11", img11);

	//影像連接
	Mat img, img0, img1;
	//影像橫向連接
	hconcat(img00, img01, img0);
	hconcat(img10, img11, img1);
	//橫向連接結果再進行豎向連接
	vconcat(img0, img1, img);

	//顯示連接影像的結果
	imshow("img0", img0);
	imshow("img1", img1);
	imshow("img", img);
	waitKey(0);
	return 0;
}

3.3.2 影像尺寸變換

resize()

代碼清單3-28 影像縮放

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

using namespace std;
using namespace cv;

int main()
{
	Mat gray = imread("lena.png", IMREAD_GRAYSCALE);
	if (gray.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	Mat smallImg, bigImg0, bigImg1, bigImg2;
	resize(gray, smallImg, Size(15, 15), 0, 0, INTER_AREA);  //先將影像縮小
	resize(smallImg, bigImg0, Size(30, 30), 0, 0, INTER_NEAREST);  //最近鄰差值
	resize(smallImg, bigImg1, Size(30, 30), 0, 0, INTER_LINEAR);  //雙線性差值
	resize(smallImg, bigImg2, Size(30, 30), 0, 0, INTER_CUBIC);  //雙三次差值
	namedWindow("smallImg", WINDOW_NORMAL);  //影像尺寸太小,一定要設定可以調節視窗大小標志
	imshow("smallImg", smallImg);
	namedWindow("bigImg0", WINDOW_NORMAL);
	imshow("bigImg0", bigImg0);
	namedWindow("bigImg1", WINDOW_NORMAL);
	imshow("bigImg1", bigImg1);
	namedWindow("bigImg2", WINDOW_NORMAL);
	imshow("bigImg2", bigImg2);
	waitKey(0);
	return 0;
}

3.3.3 影像翻轉變換

flip()

代碼清單3-29 影像翻轉

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

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	Mat img_x, img_y, img_xy;
	flip(img, img_x, 0);  //沿x軸對稱
	flip(img, img_y, 1);  //沿y軸對稱
	flip(img, img_xy, -1);  //先x軸對稱,再y軸對稱
	imshow("img", img);
	imshow("img_x", img_x);
	imshow("img_y", img_y);
	imshow("img_xy", img_xy);
	waitKey(0);
	return 0;
}

3.3.4 影像放射變換

getRotationMatrix2D()

warpAffine()

getAffineTransform()

代碼清單3-34 影像旋轉與放射變換

#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	Mat rotation0, rotation1, img_warp0, img_warp1;
	double angle = 30;  //設定影像旋轉的角度
	Size dst_size(img.rows, img.cols);  //設定輸出影像的尺寸
	Point2f center(img.rows / 2.0, img.cols / 2.0);  //設定影像的旋轉中心
	rotation0 = getRotationMatrix2D(center, angle, 1);  //計算放射變換矩陣
	warpAffine(img, img_warp0, rotation0, dst_size);  //進行仿射變換
	imshow("img_warp0", img_warp0);
	//根據定義的三個點進行仿射變換
	Point2f src_points[3];
	Point2f dst_points[3];
	src_points[0] = Point2f(0, 0);  //原始影像中的三個點
	src_points[1] = Point2f(0, (float)(img.cols - 1));
	src_points[2] = Point2f((float)(img.rows - 1), (float)(img.cols - 1));
	dst_points[0] = Point2f((float)(img.rows)*0.11, (float)(img.cols)*0.20);  //放射變換后影像中的三個點
	dst_points[1] = Point2f((float)(img.rows)*0.15, (float)(img.cols)*0.70);
	dst_points[2] = Point2f((float)(img.rows)*0.81, (float)(img.cols)*0.85);
	rotation1 = getAffineTransform(src_points, dst_points);  //根據對應點求取仿射變換矩陣
	warpAffine(img, img_warp1, rotation1, dst_size);  //進行仿射變換
	imshow("img_warp1", img_warp1);
	waitKey(0);
	return 0;
}

3.3.5 影像透視變換

getPerspectiveTransform()

warpPerspective()

代碼清單3-37 二維碼影像透視變換

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

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("noobcvqr.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	Point2f src_points[4];
	Point2f dst_points[4];
	//通過Image Watch查看的二維碼四個角點坐標
	src_points[0] = Point2f(94.0, 374.0);
	src_points[1] = Point2f(507.0, 380.0);
	src_points[2] = Point2f(1.0, 623.0);
	src_points[3] = Point2f(627.0, 627.0);
	//期望透視變換后二維碼四個角點的坐標
	dst_points[0] = Point2f(0.0, 0.0);
	dst_points[1] = Point2f(627.0, 0.0);
	dst_points[2] = Point2f(0.0, 627.0);
	dst_points[3] = Point2f(627.0, 627.0);
	Mat rotation, img_warp;
	rotation = getPerspectiveTransform(src_points, dst_points);  //計算透視變換矩陣
	warpPerspective(img, img_warp, rotation, img.size());  //透視變換投影
	imshow("img", img);
	imshow("img_warp", img_warp);
	waitKey(0);
	return 0;
}

3.3.6 極坐標變換

warpPolar()

代碼清單3-39 影像極坐標變換

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

using namespace std;
using namespace cv;

int main()
{
	Mat img = imread("dial.png");
	if (!img.data)
	{
		cout << "請檢查影像檔案名稱是否輸入正確" << endl;
		return -1;
	}

	Mat img1, img2;
	Point2f center = Point2f(img.cols / 2, img.rows/2);  //極坐標在影像中的原點
	//正極坐標變換
	warpPolar(img, img1, Size(300,600), center, center.x, INTER_LINEAR + WARP_POLAR_LINEAR);
	//逆極坐標變換
	warpPolar(img1, img2, Size(img.rows,img.cols), center, center.x, INTER_LINEAR + WARP_POLAR_LINEAR + WARP_INVERSE_MAP);

	imshow("原表盤圖", img);
	imshow("表盤極坐標變換結果", img1); 
	imshow("逆變換結果", img2);
	waitKey(0);
	return 0;
}

3.4 在影像上繪制幾何圖形

3.4.1 繪制圓形

circle()

3.4.2 繪制直線

line()

3.4.3 繪制橢圓

ellipse()

ellipse2Poly()

3.4.4 繪制多邊形

rectangle()

fillPoly()

3.4.5 文字生成

putText()

代碼清單3-47 繪制基本幾何圖形

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

using namespace cv;
using namespace std;

int main()
{
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);  //生成一個黑色影像用于繪制幾何圖形
	//繪制圓形
	circle(img, Point(50, 50), 25, Scalar(255, 255, 255), -1);  //繪制一個實心圓
	circle(img, Point(100, 50), 20, Scalar(255, 255, 255), 4);  //繪制一個空心圓
	//繪制直線
	line(img, Point(100, 100), Point(200, 100), Scalar(255, 255, 255), 2, LINE_4,0);  //繪制一條直線
	//繪制橢圓
	ellipse(img, Point(300, 255), Size(100, 70), 0, 0, 100, Scalar(255, 255, 255), -1);  //繪制實心橢圓的一部分
	ellipse(img, RotatedRect(Point2f(150, 100), Size2f(30, 20), 0), Scalar(0, 0, 255), 2);  //繪制一個空心橢圓
	vector<Point> points;
	ellipse2Poly(Point(200, 400), Size(100, 70),0,0,360,2,points);  //用一些點來近似一個橢圓
	for (int i = 0; i < points.size()-1; i++)  //用直線把這個橢圓畫出來
	{
		if (i==points.size()-1)
		{
			line(img, points[0], points[i], Scalar(255, 255, 255), 2);  //橢圓中后于一個點與第一個點連線
			break;
		}
		line(img, points[i], points[i+1], Scalar(255, 255, 255), 2);  //當前點與后一個點連線
	}
	//繪制矩形
	rectangle(img, Point(50, 400), Point(100, 450), Scalar(125, 125, 125), -1);  
	rectangle(img, Rect(400,450,60,50), Scalar(0, 125, 125), 2);
	//繪制多邊形
	Point pp[2][6];
	pp[0][0] = Point(72, 200);
	pp[0][1] = Point(142, 204);
	pp[0][2] = Point(226, 263);
	pp[0][3] = Point(172, 310);
	pp[0][4] = Point(117, 319);
	pp[0][5] = Point(15, 260);
	pp[1][0] = Point(359, 339);
	pp[1][1] = Point(447, 351);
	pp[1][2] = Point(504, 349);
	pp[1][3] = Point(484, 433);
	pp[1][4] = Point(418, 449);
	pp[1][5] = Point(354, 402);
	Point pp2[5];
	pp2[0] = Point(350, 83);
	pp2[1] = Point(463, 90);
	pp2[2] = Point(500, 171);
	pp2[3] = Point(421, 194);
	pp2[4] = Point(338, 141);
	const Point* pts[3] = { pp[0],pp[1],pp2 };  //pts變數的生成
	int npts[] = { 6,6,5 };  //頂點個數陣列的生成
	fillPoly(img, pts, npts, 3, Scalar(125, 125, 125),8);  //繪制3個多邊形
	//生成文字
	putText(img, "Learn OpenCV 4",Point(100, 400), 2, 1, Scalar(255, 255, 255));
	imshow("", img);
	waitKey(0);
	return 0;
}

3.5 感興趣區域

Rect資料結構和Rang資料結構

copyTo()

代碼清單3-50 截圖、深淺拷貝驗證程式

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

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("lena.png");
	Mat noobcv = imread("noobcv.jpg");
	if (img.empty() || noobcv.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat ROI1, ROI2, ROI2_copy, mask, img2, img_copy, img_copy2;
	resize(noobcv, mask, Size(200, 200));
	img2 = img;  //淺拷貝
				 //深拷貝的兩種方式
	img.copyTo(img_copy2);
	copyTo(img, img_copy, img);
	//兩種在圖中截取ROI區域的方式
	Rect rect(206, 206, 200, 200);  //定義ROI區域
	ROI1 = img(rect);  //截圖
	ROI2 = img(Range(300, 500), Range(300, 500));  //第二種截圖方式
	img(Range(300, 500), Range(300, 500)).copyTo(ROI2_copy);  //深拷貝
	mask.copyTo(ROI1);  //在影像中加入部分影像
	imshow("加入noobcv后影像", img);
	imshow("ROI對ROI2的影響", ROI2);
	imshow("深拷貝的ROI2_copy", ROI2_copy);
	circle(img, Point(300, 300), 20, Scalar(0, 0, 255), -1);  //繪制一個圓形
	imshow("淺拷貝的img2", img2);
	imshow("深拷貝的img_copy", img_copy);
	imshow("深拷貝的img_copy2", img_copy2);
	imshow("畫圓對ROI1的影響", ROI1);
	waitKey(0);
	return 0;
}

3.6 影像“金字塔”

3.6.1 高斯“金字塔”

pyrDown()

3.6.2 高斯“金字塔”

pyrUp()

代碼清單3-53 構建 高斯“金字塔” 和 高斯“金字塔”

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

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("lena.png");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	vector<Mat> Gauss, Lap;  //高斯金字塔和拉普拉斯金字塔
	int level = 3;  //高斯金字塔下采樣次數
	Gauss.push_back(img);  //將原圖作為高斯金字塔的第0層
						   //構建高斯金字塔
	for (int i = 0; i < level; i++)
	{
		Mat gauss;
		pyrDown(Gauss[i], gauss);  //下采樣
		Gauss.push_back(gauss);
	}
	//構建拉普拉斯金字塔
	for (int i = Gauss.size() - 1; i > 0; i--)
	{
		Mat lap, upGauss;
		if (i == Gauss.size() - 1)  //如果是高斯金字塔中的最上面一層影像
		{
			Mat down;
			pyrDown(Gauss[i], down);  //上采樣
			pyrUp(down, upGauss);
			lap = Gauss[i] - upGauss;
			Lap.push_back(lap);
		}
		pyrUp(Gauss[i], upGauss);
		lap = Gauss[i - 1] - upGauss;
		Lap.push_back(lap);
	}
	//查看兩個金字塔中的影像
	for (int i = 0; i < Gauss.size(); i++)
	{
		string name = to_string(i);
		imshow("G" + name, Gauss[i]);
		imshow("L" + name, Lap[i]);
	}
	waitKey(0);
	return 0;
}

3.7 視窗互動操作

3.7.1 影像視窗滑動條

createTrackbar()

代碼清單3-55 在影像中創建滑動條改變影像亮度

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

using namespace std;
using namespace cv;

//為了能在被調函式中使用,所以設定成全域的
int value;
void callBack(int, void*);  //滑動潭訓呼函式
Mat img1, img2;

int main()
{
	img1 = imread("lena.png");
	if (!img1.data)
	{
		cout << "請確認是否輸入正確的影像檔案" << endl;
		return -1;
	}
	namedWindow("滑動條改變影像亮度");
	imshow("滑動條改變影像亮度", img1);
	value = 100;  //滑動條創建時的初值
				  //創建滑動條
	createTrackbar("亮度值百分比", "滑動條改變影像亮度", &value, 600, callBack, 0);
	waitKey();
}

static void callBack(int, void*)
{
	float a = value / 100.0;
	img2 = img1 * a;
	imshow("滑動條改變影像亮度", img2);
}

3.7.2 滑鼠相應

setMouseCallback()

MouseCallback型別

代碼清單3-58 繪制滑鼠移動軌跡

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

using namespace std;
using namespace cv;

Mat img, imgPoint; //全域的影像
Point prePoint; //前一時刻滑鼠的坐標,用于繪制直線
void mouse(int event, int x, int y, int flags, void*);

int main()
{
	img = imread("lena.png");
	if (!img.data)
		{
			cout << "請確認輸入影像名稱是否正確! " << endl;
			return -1;
		}
	img.copyTo(imgPoint);
	imshow("影像視窗 1", img);
	imshow("影像視窗 2", imgPoint);
	setMouseCallback("影像視窗 1", mouse, 0); //滑鼠影響
	waitKey(0);
	return 0;
	}

void mouse(int event, int x, int y, int flags, void*)
{
	if (event == EVENT_RBUTTONDOWN) //單擊右鍵
	{
		cout << "點擊滑鼠左鍵才可以繪制軌跡" << endl;
	}
	if (event == EVENT_LBUTTONDOWN) //單擊左鍵,輸出坐標
	{
		prePoint = Point(x, y);
		cout << "軌跡起始坐標" << prePoint << endl;
	}
	if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) //滑鼠按住左鍵移動第 3 章 影像基本操作
	{
	 //通過改變影像像素顯示滑鼠移動軌跡
		imgPoint.at<Vec3b>(y, x) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y, x - 1) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y, x + 1) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y + 1, x) = Vec3b(0, 0, 255);
		imgPoint.at<Vec3b>(y + 1, x) = Vec3b(0, 0, 255);
		imshow("影像視窗 2", imgPoint);
		
	    //通過繪制直線顯示滑鼠移動軌跡
		Point pt(x, y);
		line(img, prePoint, pt, Scalar(0, 0, 255), 2, 5, 0);
		prePoint = pt;
		imshow("影像視窗 1", img);
	}
}

第四章 影像直方圖與模板匹配

4.1 影像直方圖的繪制

calcHist()

cvRound()

代碼清單4-2 繪制影像直方圖

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

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("apple.jpg");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	//設定提取直方圖的相關變數
	Mat hist;  //用于存放直方圖計算結果
	const int channels[1] = { 0 };  //通道索引
	float inRanges[2] = { 0,255 };
	const float* ranges[1] = { inRanges };  //像素灰度值范圍
	const int bins[1] = { 256 };  //直方圖的維度,其實就是像素灰度值的最大值
	calcHist(&gray, 1, channels, Mat(), hist, 1, bins, ranges);  //計算影像直方圖
																//準備繪制直方圖
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	for (int i = 1; i <= hist.rows; i++)
	{
		rectangle(histImage, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(hist.at<float>(i - 1) / 15)),
			Scalar(255, 255, 255), -1);
	}
	namedWindow("histImage", WINDOW_AUTOSIZE);
	imshow("histImage", histImage);
	imshow("gray", gray);
	waitKey(0);
	return 0;
}

4.2 直方圖操作

4.2.1 直方圖歸一化

normalize()

代碼清單4-4 直方圖歸一化操作

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

using namespace cv;
using namespace std;

int main()
{
	system("color F0");  //更改輸出界面顏色
	vector<double> positiveData = { 2.0, 8.0, 10.0 };
	vector<double> normalized_L1, normalized_L2, normalized_Inf, normalized_L2SQR;
	//測驗不同歸一化方法
	normalize(positiveData, normalized_L1, 1.0, 0.0, NORM_L1);  //絕對值求和歸一化
	cout << "normalized_L1=[" << normalized_L1[0] << ", "
		<< normalized_L1[1] << ", " << normalized_L1[2] << "]" << endl;
	normalize(positiveData, normalized_L2, 1.0, 0.0, NORM_L2);  //模長歸一化
	cout << "normalized_L2=[" << normalized_L2[0] << ", "
		<< normalized_L2[1] << ", " << normalized_L2[2] << "]" << endl;
	normalize(positiveData, normalized_Inf, 1.0, 0.0, NORM_INF);  //最大值歸一化
	cout << "normalized_Inf=[" << normalized_Inf[0] << ", "
		<< normalized_Inf[1] << ", " << normalized_Inf[2] << "]" << endl;
	normalize(positiveData, normalized_L2SQR, 1.0, 0.0, NORM_MINMAX);  //偏移歸一化
	cout << "normalized_MINMAX=[" << normalized_L2SQR[0] << ", "
		<< normalized_L2SQR[1] << ", " << normalized_L2SQR[2] << "]" << endl;
	//將影像直方圖歸一化
	Mat img = imread("apple.jpg");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat gray, hist;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	const int channels[1] = { 0 };
	float inRanges[2] = { 0,255 };
	const float* ranges[1] = { inRanges };
	const int bins[1] = { 256 };
	calcHist(&gray, 1, channels, Mat(), hist, 1, bins, ranges);
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage_L1 = Mat::zeros(hist_h, hist_w, CV_8UC3);
	Mat histImage_Inf = Mat::zeros(hist_h, hist_w, CV_8UC3);
	Mat hist_L1, hist_Inf;
	normalize(hist, hist_L1, 1, 0, NORM_L1, -1, Mat());
	for (int i = 1; i <= hist_L1.rows; i++)
	{
		rectangle(histImage_L1, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(30 * hist_h*hist_L1.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	normalize(hist, hist_Inf, 1, 0, NORM_INF, -1, Mat());
	for (int i = 1; i <= hist_Inf.rows; i++)
	{
		rectangle(histImage_Inf, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(hist_h*hist_Inf.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	imshow("histImage_L1", histImage_L1);
	imshow("histImage_Inf", histImage_Inf);
	waitKey(0);
	return 0;
}

4.2.2 直方圖比較

compareHist()

代碼清單4-6 比較兩個直方圖的相似性

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

using namespace cv;
using namespace std;

void drawHist(Mat &hist, int type, string name)  //歸一化并繪制直方圖函式
{
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	normalize(hist, hist, 1, 0, type, -1, Mat());
	for (int i = 1; i <= hist.rows; i++)
	{
		rectangle(histImage, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(hist_h*hist.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	imshow(name, histImage);
}
//主函式
int main()
{
	system("color F0");  //更改輸出界面顏色
	Mat img = imread("apple.jpg");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat gray, hist, gray2, hist2, gray3, hist3;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	resize(gray, gray2, Size(), 0.5, 0.5);
	gray3 = imread("lena.png", IMREAD_GRAYSCALE);
	const int channels[1] = { 0 };
	float inRanges[2] = { 0,255 };
	const float* ranges[1] = { inRanges };
	const int bins[1] = { 256 };
	calcHist(&gray, 1, channels, Mat(), hist, 1, bins, ranges);
	calcHist(&gray2, 1, channels, Mat(), hist2, 1, bins, ranges);
	calcHist(&gray3, 1, channels, Mat(), hist3, 1, bins, ranges);
	drawHist(hist, NORM_INF, "hist");
	drawHist(hist2, NORM_INF, "hist2");
	drawHist(hist3, NORM_INF, "hist3");
	//原圖直方圖與原圖直方圖的相關系數
	double hist_hist = compareHist(hist, hist, HISTCMP_CORREL);
	cout << "apple_apple=" << hist_hist << endl;
	//原圖直方圖與縮小原圖直方圖的相關系數
	double hist_hist2 = compareHist(hist, hist2, HISTCMP_CORREL);
	cout << "apple_apple256=" << hist_hist2 << endl;
	//兩張不同影像直方圖相關系數
	double hist_hist3 = compareHist(hist, hist3, HISTCMP_CORREL);
	cout << "apple_lena=" << hist_hist3 << endl;
	waitKey(0);
	return 0;
}

4.3 直方圖應用

4.3.1 直方圖均衡化

equalizeHist()

代碼清單4-8 直方圖均衡化實作

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

using namespace cv;
using namespace std;

void drawHist(Mat &hist, int type, string name)  //歸一化并繪制直方圖函式
{
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	normalize(hist, hist, 1, 0, type, -1, Mat());
	for (int i = 1; i <= hist.rows; i++)
	{
		rectangle(histImage, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(hist_h*hist.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	imshow(name, histImage);
}
//主函式
int main()
{
	Mat img = imread("gearwheel.jpg");
	if (img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat gray, hist, hist2;
	cvtColor(img, gray, COLOR_BGR2GRAY);
	Mat equalImg;
	equalizeHist(gray, equalImg);  //將影像直方圖均衡化
	const int channels[1] = { 0 };
	float inRanges[2] = { 0,255 };
	const float* ranges[1] = { inRanges };
	const int bins[1] = { 256 };
	calcHist(&gray, 1, channels, Mat(), hist, 1, bins, ranges);
	calcHist(&equalImg, 1, channels, Mat(), hist2, 1, bins, ranges);
	drawHist(hist, NORM_INF, "hist");
	drawHist(hist2, NORM_INF, "hist2");
	imshow("原圖", gray);
	imshow("均衡化后的影像", equalImg);
	waitKey(0);
	return 0;
}

4.3.2 直方圖匹配

代碼清單4-9 影像直方圖匹配

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

using namespace cv;
using namespace std;

void drawHist(Mat &hist, int type, string name)  //歸一化并繪制直方圖函式
{
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	normalize(hist, hist, 1, 0, type, -1, Mat());
	for (int i = 1; i <= hist.rows; i++)
	{
		rectangle(histImage, Point(width*(i - 1), hist_h - 1),
			Point(width*i - 1, hist_h - cvRound(20 * hist_h*hist.at<float>(i - 1)) - 1),
			Scalar(255, 255, 255), -1);
	}
	imshow(name, histImage);
}
//主函式
int main()
{
	Mat img1 = imread("histMatch.png");
	Mat img2 = imread("equalLena.png");
	if (img1.empty() || img2.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat hist1, hist2;
	//計算兩張影像直方圖
	const int channels[1] = { 0 };
	float inRanges[2] = { 0,255 };
	const float* ranges[1] = { inRanges };
	const int bins[1] = { 256 };
	calcHist(&img1, 1, channels, Mat(), hist1, 1, bins, ranges);
	calcHist(&img2, 1, channels, Mat(), hist2, 1, bins, ranges);
	//歸一化兩張影像的直方圖
	drawHist(hist1, NORM_L1, "hist1");
	drawHist(hist2, NORM_L1, "hist2");
	//計算兩張影像直方圖的累積概率
	float hist1_cdf[256] = { hist1.at<float>(0) };
	float hist2_cdf[256] = { hist2.at<float>(0) };
	for (int i = 1; i < 256; i++)
	{
		hist1_cdf[i] = hist1_cdf[i - 1] + hist1.at<float>(i);
		hist2_cdf[i] = hist2_cdf[i - 1] + hist2.at<float>(i);

	}
	//構建累積概率誤差矩陣
	float diff_cdf[256][256];
	for (int i = 0; i < 256; i++)
	{
		for (int j = 0; j < 256; j++)
		{
			diff_cdf[i][j] = fabs(hist1_cdf[i] - hist2_cdf[j]);
		}
	}

	//生成LUT映射表
	Mat lut(1, 256, CV_8U);
	for (int i = 0; i < 256; i++)
	{
		// 查找源灰度級為i的映射灰度
		// 和i的累積概率差值最小的規定化灰度
		float min = diff_cdf[i][0];
		int index = 0;
		//尋找累積概率誤差矩陣中每一行中的最小值
		for (int j = 1; j < 256; j++)
		{
			if (min > diff_cdf[i][j])
			{
				min = diff_cdf[i][j];
				index = j;
			}
		}
		lut.at<uchar>(i) = (uchar)index;
	}
	Mat result, hist3;
	LUT(img1, lut, result);
	imshow("待匹配影像", img1);
	imshow("匹配的模板影像", img2);
	imshow("直方圖匹配結果", result);
	calcHist(&result, 1, channels, Mat(), hist3, 1, bins, ranges);
	drawHist(hist3, NORM_L1, "hist3");  //繪制匹配后的影像直方圖
	waitKey(0);
	return 0;
}

4.3.3 直方圖反向投影

calcBackProject()

代碼清單4-11 影像直方圖反向攝影

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

using namespace cv;
using namespace std;

void drawHist(Mat &hist, int type, string name)  //歸一化并繪制直方圖函式
{
	int hist_w = 512;
	int hist_h = 400;
	int width = 2;
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	normalize(hist, hist, 255, 0, type, -1, Mat());
	namedWindow(name, WINDOW_NORMAL);
	imshow(name, hist);
}
//主函式
int main()
{
	Mat img = imread("apple.jpg");
	Mat sub_img = imread("sub_apple.jpg");
	Mat img_HSV, sub_HSV, hist, hist2;
	if (img.empty() || sub_img.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}

	imshow("img", img);
	imshow("sub_img", sub_img);
	//轉成HSV空間,提取S、V兩個通道
	cvtColor(img, img_HSV, COLOR_BGR2HSV);
	cvtColor(sub_img, sub_HSV, COLOR_BGR2HSV);
	int h_bins = 32; int s_bins = 32;
	int histSize[] = { h_bins, s_bins };
	//H通道值的范圍由0到179
	float h_ranges[] = { 0, 180 };
	//S通道值的范圍由0到255
	float s_ranges[] = { 0, 256 };
	const float* ranges[] = { h_ranges, s_ranges };  //每個通道的范圍
	int channels[] = { 0, 1 };  //統計的通道索引
								//繪制H-S二維直方圖
	calcHist(&sub_HSV, 1, channels, Mat(), hist, 2, histSize, ranges, true, false);
	drawHist(hist, NORM_INF, "hist");  //直方圖歸一化并繪制直方圖
	Mat backproj;
	calcBackProject(&img_HSV, 1, channels, hist, backproj, ranges, 1.0);  //直方圖反向投影
	imshow("反向投影后結果", backproj);
	waitKey(0);
	return 0;
}

4.4 影像的模板匹配

matchTemplate()

代碼清單4-13 影像的模板匹配

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

using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("lena.png");
	Mat temp = imread("lena_face.png");
	if (img.empty() || temp.empty())
	{
		cout << "請確認影像檔案名稱是否正確" << endl;
		return -1;
	}
	Mat result;
	matchTemplate(img, temp, result, TM_CCOEFF_NORMED);//模板匹配
	double maxVal, minVal;
	Point minLoc, maxLoc;
	//尋找匹配結果中的最大值和最小值以及坐標位置
	minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);
	//繪制最佳匹配區域
	rectangle(img, cv::Rect(maxLoc.x, maxLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2);
	imshow("原圖", img);
	imshow("模板影像", temp);
	imshow("result", result);
	waitKey(0);
	return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291957.html

標籤:其他

上一篇:計算機視覺課程第二講-OpenCV4讀取、顯示、保存-視頻&攝像頭資料

下一篇:計算機視覺PyTorch實作影像著色 - (二)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more