12.OpenCV—基礎入門

01讀取圖像?

02創建空白圖像

03保存圖像

04更改圖像亮度

05更改圖像對比度

06灰度直方圖均衡

07彩色直方圖均衡

08五種濾波方式

09形態學操作

10仿射變換

11角度+縮放仿射變換

12透視變換

13坐標映射

14模板匹配

15多模板匹配

16查找輪廓線

17輪廓線匹配

17繪制基本圖形





.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();void demo01();//01顯示圖像void demo02();//02創建空白圖像void demo03();//03保存圖像void demo04();//04更改圖像亮度void demo05();//05更改圖像對比度void demo06();//06灰度直方圖均衡void demo07();//07彩色直方圖均衡void demo08();//08五種過濾圖像void demo09(); //09形態學操作void demo10();//10仿射平移變換(3點法。2*3矩陣)void demo11();//11角度+縮放仿射變換void demo12();//12透視變換(4點法 3*3矩陣)void demo13(); //13坐標映射(一一對應)void demo14(); //14模板匹配void demo15();//15多模板匹配void demo16();//16查找輪廓線void drawRectangle(int event, int x, int y, int flags, void* userdata);private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();//輪廓線匹配void on_pushButton_3_clicked();//繪制圖形private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QMessageBox>
#include <QCoreApplication>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
#include <qdebug.h>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{//demo01();//01顯示圖像//demo02();//02創建空白圖像//demo03();//03保存圖像//demo04();//04更改圖像亮度//demo05();//05更改圖像對比度//demo06();//06灰度直方圖均衡//demo07();//07彩色直方圖均衡//demo08();//08五種過濾圖像//demo09();//09形態學操作//demo10();//10仿射變換//demo11();//11角度+縮放仿射變換//demo12();//12透視變換//demo13(); //13坐標映射demo14(); //14模板匹配//demo15();//15多模板匹配//demo16();//16查找輪廓線}//01顯示圖像
void MainWindow::demo01()
{/*讀取圖像Mat imread(const String&filename, int flags = IMREAD_COLOR)文件名 - 始終支持 JPEG、JPG、BMP、PNG、TIFF 和 TIF 圖像文件類型。支持其他映像文件類型,具體取決于您的平臺和安裝的編解碼器。flags - 標志參數有幾個可能的值默認的IMREAD_COLOR參數。IMREAD_UNCHANGED - 圖像將按原樣加載。如果要在輸入圖像中獲取 alpha 通道(如果可用),則必須使用此標志。IMREAD_GRAYSCALE - 圖像將作為灰度圖像加載(即 - 單通道圖像,黑白圖像)IMREAD_COLOR - 圖像將作為BGR圖像加載(即 - 3通道圖像,彩色圖像)*/Mat image = imread("./image/1.png",IMREAD_COLOR);if(image.empty()){//報錯QMessageBox::warning(this,QString::fromLocal8Bit("警告"),QString::fromLocal8Bit("操作錯誤,某文件不存在"));return;}else{//定義一個窗口名稱String winName = "lena圖像";/*創建一個窗口用于顯示圖像winname - 窗口的名稱。該名稱將顯示在新創建的窗口的標題欄中。此名稱也是此窗口的標識符,它將在以后的 OpenCV 函數調用中用于標識窗口。標志 - 確定窗口的大小。在上面的程序中,我沒有向此參數傳遞任何值,因此將使用默認WINDOW_AUTOSIZE參數。WINDOW_AUTOSIZE - 用戶無法調整窗口大小。圖像將以其原始大小顯示。WINDOW_NORMAL-用戶可以調整窗口大小。*/namedWindow(winName,WINDOW_AUTOSIZE);//把圖像放在這個窗口上面imshow(winName,image);//等待輸入任意按鍵關閉窗口,如果輸入大于0的數值則,以毫秒為單位進行倒計時處理waitKey(0);destroyWindow(winName);}
}//02創建空白圖像
void MainWindow::demo02()
{/*這是 Mat 類中可用的眾多構造函數之一。它創建一個高 600 像素、寬800像素的圖像。為圖像中的每個像素分配 24 位。24 位將由三個無符號 8位整數組成,分別代表藍色、綠色和紅色平面。三個整數的值應介于 0 到 255 之間。然后,此構造函數使用 3 個無符號整數(100、250、30)初始化創建圖像的每個像素。因此,它初始化藍色通道為 100,綠色通道初始化為 250,紅色通道初始化為 30。由于綠色通道的值明顯大于其他通道的值,因此輸出圖像為綠色。Mat:**(int rows, int cols, int type, const Scalar& s)*/Mat image(600,800,CV_8UC3,Scalar(200,31,120));String WindowName = "空白圖像";namedWindow(WindowName);imshow(WindowName,image);waitKey(0);destroyWindow(WindowName);}//03保存圖像
void MainWindow::demo03()
{//讀圖圖像Mat image = imread("./image/1.png",IMREAD_COLOR);if(image.empty()){QMessageBox::warning(this,"警告","圖像不存在");return;}/*保存讀取的圖像bool imwrite( const String& filename, InputArray img, const std::vector& params = std::vector())此函數將給定的 img 對象寫入指定的文件。成功后,此函數將返回 true,否則將返回 false。1.文件名 - 輸出圖像的文件名。請注意,文件名的擴展名將用于確定圖像格式。(例如 - 如果文件名是 MyImage.jpg,則將寫入 JPEG 圖像。如果文件名為 MyImage.png,則將寫入 PNG 圖像。始終支持 JPEG、JPG、BMP、PNG、TIFF 和 TIF 擴展名。2.img - 要保存的圖像對象。請注意,此圖像對象應具有以下屬性。2.1.圖像對象的位深度應為 8 位有符號或 16 位無符號。2.2.圖像的通道數應為 1 或 3。對于 3 通道圖像對象,應存在 BGR 通道順序。2.3.如果圖像對象的位深度或通道順序與上述規范不同,則可以使用 Mat::convertTo 和 cv::cvtColor 函數來轉換圖像。3.參數 - 這是一個可選參數。*/bool isScussess = imwrite("./image/2.png",image);//判斷是否保存成功if(isScussess == false){QMessageBox::warning(this,"警告","圖像保存失敗");return;}//顯示一開始讀取并保存的圖像String windowName = "Save image";namedWindow(windowName);imshow(windowName,image);waitKey(0);destroyWindow(windowName);}//04更改圖像亮度
void MainWindow::demo04()
{//讀圖Mat image = imread("./image/1.png",IMREAD_COLOR);if(image.empty()){QMessageBox::warning(this,"警告","圖像不存在");return;}/*void Mat::convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const此函數將每個像素值轉換為目標數據類型,并按照以下公式更改值。pixel_value_of_output_image(x, y) = pixel_value_of_input_image(x, y) * alpha + beta;m - 輸出圖像。如果需要,將重新分配此數據結構。rtype - 輸出圖像的類型。如果 rtype 為負值,則輸出圖像的類型將與輸入圖像的類型相同。alpha - 在分配給輸出圖像之前,輸入圖像中的每個像素將乘以此數字。beta - 此值將添加到輸入圖像中的每個像素并分配給輸出圖像。*///對圖像進行亮度增加Mat imageAdd;image.convertTo(imageAdd,-1,1,100);//亮度增加100//對圖像進行亮度減少Mat imageDark;image.convertTo(imageDark,-1,1,-100);//亮度減少100//定義窗口名字String imageOringWind = "原圖像";String imageAddWind = "亮度增加50";String imageDarkWind = "亮度減少";//創建窗口namedWindow(imageOringWind,WINDOW_AUTOSIZE);namedWindow(imageAddWind,WINDOW_AUTOSIZE);namedWindow(imageDarkWind,WINDOW_AUTOSIZE);//窗口顯示圖像imshow(imageOringWind,image);imshow(imageAddWind,imageAdd);imshow(imageDarkWind,imageDark);//等待關閉窗口waitKey(0);destroyWindow(imageOringWind);destroyWindow(imageAddWind);destroyWindow(imageDarkWind);
}//05更改圖像對比度
void MainWindow::demo05()
{//讀圖Mat image = imread("./image/1.png",IMREAD_COLOR);if(image.empty()){QMessageBox::warning(this,"警告","圖像不存在");return;}//增加圖像對比度(參考亮度)Mat imageAdd;image.convertTo(imageAdd,-1,4,0);//減少圖像對比度Mat imageReduce;image.convertTo(imageReduce,-1,0.4,0);//定義窗口名字String imageOringWind = "原圖像";String imageAddWind = "增加圖像";String imageReduceWind = "減少圖像";//創建窗口namedWindow(imageOringWind,WINDOW_AUTOSIZE);namedWindow(imageAddWind,WINDOW_AUTOSIZE);namedWindow(imageReduceWind,WINDOW_AUTOSIZE);//圖像顯示imshow(imageOringWind,image);imshow(imageAddWind,imageAdd);imshow(imageReduceWind,imageReduce);//等待關閉窗口waitKey(0);destroyWindow(imageOringWind);destroyWindow(imageAddWind);destroyWindow(imageReduceWind);}//06灰度直方圖均衡
void MainWindow::demo06()
{//讀圖Mat image = imread("./image/4.png",IMREAD_COLOR);if(image.empty()){QMessageBox::warning(this,"警告","圖像不存在");return;}//改變圖像顏色變為灰度圖(如果一開始讀取的就是灰度圖,則不需要轉化)cvtColor(image,image,COLOR_BGR2GRAY);//進行灰度直方圖均衡化Mat hist_equalized_image;equalizeHist(image,hist_equalized_image);//定義窗口名字String imageWind = "原圖像";String equlizedWind = "均衡化之后";//創建窗口namedWindow(imageWind,WINDOW_AUTOSIZE);namedWindow(equlizedWind,WINDOW_AUTOSIZE);//顯示圖像imshow(imageWind,image);imshow(equlizedWind,hist_equalized_image);//等待關閉窗口waitKey(0);destroyWindow(imageWind);destroyWindow(equlizedWind);
}//07彩色直方圖均衡
void MainWindow::demo07()
{// Read the image fileMat image = imread("./image/4.png");// Check for failureif (image.empty()){QMessageBox::warning(this,"警告","圖像不存在");return ;}//把圖像從BGR色彩空間轉換為YCrCb色彩空間/* 直方圖均衡只能處理強度信息,不能處理帶顏色的通道加載的圖像位于 BGR 色彩空間中。此顏色空間的 3 個通道(藍色、綠色和紅色)中的任何一個都無法處理以均衡直方圖,因為所有通道都包含顏色信息。因此,加載的圖像應轉換為 YCrCb 色彩空間。在此顏色空間中,Y 通道僅包含強度信息,而 Cr 和 Cb 通道包含顏色信息。因此,只需要處理Y通道即可均衡直方圖。*/Mat hist_equalized_image;cvtColor(image, hist_equalized_image, COLOR_BGR2YCrCb);//轉化圖像/*把轉換好的色彩空間對象分割處對應通道分別是Y,Cr,Cb并把結果存儲到vector集合中上述 OpenCV 函數將 3 通道圖像拆分為 3 個單獨的矩陣。每個矩陣都被推送到 std::vector。vec_channels[0] 包含 Y 通道,vec_channels[1] 包含 Cr 通道,vec_channels[2] 包含 Cb 通道。*/vector<Mat> vec_channels;split(hist_equalized_image, vec_channels);//分離三通道//把拆分出來的Y通道進行直方圖均衡equalizeHist(vec_channels[0], vec_channels[0]);//合并處理好的3通道數據合并到YCrCb的色彩空間中merge(vec_channels, hist_equalized_image);//合并三通道//把YCrCb的色彩空間圖像轉換到BGR顏色空間cvtColor(hist_equalized_image, hist_equalized_image, COLOR_YCrCb2BGR);//Define the names of windowsString windowNameOfOriginalImage = "原圖";String windowNameOfHistogramEqualized = "處理后";// Create windows with the above namesnamedWindow(windowNameOfOriginalImage, WINDOW_NORMAL);namedWindow(windowNameOfHistogramEqualized, WINDOW_NORMAL);// Show images inside the created windows.imshow(windowNameOfOriginalImage, image);imshow(windowNameOfHistogramEqualized, hist_equalized_image);waitKey(0); // Wait for any keystroke in one of the windowsdestroyAllWindows(); //Destroy all open windows
}//08五種過濾圖像
void MainWindow::demo08()
{//讀取圖像Mat image = imread("./image/1.png",IMREAD_COLOR);if(image.empty()){QMessageBox::warning(this,"警告","圖像不存在");return;}//定義窗口名字String  imageOriginalWind = "原圖";String  imageBoxFilterWind = "方框濾波";String  imageBlurWind = "均值濾波";String  imageGaussianWind = "高斯濾波";String  imageMedianWind = "中值濾波";String  imageBilateraWind = "雙邊濾波";//創建窗口namedWindow(imageOriginalWind);namedWindow(imageBoxFilterWind);namedWindow(imageBlurWind);namedWindow(imageGaussianWind);namedWindow(imageMedianWind);namedWindow(imageBilateraWind);//顯示原圖imshow(imageOriginalWind,image);//1.方框濾波處理 –> boxFilter函數來實現 –>線性濾波//  方框濾波boxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor = Point(-1,-1),bool normalize = true,int borderType = BORDER_DEFAULT )//        src:輸入圖像//        dst:輸出圖像//        ddepth:輸入圖像的深度,-1 代表使用原圖深度//        ksize: 濾波內核的大小。一般這樣寫Size(w, h)來表示內核的大小,Size(10, 10)就表示 10x10 的核大小//        anchor = Point(-1,-1) :表示錨點(即被平滑的那個點),注意他有默認值Point(-1,-1) 如果這個點坐標是負值的話,就表示取核的中心為錨點,所以默認值Point(-1,-1)表示這個錨點在核的中心。//        normalize = true:默認值為true,一個標識符,表示內核是否被其區域歸一化(normalized)了//        borderType = BORDER_DEFAULT:用于推斷圖像外部像素的某種邊界模式。有默認值BORDER_DEFAULT,我們一般不去管它。Mat imageBoxFilter;boxFilter(image,imageBoxFilter,image.depth(),Size(15,15));imshow(imageBoxFilterWind,imageBoxFilter);//2.均值濾波(鄰域平均濾波)–> blur函數 –>線性濾波//  均值濾波blur( InputArray src,OutputArray dst, Size ksize, Point anchor = Point(-1,-1),int borderType = BORDER_DEFAULT)//        src:輸入圖像 。//        dst:輸出圖像 。//        ksize:內核大小 ,一般用 Size(w,h),w 為寬度,h 為深度。//        anchor:被平滑的點,表示取 內核中心 ,默認值 Point(-1,-1)。//        boderType:推斷圖像外部像素的某種邊界模式。默認值 BORDER_DEFAULTMat imageBlur;blur(image,imageBlur,Size(15,15));imshow(imageBlurWind,imageBlur);//3.高斯濾波–>GaussianBlur函數 –>線性濾波//  高斯濾波GaussianBlur( InputArray src, OutputArray dst, Size ksize,double sigmaX, double sigmaY = 0,int borderType = BORDER_DEFAULT )//        src:輸入圖像 。//        dst:輸出圖像 。//        ksize:ksize.width 和 ksize.height 可以不同,但他們都必須為正數和奇數,或者為0,可由 sigma 計算而來//        sigmaX:高斯核函數在 X 方向的的標準差//        sigmaY:高斯核函數在 Y 方向的的標準差//        若 sigmaY 為零,就將它設為 sigmaX;若 sigmaX 和 sigmaY 都是0,那么就由 ksize.width 和 ksize.height 計算出來Mat imageGauss;GaussianBlur(image,imageGauss,Size(15,15),0);imshow(imageGaussianWind,imageGauss);//4.中值濾波–>medianBlur函數 –>非線性濾波//  中值濾波medianBlur(InputArray src,OutputArray dst,int ksize)//        src:輸入圖像 。//        dst:輸出圖像 。//        ksize:孔徑的線性尺寸,這個參數必須是大于1 的奇數Mat imageMedian;medianBlur(image,imageMedian,9);imshow(imageMedianWind,imageMedian);//5.雙邊濾波–>bilateralFilter函數 –>非線性濾波//  雙邊濾波bilateralFilter(InputArray src,OutputArray dst, int d,  double sigmaColor,double sigmaSpace, int borderType=BORDER_DEFAULT)//        src: 輸入圖像,可以是Mat類型,圖像必須是8位或浮點型單通道、三通道的圖像。//        dst: 輸出圖像,和原圖像有相同的尺寸和類型。//        d: 表示在過濾過程中每個像素鄰域的直徑范圍。如果這個值是非正數,則函數會從第五個參數sigmaSpace計算該值。//        sigmaColor: 顏色空間過濾器的sigma值,這個參數的值月大,表明該像素鄰域內有月寬廣的顏色會被混合到一起,產生較大的半相等顏色區域。//        sigmaSpace: 坐標空間中濾波器的sigma值,如果該值較大,則意味著顏色相近的較遠的像素將相互影響,從而使更大的區域中足夠相似的顏色獲取相同的顏色。當d>0時,d指定了鄰域大小且與sigmaSpace五官,否則d正比于sigmaSpace.//        borderType=BORDER_DEFAULT: 用于推斷圖像外部像素的某種邊界模式,有默認值BORDER_DEFAULT.Mat imageBilatera;bilateralFilter(image, imageBilatera, 11, 21, 19);imshow(imageBilateraWind,imageBilatera);//等待關閉窗口waitKey(0);destroyAllWindows();}//09形態學操作
void MainWindow::demo09()
{/*
void morphologyEx(InputArray src,OutputArray dst,int op,InputArray kernel,Point anchor = Point(-1,-1),int iterations = 1,int borderType = BORDER_CONSTANT,const Scalar & borderValue = morphologyDefaultBorderValue()1.src:輸入圖像,圖像的通道數可以是任意的,但是圖像的數據類型必須是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。2.dst:形態學操作后的輸出圖像,與輸入圖像具有相同的尺寸和數據類型。3.op:形態學操作類型的標志,可以選擇的標志及含義在表6-6中給出。4.kernel:結構元素,可以自己生成,也可以用getStructuringElement()函數生成。5.anchor:中心點在結構元素中的位置,默認參數為結構元素的幾何中心點6.iterations:處理的次數7.borderType:像素外推法選擇標志,取值范圍在表3-5中給出。默認參數為BORDER_DEFAULT,表示不包含邊界值倒序填充。8.borderValue:使用邊界不變外推法時的邊界值。該函數根據結構元素對輸入圖像進行多種形態學操作,在處理多通道圖像時每個通道獨立進行處理。
函數的第一個參數為待形態學處理的圖像,圖像通道數可以是任意的,但是圖像的數據類型必須是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。
函數第二個參數為形態學處理后的輸出圖像,與輸入圖像具有相同的尺寸和數據類型。
函數第三個參數是形態學操作類型的選擇標志,可以選擇的形態學操作類型有開運算、閉運算、形態學梯度、頂帽運算、黑帽運算以及擊中擊不中變換,詳細的參數在表6-6給出。
函數第四個和第五個參數都是與結構元素相關的參數,第四個參數為結構元素,使用的結構元素尺寸越大效果越明顯,第四個參數為結構元素的中心位置,第五個參數的默認值為Point(-1,-1),表示結構元素的幾何中心處為結構元素的中心點。
函數第六個參數是使用結構元素處理的次數,處理次數越多效果越明顯。
函數第七個參數是圖像像素外推法的選擇標志,
第八個參數為使用邊界不變外推法時的邊界值,這兩個參數對圖像中主要部分的形態學操作沒有影響,因此在多數情況下使用默認值即可。標志參數         簡記       作用MORPH_ERODE      0       圖像腐蝕MorPh_DIlATE     1       圖像膨脹MORPh_OPEN       2        開運算MORPH_CLOSE      3        閉運算MORPH_GRADIENT   4       形態學梯度MORPh_TOPHAT     5        頂帽運算MORPH_BLACKHAT   6        黑帽運算MORPH_HITMISS    7       擊中擊不中運算*///用于驗證形態學應用的二值化矩陣Mat src = (Mat_<uchar>(9, 12) <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 0, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 0,0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);namedWindow("src", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("src", src);// 創建3X3矩形核元素Mat kernel = getStructuringElement(0, Size(3,3));// 1.對象矩陣進行膨脹操作Mat dilateImg;morphologyEx(src, dilateImg, MORPH_DILATE, kernel);namedWindow("dilateWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("dilateWd", dilateImg);// 2.對象矩陣進行腐蝕操作Mat erodeImg;morphologyEx(src, erodeImg, MORPH_ERODE, kernel);namedWindow("erodeWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("erodeWd", erodeImg);// 3.對象矩陣進行開運算操作Mat openImg;morphologyEx(src, openImg, MORPH_OPEN, kernel);namedWindow("openWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("openWd", openImg);// 4.對象矩陣進行閉運算操作Mat closeImg;morphologyEx(src, closeImg, MORPH_CLOSE, kernel);namedWindow("closeWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("closeWd", closeImg);// 5.對象矩陣進行頂帽    原圖 - 開操作后的圖Mat topHatImg;morphologyEx(src, topHatImg, MORPH_TOPHAT, kernel);namedWindow("topHatWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("topHatWd", topHatImg);// 6.對象矩陣進行黑帽    閉操作后的圖 - 原圖Mat blackImg;morphologyEx(src, blackImg, MORPH_BLACKHAT, kernel);namedWindow("blackWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("blackWd", blackImg);// 7.對象矩陣進行梯度運算操作// 內梯度:原圖 - 腐蝕圖// 外梯度:膨脹圖 - 原圖Mat gradientImg;morphologyEx(src, gradientImg, MORPH_GRADIENT, kernel);namedWindow("gradientWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("gradientWd", gradientImg);// 8.對象矩陣進行擊中擊不中運算  通過特定模板,僅當輸入的圖像中,**有與模板一模一樣的塊**時,被擊中的輸入圖像區域才會被保留。Mat hitmissImg;morphologyEx(src, hitmissImg, MORPH_HITMISS, kernel);namedWindow("hitmissWd", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸imshow("hitmissWd", hitmissImg);waitKey(0);destroyAllWindows();}//10仿射平移變換
void MainWindow::demo10()
{//    // 創建一個3X4矩陣//       Mat matRect = Mat::eye(3,4, CV_8UC1);//       // 打印矩陣//       cout << matRect <<endl;//       // 打印矩陣的行列值//       cout << "rows :" << matRect.rows << endl;//       cout << "cols :" << matRect.cols << endl;//       // 訪問數據//       // matRect.at<uchar>(y,x) => y(row), x(col)//       matRect.at<uchar>(0,0) = 255;//       matRect.at<uchar>(0,2) = 255;//       // 設置像素點后結果//       cout << matRect <<endl;//       namedWindow("matRect", WINDOW_NORMAL);  //可以自由調節顯示圖像的尺寸//       imshow("matRect", matRect);// 讀取圖像Mat srcImg = imread("./image/1.png");// 定義窗口的名稱string srcTitle = "原始圖像";// 創建1個窗口namedWindow(srcTitle, WINDOW_NORMAL);// 顯示原圖imshow(srcTitle, srcImg);// 定義原圖的三個點Point2f srcPoints[3];// 定義映射后的三個坐標點Point2f dstPoints[3];// 采用三角法srcPoints[0] = Point2f(0, 0);srcPoints[1] = Point2f(0, srcImg.rows);srcPoints[2] = Point2f(srcImg.cols, 0);// 映射后的三個點dstPoints[0] = Point2f(106, 106);dstPoints[1] = Point2f(106, srcImg.rows +106);dstPoints[2] = Point2f(srcImg.cols +106,106);// 獲取仿射變換矩陣//        Mat M1=getAffineTransform(const Point2f* src, const Point2f* dst)//        參數const Point2f* src:原圖的三個固定頂點(左上角,左下角,右上角)//        參數const Point2f* dst:目標圖像的三個固定頂點//        返回值:Mat型變換矩陣,可直接用于warpAffine()函數//        注意,頂點數組長度超過3個,則會自動以前3個為變換頂點;數組可用Point2f[]或Point2f*表示Mat homat2D = getAffineTransform(srcPoints, dstPoints);// 進行圖像仿射變換操作//void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())//參數InputArray src:輸入變換前圖像//參數OutputArray dst:輸出變換后圖像,需要初始化一個空矩陣用來保存結果,不用設定矩陣尺寸//參數InputArray M:變換矩陣,用另一個函數getAffineTransform()計算//參數Size dsize:設置輸出圖像大小//參數int flags = INTER_LINEAR:設置插值方式,默認方式為線性插值(另一種WARP_FILL_OUTLIERS)//參數int borderMode=BORDER_CONSTANT:邊界像素模式,默認值BORDER_CONSTANT//參數const Scalar& borderValue=Scalar(),在恒定邊界情況下取的值,默認值為Scalar(),即0Mat dstImg;warpAffine(srcImg, dstImg, homat2D, srcImg.size());// 創建1個窗口namedWindow("平移后", WINDOW_NORMAL);// 顯示原圖imshow("平移后", dstImg);waitKey(0);destroyAllWindows();}//11角度+縮放仿射變換
void MainWindow::demo11()
{// 讀取圖像Mat srcImg = imread("./image/1.png");// 定窗口的名稱string srcTitle = "原始圖像";// 創建1個窗口namedWindow(srcTitle, WINDOW_NORMAL);// 顯示原圖imshow(srcTitle, srcImg);//獲取原圖坐標int nCols = srcImg.cols;int nRows = srcImg.rows;//設置仿射變換參數Point2f centerPoint = Point2f(nCols / 2, nRows / 2);double angle = -90;double scale = 0.5;//獲取仿射變換矩陣// Mat M2=getRotationMatrix2D (CvPoint2D32f  center,double angle,double scale)//參數CvPoint2D32f  center,表示源圖像旋轉中心//參數double angle,旋轉角度,正值表示逆時針旋轉//參數double scale,縮放系數Mat homat2D = getRotationMatrix2D(centerPoint, angle, scale);// 進行圖像仿射變換操作Mat dstImg;warpAffine(srcImg, dstImg, homat2D, srcImg.size());// 創建1個窗口namedWindow("變換后", WINDOW_NORMAL);// 顯示原圖imshow("變換后", dstImg);waitKey(0);destroyAllWindows();
}//12透視變換(四點法的平移仿射變換)
void MainWindow::demo12()
{Mat src;src = imread("./image/1.png");namedWindow("original image", CV_WINDOW_AUTOSIZE);imshow("original image", src);Mat dst_warp;Point2f srcPoints[4];//原圖中的四點 ,一個包含三維點(x,y)的數組,其中x、y是浮點型數Point2f dstPoints[4];//目標圖中的四點srcPoints[0] = Point2f(0, 0);srcPoints[1] = Point2f(0, src.rows);srcPoints[2] = Point2f(src.cols, 0);srcPoints[3] = Point2f(src.cols, src.rows);//映射后的四個坐標值dstPoints[0] = Point2f(100, 100);dstPoints[1] = Point2f(100, src.rows+100);dstPoints[2] = Point2f(src.cols+100, 100);dstPoints[3] = Point2f(src.cols+100, src.rows+100);// getPerspectiveTransform(const Point2f* src, const Point2f* dst)// 參數const Point2f* src:原圖的四個固定頂點// 參數const Point2f* dst:目標圖像的四個固定頂點// 返回值:Mat型變換矩陣,可直接用于warpAffine()函數// 注意,頂點數組長度超4個,則會自動以前4個為變換頂點;數組可用Point2f[]或Point2f*表示// 注意:透視變換的點選取變為4個Mat M1 = getPerspectiveTransform(srcPoints, dstPoints);//由四個點對計算透視變換矩陣//  warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())//參數InputArray src:輸入變換前圖像//參數OutputArray dst:輸出變換后圖像,需要初始化一個空矩陣用來保存結果,不用設定矩陣尺寸//參數InputArray M:變換矩陣,用另一個函數getAffineTransform()計算//參數Size dsize:設置輸出圖像大小//參數int flags = INTER_LINEAR:設置插值方式,默認方式為線性插值(另一種WARP_FILL_OUTLIERS)warpPerspective(src, dst_warp, M1, src.size());//仿射變換namedWindow("Perspective image", CV_WINDOW_AUTOSIZE);imshow("Perspective image", dst_warp);waitKey(0);
}//13坐標映射
void MainWindow::demo13()
{Mat src = imread("./image/1.png");if (!src.data){return ;}//輸出矩陣定義Mat result(src.size(), src.type());//x方向與y方向矩陣Mat xMap(src.size(), CV_32FC1);Mat yMap(src.size(), CV_32FC1);//取圖像的寬和高int rows = src.rows;int cols = src.cols;//圖像遍歷for (int j = 0; j < rows; j++){for (int i = 0; i < cols; i++){//x與y均翻轉xMap.at<float>(j, i) = cols - i;yMap.at<float>(j, i) = rows - j;}}//重映射操作/*
圖像的坐標映射是通過原圖像與目標圖像之間建立一種映射關系,這種映射關系有兩種:一種是計算原圖像任意像素在映射后圖像后的坐標位置二是計算變換后圖像任意像素反應設在原圖像的坐標位置。由原圖像映射到目標圖像稱為正映射,相反地,由目標圖像通過映射關系得到原圖像稱為反映射。由于正映射常常會映射不完全以及出現映射重復現象,一般在圖像處理的過程中采取反映射的方式來保證輸出目標圖像的每個像素都可以通過映射關系在源圖像中找到唯一的對應像素。OpenCV中提供重映射相關操作,重映射是指把一個圖像中一個位置的像素通過映射關系轉換到零一圖像的指定位置。
對于輸入源圖像f(x,y),目標圖像為g(x,y),映射關系為T,則滿足 g(x,y)=T(f(x,y))需要注意的是通過映射關系T實現得到的目標圖像可能存在目標圖像像素值是非整數的情況,一般可以考慮插值或向上取整void remap(InputArray src,OutputArray dst,InputArray map1,InputArray map2,int interpolation,int borderMode=BORDER_CONSTANT,const Scallar& borderValue=Scalar())map1表示(x,y)點的坐標或x坐標,可以是CV_16SC2,CV_32FC1,CV_32FC2類型;map2表示y坐標,可以是CV_16UC1,CV_32FC1類型,如果map1為(x,y),map2則可以選擇不用;interpolation表示插值方法;borderMode表示邊界插值類型;borderValue表示插值數值。
*/remap(src, result, xMap, yMap, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));//輸出結果imshow("src", src);imshow("result", result);waitKey();destroyAllWindows();
}//14模板匹配
void MainWindow::demo14()
{//    1 CV_EXPORTS_W void matchTemplate(InputArray image, InputArray temp1, OutputArray result, int method);//    image:待搜索圖像(大圖)//      temp1:搜索模板,需和原圖一樣數據類型且尺寸大小不能大于源圖像//      reuslt:比較結果的映射圖像,其必須為單通道的,32位浮點型圖像,如果原圖(待搜索圖像)尺寸為W*H,二temp1的尺寸為w*h,則result的尺寸一定是(W-w+1)*(H-h+1)//      method:指定的匹配方法,有如下六種://            CV_TM_SQDIFF --- 平方差匹配法(最好匹配0)//            CV_TM_SQDIFF_NORMED --- 歸一化平方差匹配法(最好匹配0)//            CV_TM_CCORR --- 相關匹配法(最壞匹配0)//            CV_TM_CCORR_NORMED ---歸一化相關匹配法(最壞匹配0)//            CV_TM_CCOEFF --- 系數匹配法(最好匹配1)//            CV_TM_CCOEFF_NORMED --- 歸一化系數匹配法(最好匹配1)//    2、矩陣歸一化 — normalize()//    void normalize(InputArray src,OutputArray dst, double alpha=1,//                double beta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )//      src:輸入源圖像,Mat類型//      dst:輸出結果圖像,需要和原圖一樣的尺寸和類型//      alpha:歸一化后的最小值,默認為1//      beta:歸一化后的最大值,默認為0//      norm_type:歸一化類型,可選:NORM_INF, NORM_L1, NORM_L2(默認)等//      dtype:默認值為-1,此參數為負值時,輸出矩陣和src有同樣的類型//      mask:可選的掩碼操作//    normallize()函數的作用是進行矩陣歸一化。//    3、尋找最值 — minMaxLoc()//    1void minMaxLoc(InputArray src, CV_OUT double* minVal, CV_OUT double* maxVal = 0,//                      CV_OUT Point* minLoc=0, CV_OUT Point* maxLoc=0,//                      InputArray mask=noArray());//      src:輸入源圖像,單通道圖像//      minVal:返回最小值的指針,若無需返回,則置為0//      maxVal:返回最大值的指針,若無需返回,則置為0//      minLoc:返回最小位置的指針,若無需返回,則置為0//      maxLoc:返回最大位置的指針,若無需返回,則置為0//      mask:可選的掩碼操作//    minMaxLoc()函數的作用是在數組中找到全局最小值和最大值Mat temp=imread("./image/20.png");Mat src=imread("./image/16.png");Mat dst=src.clone();imshow("temp",temp);int width=src.cols-temp.cols+1;//result寬度int height=src.rows-temp.rows+1;//result高度Mat result(height,width,CV_32FC1);//創建結果映射圖像//matchTemplate(srcImg, templateImg, resultImg, CV_TM_SQDIFF); //平方差匹配法(最好匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_SQDIFF_NORMED); //歸一化平方差匹配法(最好匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCORR); //相關匹配法(最壞匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCORR_NORMED); //歸一化相關匹配法(最壞匹配0)//matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCOEFF); //系數匹配法(最好匹配1)matchTemplate(src,temp,result,CV_TM_CCOEFF_NORMED);//化相關系數匹配,最佳值1//  imshow("result",result);normalize(result,result,0,1,NORM_MINMAX,-1);//歸一化到0-1范圍double minValue,maxValue;Point minLoc,maxLoc;minMaxLoc(result,&minValue,&maxValue,&minLoc,&maxLoc);cout<<"minValue="<<minValue<<endl;cout<<"maxValue="<<maxValue<<endl;rectangle(dst,maxLoc,Point(maxLoc.x+temp.cols,maxLoc.y+temp.rows),Scalar(0,255,0),2,8);imshow("dst",dst);waitKey(0);destroyAllWindows();
}//15多模板匹配
void MainWindow::demo15()
{Mat srcImg = imread("./image/16.png");cvtColor(srcImg, srcImg, CV_BGR2GRAY);//轉為灰度圖Mat templateImg = imread("./image/20.png");cvtColor(templateImg, templateImg, CV_BGR2GRAY);//轉為灰度圖Mat resultImg;Mat showImg = srcImg.clone();int resultImg_cols = srcImg.cols -  templateImg.cols + 1;int resultImg_rows = srcImg.rows -  templateImg.rows + 1;resultImg.create(resultImg_cols, resultImg_rows, CV_32FC1);matchTemplate(srcImg, templateImg, resultImg, CV_TM_CCOEFF_NORMED); //化相關系數匹配法(最好匹配1)normalize(resultImg, resultImg, 0, 1, NORM_MINMAX);Mat midImg = resultImg.clone();//多目標模板匹配---方法一double matchValue;int count0=0;int tempW=0, tempH=0;char matchRate[10];for(int i=0; i<resultImg_rows; i++){for(int j=0; j<resultImg_cols; j++){matchValue = resultImg.at<float>(i, j);sprintf(matchRate, "%0.2f", matchValue);if(matchValue>=0.75 && (abs(j - tempW)>5) && (abs(i - tempH)>5) ){count0++;putText(showImg, matchRate, Point(j-5, i-5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);rectangle(showImg, Point(j, i), Point(j + templateImg.cols, i + templateImg.rows), Scalar(0, 255, 0), 2);tempW = j;tempH = i;}}}cout<<"count="<<count0<<endl;imshow("resultImg", midImg);imshow("dst", showImg);//多目標模板匹配---方法二
//           double minValue, maxValue;
//           Point minLoc, maxLoc;
//           Point matchLoc;
//           char matchRate[10];//           for(int i=0; i<100; i++)
//           {
//               int startX = maxLoc.x - 4;
//               int startY = maxLoc.y - 4;
//               int endX = maxLoc.x + 4;
//               int endY = maxLoc.y + 4;
//               if(startX<0 || startY<0)
//               {
//                   startX = 0;
//                   startY = 0;
//               }
//                if(endX > resultImg.cols - 1 || endY > resultImg.rows - 1)
//               {
//                   endX = resultImg.cols - 1;
//                   endY = resultImg.rows- 1;
//               }
//                Mat temp = Mat::zeros(endX - startX, endY - startY, CV_32FC1);
//                //Mat ROI = resultImg(Rect(Point(startX, startY), temp.cols, temp.rows));
//                temp.copyTo(resultImg(Rect(startX, startY, temp.cols, temp.rows)));
//                minMaxLoc(resultImg, &minValue, &maxValue, &minLoc, &maxLoc);
//                if(maxValue<0.8)    break;//                cout<<"max_value= "<<maxValue<<endl;
//                sprintf(matchRate, "%0.2f", maxValue);
//                putText(showImg, matchRate, Point(maxLoc.x - 5, maxLoc.y - 5), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 1);
//                rectangle(showImg, maxLoc, Point(maxLoc.x + templateImg.cols, maxLoc.y + templateImg.rows), Scalar(0, 255, 0), 2);//           }
//           imshow("midImg", midImg);
//           imshow("resultImg", resultImg);
//           imshow("dst", showImg);waitKey(0);destroyAllWindows();
}//16查找輪廓線
void MainWindow::demo16()
{/*1)什么是輪廓輪廓可以簡單認為成將連續的點(連著邊界)連在一起的曲線,具有相同的顏色或者灰度,提取輪廓就是提取這些具有相同顏色或者灰度的曲線,或者說是連通域,輪廓在形狀分析和物體的檢測和識別中非常有用。2)注意事項:①為了更加準確,要使用二值化圖像。在尋找輪廓之前,要進行閾值化處理 或者 Canny 邊界檢測②查找輪廓的函數會修改原始圖像。如果你在找到輪廓之后還想使用原始圖像的話,你應該將原始圖像存儲到其他變量中(clone(), copyTo())③在OpenCV 中,查找輪廓就像在黑色背景中找白色物體。你應該記住,要找的物體應該是白色而背景應該是黑色。3)常用函數:findContours()—–查找輪廓drawContours()—–繪制輪廓findContours(InputArray image, OutputArrayofArrays contours, OutputArray hierarchy,int mode, int method, Point offset=Point());image: 輸入圖像, Mat類型8位單通道圖像(一般為二值圖)contours: 檢測到的輪廓, 每個輪廓存儲為一個點向量, 即Point類型的vector表示hierarchy: 可選的輸出向量, 包含圖像的拓撲信息。其作為輪廓數量的表示, 包含了許多元素, 每個輪廓contours[i]對應4個hierarchy元素hierarchy[i][0]~hierarchy[i][3], 分別表示后一輪廓、前一輪廓、父輪廓、內嵌輪廓的索引編號, 如果沒有對應項, 設置為負數mode: 輪廓檢索模式, 取值如下:CV_RETR_EXTERNAL=0-----表示只檢測最外層輪廓CV_RETR_LIST=1------提取所有輪廓并放置在list中, 輪廓不建立等級關系CV_RETR_CCOMP=2------提取所有輪廓并組織為雙層結構CV_RETR_TREE=3------提取所有輪廓并重新建立網狀輪廓結構method: 輪廓的近似方法, 取值如下:CV_CHAIN_APPROX_NONE ---連續存儲所有的輪廓點,任何兩個相鄰的點都是水平、垂直或者相鄰的。也就是說max(abs(x1-x2), abs(y2-y1)) == 1CV_CHAIN_APPROX_SIMPLE --- 壓縮存儲,對于水平、垂直或者斜向的線段,比如一個四邊形,只會存儲四個頂點CV_CHAIN_APPROX_TC89_L1/CV_CHAIN_APPROX_TC89_KCOSoffset: 每個輪廓的可選偏移量, 默認值Point()3、繪制輪廓1 CV_EXPORTS_W void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx,const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(),int maxLevel=INT_MAX, Point offset=Point());image: 目標圖像, Mat類型對象即可contours: 所有的輸入輪廓, 每個輪廓存儲為一個點向量contourIdx: 輪廓繪制指示變量(索引), 若為負值, 則表示繪制所有輪廓color: 繪制輪廓的顏色thickness: 輪廓線條的粗細, 默認值1, 如果為負值, 則繪制輪廓內部, 可選宏 CV_FILLEDlineType: 線條類型, 默認值8hierarcy: 可選的層次結構信息, 默認值noArray()maxLevel: 表示用于繪制輪廓的最大等級, 默認值INT_MAXoffset: 可選的輪廓偏移參數, 默認值Point()*///查找所有輪廓線//    Mat srcImg = imread("./image/17.png");//    Mat tempImg = srcImg.clone();//       //Mat draw(srcImg.rows, srcImg.cols, CV_8UC3);//       cvtColor(srcImg, srcImg, CV_BGR2GRAY); //轉為灰度圖//       threshold(srcImg, srcImg,100, 255, CV_THRESH_BINARY);//圖像二值化,value>threshold(即100)?255:0//       imshow("二值化后圖像", srcImg);  //輪廓查找前//      //imwrite("./image/98.png",srcImg);//       vector<vector<Point>> contours;//       vector<Vec4i> hierarchy;//      // findContours(srcImg, contours, hierarchy,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE ); //查找外輪廓,壓縮存儲輪廓點//       findContours(srcImg, contours, hierarchy,RETR_LIST, CHAIN_APPROX_SIMPLE ); //查找所有輪廓//       //findContours(srcImg, contours, hierarchy,CV_RETR_CCOMP, CHAIN_APPROX_SIMPLE ); //查找所有輪廓//       //findContours(srcImg, contours, hierarchy,RETR_TREE, CHAIN_APPROX_NONE ); //查找所有輪廓,存儲所有輪廓點//      // imshow("cont", srcImg);  //輪廓查找后//       cout<<"num="<<contours.size()<<endl; //輸出輪廓個數//       for(int i=0;i<contours.size();i++)//       {//            drawContours(tempImg, contours,i, Scalar(0, 255, 0),2);  //繪制輪廓:-1代表繪制所有輪廓//       }//       imshow("原圖處理后", tempImg);//去除邊界輪廓線方法一Mat srcImg = imread("./image/16.png");Mat tempImg = srcImg.clone();cvtColor(srcImg, srcImg, COLOR_BGR2GRAY);threshold(srcImg, srcImg, 100, 255, THRESH_BINARY);// 進行形態學操作去除小噪點Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));morphologyEx(srcImg, srcImg, MORPH_OPEN, kernel);//開運算imshow("二值化后圖像", srcImg);vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(srcImg, contours, hierarchy, RETR_LIST, CHAIN_APPROX_SIMPLE);cout << "num=" << contours.size() << endl;double minAreaThreshold1 = 1000.0; // 設置合適的面積閾值double minAreaThreshold2 = 15000.0;// 設置合適的面積閾值for (int i = 0; i < contours.size(); i++){if (contourArea(contours[i]) > minAreaThreshold1 && minAreaThreshold2 >contourArea(contours[i])){drawContours(tempImg, contours, i, Scalar(0, 255, 0), 2);}}imshow("原圖處理后", tempImg);//    //去除邊界輪廓線方法二//    Mat srcImg = imread("./image/16.png");//    Mat tempImg = srcImg.clone();//    cvtColor(srcImg, srcImg, COLOR_BGR2GRAY);//    threshold(srcImg, srcImg, 100, 255, THRESH_BINARY);//    imshow("二值化后圖像", srcImg);//    vector<vector<Point>> contours;//    vector<Vec4i> hierarchy;//    findContours(srcImg, contours, hierarchy, RETR_LIST, CHAIN_APPROX_SIMPLE);//    cout << "Contours found: " << contours.size() << endl;//    // 繪制不接觸邊界的輪廓//    for (int i = 0; i < contours.size(); i++)//    {//        bool isBoundaryContour = false;//        for (auto& point : contours[i])//        {//            if (point.x <= 0 || point.x >= srcImg.cols - 1 || point.y <= 0 || point.y >= srcImg.rows - 1)//            {//                isBoundaryContour = true;//                break;//            }//        }//        if (!isBoundaryContour)//        {//            drawContours(tempImg, contours, i, Scalar(0, 255, 0), 2);//        }//    }//    imshow("原圖處理后", tempImg);waitKey(0);destroyAllWindows();
}//模板匹配
void MainWindow::on_pushButton_2_clicked()
{//1.創建模板Mat TemplateImage= imread("./image/model/model.png");  //.bmp   加后綴  黑白圖Mat oriImg = TemplateImage.clone();//復制原圖做為最終顯示Mat TemplateImage1;cvtColor(TemplateImage, TemplateImage1, CV_BGR2GRAY);//轉為灰度圖Mat TemplateImage2;threshold(TemplateImage1, TemplateImage2, 100, 255,CV_THRESH_BINARY);//二值化處理// 進行形態學操作去除小噪點Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));morphologyEx(TemplateImage2, TemplateImage2, MORPH_OPEN, kernel);vector <vector <Point> >  modelContours;vector<Vec4i> hierarcy;findContours(TemplateImage2, modelContours, hierarcy,RETR_LIST, CHAIN_APPROX_SIMPLE ); //查找所有輪廓qDebug()<<QString::fromLocal8Bit(" 模板輪廓數量:")<<modelContours.size();   //兩個輪廓double minAreaThreshold1 = 1000.0; // 設置合適的面積閾值double minAreaThreshold2 = 20000.0;// 設置合適的面積閾值int tempIdx;   //旋轉最長的那個輪廓線for (int i = 0; i < modelContours.size(); i++){if (contourArea(modelContours[i]) > minAreaThreshold1 && minAreaThreshold2 >contourArea(modelContours[i])){//繪制查找到的輪廓線drawContours(oriImg, modelContours, i, Scalar(0, 255, 0), 2);tempIdx = i;}}imshow("模板圖像", oriImg);//2.找到被查找圖像的輪廓線Mat SearchImage= imread("./image/model/scene.png");Mat oriImg2 = SearchImage.clone();imshow("匹配圖像", oriImg2);Mat TemplateImage3;cvtColor(SearchImage, TemplateImage3, CV_BGR2GRAY);//轉灰度圖//pixmap  做個剪切  596 ,  319, 795,  518//QPixmap pm = pixmap.copy(QRect(QPoint(596-100 ,  319-50),QPoint(795+200,  518+200)));Mat TemplateImage4;threshold(TemplateImage3, TemplateImage4, 100, 255,CV_THRESH_BINARY);//二值化// 進行形態學操作去除小噪點Mat kernel2 = getStructuringElement(MORPH_RECT, Size(7, 7));morphologyEx(TemplateImage4, TemplateImage4, MORPH_OPEN, kernel2);vector <vector <Point> >  SearchContours;vector<Vec4i> hierarcy1;findContours(TemplateImage4, SearchContours, hierarcy1,RETR_LIST, CHAIN_APPROX_SIMPLE ); //查找所有輪廓qDebug()<<QString::fromLocal8Bit(" 匹配輪廓數量:")<<SearchContours.size();double minAreaThreshold3 = 1000.0; // 設置合適的面積閾值double minAreaThreshold4 = 20000.0;// 設置合適的面積閾值for (int i = 0; i < SearchContours.size(); i++){if (contourArea(SearchContours[i]) > minAreaThreshold3 && minAreaThreshold4 >contourArea(SearchContours[i])){//繪制查找到的輪廓線drawContours(oriImg2, SearchContours, i, Scalar(0, 255, 0), 2);}}//識別到多個變成數組,存到boxvector<RotatedRect>box(SearchContours.size());qDebug()<<QString::fromLocal8Bit("識別數量=")<<SearchContours.size();Point center4;//定義匹配坐標Mat matCenter4 = Mat::ones(3, 1, CV_64FC1);//3.對于被查詢輪廓線 逐一進行匹配   ----相當于for循環for(int i=0; i<SearchContours.size(); i++){//返回的是匹配得分//modelContours[tempIdx]  ---模板輪廓線//SearchContours[i]   --被檢測物體輪廓線//對于輪廓線較長進行匹配  ,較小的輪廓線直接刪除double oriented;double area= contourArea(SearchContours[i],oriented);if(abs(area)<1000){qDebug()<<QString::fromLocal8Bit("短輪廓長度" ) <<abs(area);continue;}else{qDebug()<<QString::fromLocal8Bit("長輪廓長度")  <<abs(area);}//開始匹配 matchShapes()函數比較輪廓相似度是基于Hu矩來計算的, 結果越小相似度越高。double matchRate = matchShapes(modelContours[tempIdx], SearchContours[i], CV_CONTOURS_MATCH_I1, 0.0);//形狀匹配:值越小越相似qDebug()<<QString::fromLocal8Bit("匹配得分")<<matchRate ;//得分較小的存儲并且打印 ,  得分大的直接刪除if(matchRate<=0.5){//仿射輪廓線到目標位置drawContours(oriImg2,SearchContours, i, Scalar(0,255,0), 2,8);imwrite("./data/sceneResult.bmp",oriImg2);/*輸出坐標****************************************************///box  ---存儲了 匹配的結果//RotatedRect::RotatedRect()//: center(), size(), angle(0) {}box[i]= fitEllipse(Mat(SearchContours[i]));//qDebug()<<"matchrate--z1     ---0:="  <<i;circle(oriImg2, box[i].center, 3, Scalar(0, 0, 255),-1, 8);center4 = box[i].center;//string strCenter = pointToString(center4.x,center4.y);stringstream ssX,ssY;ssX << center4.x;ssY << center4.y;string sx,sy;ssX >> sx;ssY >> sy;string strCenter = " (" + sx + "," + sy + ")";//輸出顯示putText(oriImg2, strCenter, Point2f(center4.x,center4.y), CV_FONT_HERSHEY_COMPLEX, 0.5, Scalar(0, 0, 255),1);//保存坐標值// matCenter4.at<double>(0, 0) = center4.x;//  matCenter4.at<double>(1, 0) = center4.y;// 提取值并打印1// double x = matCenter4.at<double>(0, 0);// double y = matCenter4.at<double>(1, 0);// qDebug() << QString::fromLocal8Bit("匹配坐標=")<<"(" << x << "," << y << ")" << endl;// 打印2qDebug()<<QString::fromLocal8Bit("匹配x坐標")<<center4.x;qDebug()<<QString::fromLocal8Bit("匹配y坐標")<<center4.y;qDebug()<<QString::fromLocal8Bit("匹配角度")<<box[i].angle;}imshow("結果圖像", oriImg2);}SearchContours.clear();waitKey(0);destroyAllWindows();
}//繪制圖形
void MainWindow::on_pushButton_3_clicked()
{Mat image(600,800,CV_8UC3,Scalar(255,255,255));imshow("空白圖像",image);//畫圓Point   ptCircleCenter;  //聲明一個變量ptCircleCenter.x=300;ptCircleCenter.y=300;int nRadius=50;circle(image, ptCircleCenter, nRadius, Scalar(0, 255, 0), 3);imshow("圓",image);//畫直線Point  Pt1,Pt2;Pt1.x=150;Pt1.y=100;Pt2.x=150;Pt2.y=500;line(image,Pt1,Pt2,Scalar(0,0,0),3,8,0);imshow("線",image);//畫矩形Rect rect(370, 200, 300, 300);rectangle(image,rect,Scalar(255,0,0),3,2,0);imshow("矩形",image);// 剪切矩形區域Mat croppedImage = image(rect);  // 使用矩形區域進行剪切imshow("剪切后的圖像", croppedImage);waitKey(0);destroyAllWindows();}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84825.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84825.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84825.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Python】Python之什么是生成器?什么是迭代器?

目錄 專欄導讀前言什么是迭代器&#xff08;Iterator&#xff09;&#xff1f;迭代器的定義迭代器協議可迭代對象 vs 迭代器自定義迭代器迭代器的優勢 什么是生成器&#xff08;Generator&#xff09;&#xff1f;生成器的定義生成器函數生成器表達式復雜的生成器示例生成器的狀…

Python中實現簡單爬蟲并處理數據

在當今數據驅動的時代&#xff0c;能夠從互聯網上高效地抓取信息變得越來越重要。Python因其簡潔易學的特性&#xff0c;成為了編寫網絡爬蟲的首選語言之一。接下來&#xff0c;我將介紹如何使用Python來實現一個基礎的網絡爬蟲&#xff0c;并對收集到的數據進行初步處理。 首先…

免費wordpress主題網

免費WordPress主題網 WP模板牛 WP模板牛是一個提供免費WordPress主題的網站&#xff0c;用戶可以在這里找到大量高質量的模板&#xff0c;適用于各種網站類型。該網站致力于為用戶提供簡單、高效的建站體驗。 官網鏈接&#xff1a; https://wpniu.com 建站哥模板 建站哥模板…

為什么需要MyBatis-Plus條件構造器?

目錄 前言 一、傳統SQL編寫的痛點 二、條件構造器的核心優勢 1. 防SQL注入&#xff08;安全性&#xff09; 2. 面向對象編程&#xff08;可讀性&#xff09; 3. 動態條件構建&#xff08;靈活性&#xff09; 4. 數據庫無關性&#xff08;可移植性&#xff09; 三、典型應…

【從零學習JVM|第九篇】常見的垃圾回收算法和垃圾回收器

前言&#xff1a; 我們知道在堆內存中&#xff0c;會有自動的垃圾回收功能&#xff0c;那今天這篇文章將會向你介紹&#xff0c;這個功能實現的方式&#xff0c;還有實現的對象&#xff0c;接下來就由我來給你們詳細介紹垃圾回收的算法和實現算法的回收器。 目錄 前言&#…

品牌竄貨治理解決方案

在渠道網絡的暗潮中&#xff0c;竄貨猶如隱秘的漩渦&#xff0c;某知名白酒品牌曾因區域竄貨導致終端價格體系崩潰&#xff0c;半年內損失超3億元。竄貨行為不僅破壞市場秩序&#xff0c;更會引發信任危機。隨著電商平臺的多元化與分銷層級的復雜化&#xff0c;品牌方亟需構建一…

車載電子電器架構 --- 法律和標準對電子電氣架構的影響

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 做到欲望極簡,了解自己的真實欲望,不受外在潮流的影響,不盲從,不跟風。把自己的精力全部用在自己。一是去掉多余,凡事找規律,基礎是誠信;二是…

一種通用跨平臺實現SEH的解決方案

一. 前言 眾所周知&#xff0c;在軟件的代碼中&#xff0c;處理軟件本身的邏輯只要大約1/3的代碼&#xff0c;另外2/3的代碼實際上是在處理各種各樣的異常情況。 這些異常情況一方面是因為不同用戶之間不同的硬件軟件環境要處理。另一方面是程序中可能出現的bug。比較典型的情…

25.6.19學習總結

什么是堆&#xff08;Heap&#xff09;&#xff1f; 堆是一種特殊的樹形數據結構&#xff0c;它滿足以下兩個主要屬性&#xff1a; 結構性&#xff08;完全二叉樹&#xff09;&#xff1a; 堆總是一個完全二叉樹 (Complete Binary Tree)。這意味著&#xff0c;除了最后一層&am…

【前后前】導入Excel文件閉環模型:Vue3前端上傳Excel文件,【Java后端接收、解析、返回數據】,Vue3前端接收展示數據

【前后前】導入Excel文件閉環模型&#xff1a;Vue3前端上傳Excel文件&#xff0c;【Java后端接收、解析、返回數據】&#xff0c;Vue3前端接收展示數據 一、Vue3前端上傳&#xff08;導入&#xff09;Excel文件 ReagentInDialog.vue <script setup lang"ts" na…

網絡基礎入門:從OSI模型到TCP/IP協議詳解

網絡基礎入門&#xff1a;從OSI模型到TCP/IP協議詳解 一、網絡基礎概念與OSI七層模型 1.1 網絡通信的本質 計算機網絡的核心是將抽象語言轉換為二進制數據進行傳輸與計算&#xff0c;這一過程涉及多層抽象與轉換&#xff1a; 應用層&#xff1a;人機交互—抽象語言------編…

Linux致命漏洞CVE-2025-6018和CVE-2025-6019

Qualys 最近披露了兩個影響主流 Linux 發行版的本地權限提升 (LPE) 漏洞&#xff0c;分別是 CVE-2025-6018 和 CVE-2025-6019。這兩個漏洞可以被串聯利用&#xff0c;使得非特權用戶在幾秒鐘內獲得系統的 root 權限&#xff0c;從而實現對系統的完全控制。 一、漏洞詳情 這兩…

【Docker基礎】Docker鏡像管理:docker push詳解

目錄 引言 1 Docker鏡像推送基礎概念 1.1 什么是Docker鏡像推送 1.2 鏡像倉庫概述 1.3 鏡像標簽與版本控制 2 docker push命令詳解 2.1 基本語法 2.2 常用參數選項 2.3 實際命令示例 2.4 推送流程 2.5 步驟描述 3 鏡像推送實踐示例 3.1 登錄管理 3.2 標簽管理 3…

FPGA基礎 -- Verilog行為建模之循環語句

行為級建模&#xff08;Behavioral Modeling&#xff09;是 Verilog HDL 中最接近軟件編程語言的一種描述方式&#xff0c;適用于功能建模和仿真建模的初期階段。在行為級中&#xff0c;循環語句&#xff08;loop statements&#xff09;是常見且重要的控制結構&#xff0c;用于…

從C學C++(7)——static成員

從C學C(7)——static成員 若無特殊說明&#xff0c;本博客所執行的C標準均為C11. static成員和成員函數 對于特定類型的全體對象而言&#xff0c;有時候可能需要訪問一個全局的變量。比如說統計某種類型對象已創建的數量。 通常在C中使用全局變量來實現&#xff0c;如果我們…

大模型和ollama一起打包到一個docker鏡像中

如何將大模型鏡像和 Ollama 鏡像打包在一個 Docker 鏡像中 最近工作中有個需求是將ollama和大模型一起打成一個鏡像部署&#xff0c;將自己的操作步驟分享給大家。將大模型與 Ollama 服務打包在同一個 Docker 鏡像中&#xff0c;可以簡化部署流程并確保環境一致性。下面詳細介…

2025年滲透測試面試題總結-攻防研究員(應用安全)(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 攻防研究員(應用安全) 一、基礎部分 1. HTTP狀態碼對比 2. HTTP請求方法核心作用 3. 網絡分層協議速查表…

SpringBoot新聞項目學習day3--后臺權限的增刪改查以及權限管理分配

新增管理員修改管理員刪除管理員登錄 新增管理員 1.點擊新增按鈕打開一個對話框 2.確定新增對話框要顯示哪些內容 3.提交 4.后端處理、保存 5.響應前端 vue代碼 <template><!-- 新增代碼內容是比較多的,建議抽取出來,定義到一個獨立的vue文件中在列表組件中導入…

算法導論第二十五章 深度學習的倫理與社會影響

第二十五章 深度學習的倫理與社會影響 技術的光芒不應掩蓋倫理的陰影 隨著深度學習技術在各領域的廣泛應用&#xff0c;其引發的倫理和社會問題日益凸顯。本章將深入探討這些挑戰&#xff0c;并提供技術解決方案和最佳實踐&#xff0c;引導讀者構建負責任的人工智能系統。 25.…

Linux中ansible模塊補充和playbook講解

一、模塊使用 1.1 Yum模塊 功能&#xff1a;管理軟件包&#xff0c;只支持RHEL&#xff0c;CentOS&#xff0c;fedora&#xff0c;不支持Ubuntu其它版本 參數說明name要操作的軟件包名稱&#xff0c;支持通配符&#xff08;如 httpd, nginx*&#xff09;&#xff0c;也可以是…