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();}