專案實戰:Qt+OpenCV大家來找茬(Qt抓圖,穿透應用,識別區別,框選區別,微調位置)
前言
Demo演示效果
執行包下載地址(供測試學習)
執行包+原始碼包下載地址(供測試學習)
功能列表
Qt技術點
OpenCV技術點
專案模組化部署
Qt程式碼:DrawWdget
Ui介面
DrawWidegt.h
#ifndef DRAWWIDGET_H#define DRAWWIDGET_H#include <QWidget>namespace Ui {class DrawWidget;}class DrawWidget : public QWidget{ Q_OBJECTpublic: explicit DrawWidget(QWidget *parent = 0); ~DrawWidget();public: void setRect(int x, int y, int width, int height); void setRect2(int x, int y, int width, int height); void clearListRect(); void setListRect(QList<QRect> listRect);protected: void initControl();protected: void paintEvent(QPaintEvent *event);protected: void drawSelectRect(QPainter *painter); void drawListRect(QPainter *painter);private: Ui::DrawWidget *ui;private: QColor _colorRect; QRect _rect; QRect _rect2; QList<QRect> _listRect;};#endif // DRAWWIDGET_H
DrawWidget.cpp
#include "DrawWidget.h"#include "ui_DrawWidget.h"#include <QPainter>#include <windows.h>#include <QDebug>#include <QDateTime>//#define LOG qDebug()<<__FILE__<<__LINE__//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent), ui(new Ui::DrawWidget), _colorRect(Qt::red){ ui->setupUi(this); setWindowFlag(Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TransparentForMouseEvents); initControl();}DrawWidget::~DrawWidget(){ delete ui;}void DrawWidget::setRect(int x, int y, int width, int height){ _rect.setRect(x, y, width, height);}void DrawWidget::setRect2(int x, int y, int width, int height){ _rect2.setRect(x, y, width, height); LOG << _rect << _rect2;}void DrawWidget::clearListRect(){ _listRect.clear(); update();}void DrawWidget::setListRect(QList<QRect> listRect){ _listRect = listRect; update();}void DrawWidget::initControl(){ // 置頂 ::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);}void DrawWidget::paintEvent(QPaintEvent *event){ QPainter painter(this); drawSelectRect(&painter); drawListRect(&painter);}void DrawWidget::drawSelectRect(QPainter *painter){ painter->save(); painter->setPen(QPen(_colorRect, 4)); painter->drawRect(_rect); painter->drawRect(_rect2); painter->restore();}void DrawWidget::drawListRect(QPainter *painter){ painter->save(); painter->setPen(QPen(Qt::white, 2)); for(int index = 0; index < _listRect.size(); index++) { painter->drawRect(_rect.x() + _listRect.at(index).x(), _rect.y() + _listRect.at(index).y(), _listRect.at(index).width(), _listRect.at(index).height()); } painter->setPen(QPen(Qt::blue, 2)); for(int index = 0; index < _listRect.size(); index++) { painter->drawRect(_rect2.x() + _listRect.at(index).x(), _rect2.y() + _listRect.at(index).y(), _listRect.at(index).width(), _listRect.at(index).height()); } painter->restore();}
Qt程式碼:FindDifferenceWidget
Ui介面
FindDifferenceWidget.h
#ifndef FINDDIFFERENCEWIDGET_H#define FINDDIFFERENCEWIDGET_H#include <QWidget>#include <QPainter>#include <QRect>#include <QRegion>#include <QList>#include "FindDifferenceManager.h"#include "DrawWidget.h"#include <QElapsedTimer>namespace Ui {class FindDifferenceWidget;}class FindDifferenceWidget : public QWidget{ Q_OBJECTpublic: explicit FindDifferenceWidget(QWidget *parent = 0); ~FindDifferenceWidget();protected: void initControl(); void updateGameRect();protected slots: void slot_initControl();protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); void moveEvent(QMoveEvent *event); void closeEvent(QCloseEvent *event);protected slots: void slot_valueChanged(int value);protected slots: void slot_findResult(bool result, QList<QRect> listRect = QList<QRect>());private slots: void on_pushButton_do_clicked(); void on_pushButton_up_clicked(); void on_pushButton_left_clicked(); void on_pushButton_right_clicked(); void on_pushButton_down_clicked(); void on_pushButton_clear_clicked();private: Ui::FindDifferenceWidget *ui;private: FindDifferenceManager *_pFindDifferenceManager; QRect _rectGame; QRect _rectApplication; int _captionHeigh; int _margin; DrawWidget *_pDrawWidget;};#endif // FINDDIFFERENCEWIDGET_H
FindDifferenceWidget.cpp
#include "FindDifferenceWidget.h"#include "ui_FindDifferenceWidget.h"#include <windows.h>#include <QApplication>#include <QDesktopWidget>#include <QScreen>#include <QTimer>#include <QDebug>#include <QDateTime>//#define LOG qDebug()<<__FILE__<<__LINE__//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")FindDifferenceWidget::FindDifferenceWidget(QWidget *parent) : QWidget(parent), ui(new Ui::FindDifferenceWidget), _pFindDifferenceManager(0), _pDrawWidget(0){ ui->setupUi(this); QString version = "v1.0.0"; setWindowTitle(QString("大家來找茬(僅供學習Qt+OpenCV實戰專案) Demo %1(作者:長沙紅胖子 QQ:21497936 WX:15173255813 blog:hpzwl.blog.csdn.net").arg(version)); resize(1230, 785); initControl(); QTimer::singleShot(0, this, SLOT(slot_initControl()));}FindDifferenceWidget::~FindDifferenceWidget(){ delete ui;}void FindDifferenceWidget::initControl(){ // 置頂 ::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); // 識別類 _pFindDifferenceManager = new FindDifferenceManager(); connect(_pFindDifferenceManager, SIGNAL(signal_findResult(bool,QList<QRect>)), this, SLOT(slot_findResult(bool,QList<QRect>))); // 初始化 _captionHeigh = 26; _margin = 3; updateGameRect(); _pDrawWidget = new DrawWidget(); _pDrawWidget->show(); connect(ui->spinBox_image1X, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image1Y, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image1Width, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image1Height, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image2X, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image2Y, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image2Width, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image2Height, SIGNAL(valueChanged(int)), this, SLOT(slot_valueChanged(int))); _pDrawWidget->setRect(ui->spinBox_image1X->value(), ui->spinBox_image1Y->value(), ui->spinBox_image1Width->value(), ui->spinBox_image1Height->value()); _pDrawWidget->setRect2(ui->spinBox_image2X->value(), ui->spinBox_image2Y->value(), ui->spinBox_image2Width->value(), ui->spinBox_image2Height->value());}void FindDifferenceWidget::updateGameRect(){ _rectApplication = QRect(-_margin, -_captionHeigh, rect().width() + _margin*2, rect().height() + _captionHeigh + _margin); _rectGame = QRect(_margin, rect().height() - _margin - 780, 1032, 780);}void FindDifferenceWidget::slot_initControl(){ _pDrawWidget->setGeometry(ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(), ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(), ui->frame_mask->width(), ui->frame_mask->height());}void FindDifferenceWidget::paintEvent(QPaintEvent *event){#if 1 QRegion r1(_rectApplication); QRegion r2(_rectGame); QRegion r3 = r1 - r2; setMask(r3);#endif QWidget::paintEvent(event);}void FindDifferenceWidget::resizeEvent(QResizeEvent *event){ // 初始化 updateGameRect(); if(_pDrawWidget) { _pDrawWidget->setGeometry(ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(), ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(), ui->frame_mask->width(), ui->frame_mask->height()); }}void FindDifferenceWidget::moveEvent(QMoveEvent *event){ if(_pDrawWidget) { _pDrawWidget->setGeometry(ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(), ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(), ui->frame_mask->width(), ui->frame_mask->height()); } LOG << geometry();}void FindDifferenceWidget::closeEvent(QCloseEvent *event){ _pDrawWidget->hide(); _pDrawWidget->deleteLater();}void FindDifferenceWidget::slot_valueChanged(int value){ _pDrawWidget->setRect(ui->spinBox_image1X->value(), ui->spinBox_image1Y->value(), ui->spinBox_image1Width->value(), ui->spinBox_image1Height->value()); _pDrawWidget->setRect2(ui->spinBox_image2X->value(), ui->spinBox_image2Y->value(), ui->spinBox_image2Width->value(), ui->spinBox_image2Height->value()); _pDrawWidget->update(); QSpinBox *pSpinBox = dynamic_cast<QSpinBox *>(sender()); if(pSpinBox == ui->spinBox_image1Width) { ui->spinBox_image2Width->setValue(value); }else if(pSpinBox == ui->spinBox_image2Width) { ui->spinBox_image1Width->setValue(value); }else if(pSpinBox == ui->spinBox_image1Height) { ui->spinBox_image2Height->setValue(value); }else if(pSpinBox == ui->spinBox_image2Height) { ui->spinBox_image1Height->setValue(value); }}void FindDifferenceWidget::slot_findResult(bool result, QList<QRect> listRect){ if(result) { LOG << listRect; _pDrawWidget->setListRect(listRect); }}void FindDifferenceWidget::on_pushButton_do_clicked(){ _pDrawWidget->clearListRect(); QElapsedTimer elapsedTimer; elapsedTimer.start(); while(elapsedTimer.elapsed() < 500) { qApp->processEvents(); } QScreen * pScreen = QApplication::primaryScreen(); QImage gameImage = pScreen->grabWindow(QApplication::desktop()->winId(), ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(), ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(), ui->frame_mask->width(), ui->frame_mask->height()).toImage(); QImage image1 = gameImage.copy(ui->spinBox_image1X->value(), ui->spinBox_image1Y->value(), ui->spinBox_image1Width->value(), ui->spinBox_image1Height->value()); QImage image2 = gameImage.copy(ui->spinBox_image2X->value(), ui->spinBox_image2Y->value(), ui->spinBox_image2Width->value(), ui->spinBox_image2Height->value()); _pFindDifferenceManager->slot_findDiffrence(image1, image2);}void FindDifferenceWidget::on_pushButton_up_clicked(){ setGeometry(geometry().x(), geometry().y() - 1, geometry().width(), geometry().height());}void FindDifferenceWidget::on_pushButton_left_clicked(){ setGeometry(geometry().x() - 1, geometry().y(), geometry().width(), geometry().height());}void FindDifferenceWidget::on_pushButton_right_clicked(){ setGeometry(geometry().x() + 1, geometry().y(), geometry().width(), geometry().height());}void FindDifferenceWidget::on_pushButton_down_clicked(){ setGeometry(geometry().x(), geometry().y() + 1, geometry().width(), geometry().height());}void FindDifferenceWidget::on_pushButton_clear_clicked(){ _pDrawWidget->setListRect(QList<QRect>());}
OpenCV程式碼:FindDifferenceManager
FindDifferenceManager.h
#ifndef FINDDIFFERENCEMANAGER_H#define FINDDIFFERENCEMANAGER_H#include <QObject>#include <QImage>// opencv#include "opencv/highgui.h"#include "opencv/cxcore.h"#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"#include "opencv2/opencv.hpp"#include "opencv2/xphoto.hpp"#include "opencv2/dnn/dnn.hpp"// opencv_contrib#include <opencv2/xphoto.hpp>#include <opencv2/ximgproc.hpp>#include <opencv2/calib3d.hpp>#include <opencv2/features2d.hpp>#include <opencv2/xfeatures2d.hpp>#include <opencv2/xfeatures2d/nonfree.hpp>class FindDifferenceManager : public QObject{ Q_OBJECTpublic: explicit FindDifferenceManager(QObject *parent = 0);private: bool getRunning() const;signals: void signal_findResult(bool result, QList<QRect> listRect = QList<QRect>());public slots: void slot_start(); void slot_stop();public slots: void slot_findDiffrence(QImage image, QImage image2, int thresh = 20, QRect minRect = QRect(0, 0, 4, 4));protected: cv::Mat image2Mat(QImage image);private: bool _running;};#endif // FINDDIFFERENCEMANAGER_H
FindDifferenceManager.cpp
# include "FindDifferenceManager.h" # include <QTimer> # include <QDebug> # include <QDateTime> //#define LOG qDebug()<<__FILE__<<__LINE__ //#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__ //#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread() //#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd") # define LOG qDebug ( ) << __FILE__ << __LINE__ << QDateTime :: currentDateTime ( ) . toString ( "yyyy-MM-dd hh:mm:ss:zzz" ) FindDifferenceManager :: FindDifferenceManager (QObject *parent ) : QObject (parent ) , _running ( false ) { qRegisterMetaType <QList <QRect >> ( "QList<QRect> " ) ; } bool FindDifferenceManager :: getRunning ( ) const { return _running ; } void FindDifferenceManager :: slot_start ( ) { if (_running ) { LOG << "Failed to" << __FUNCTION__ << ", it's already running." ; return ; } _running = true ; } void FindDifferenceManager :: slot_stop ( ) { if ( !_running ) { LOG << "Failed to" << __FUNCTION__ << ", it's not running." ; return ; } _running = false ; } void FindDifferenceManager :: slot_findDiffrence (QImage image , QImage image2 , int thresh , QRect minRect ) { QList <QRect > listRect ; // 將QImage轉換為cv::Mat cv ::Mat srcMat = image2Mat (image ) ; cv ::Mat srcMat2 = image2Mat (image2 ) ; if ( (srcMat .rows != srcMat2 .rows ) || (srcMat .cols != srcMat2 .cols ) ) { emit signal_findResult ( false ) ; } cv ::Mat srcMatGray ; cv ::Mat srcMat2Gray ; // 轉灰度圖 cv :: cvtColor (srcMat , srcMatGray , cv ::COLOR_BGR2GRAY ) ; cv :: cvtColor (srcMat2 , srcMat2Gray , cv ::COLOR_BGR2GRAY ) ; // cv::imshow("1", srcMatGray); // cv::imshow("2", srcMat2Gray); cv ::Mat diffMatGray ; // 圖1減去圖2:檢視差異(灰度,可能差距不大,0-255, 0 1 2 3差距小看不出) cv :: subtract (srcMatGray , srcMat2Gray , diffMatGray , cv :: Mat ( ) , CV_16SC1 ) ; // 絕對值(有負數,變正數) // cv::imshow("3", diffMatGray); cv ::Mat diffAbsMatGray = cv :: abs (diffMatGray ) ; // 改變位深(歸一化試過,但是可能存在0和255,導致漏掉一些) diffAbsMatGray . convertTo (diffAbsMatGray , CV_8UC1 , 1 , 0 ) ; // cv::imshow("4", diffAbsMatGray); # if 0 // 整個畫素降低5個點的誤差(色差) for ( int row = 0 ; row < diffAbsMatGray .rows ; row ++ ) { for ( int col = 0 ; col < diffAbsMatGray .cols ; col ++ ) { if (diffAbsMatGray . at <uchar > (row , col ) < 3 ) { diffAbsMatGray . at <uchar > (row , col ) = 0 ; } else { diffAbsMatGray . at <uchar > (row , col ) = diffAbsMatGray . at <uchar > (row , col ) - 5 ; } } } # endif cv ::Mat threshMat ; //閾值處理 cv :: threshold (diffAbsMatGray , threshMat , thresh , 255 , cv ::THRESH_BINARY ) ; // cv::imshow("5", threshMat); cv ::Mat mdianMat ; # if 0 //中值濾波 cv :: medianBlur (threshMat , mdianMat , 3 ) ; cv :: imshow ( "6" , mdianMat ) ; # else mdianMat = threshMat . clone ( ) ; # endif cv ::Mat closeMat ; # if 0 // 閉運算: 用擬合小裂縫,消除小型黑洞,並且在平滑較大物體的邊界的同時不明顯改變其面積。 cv ::Mat kernel = cv :: getStructuringElement (cv ::MORPH_RECT , cv :: Size ( 3 , 3 ) , cv :: Point ( - 1 , - 1 ) ) ; cv :: morphologyEx (mdianMat , closeMat , cv ::MORPH_CLOSE , kernel , cv :: Point ( - 1 , - 1 ) , 2 , cv ::BORDER_REPLICATE ) ; # else closeMat = mdianMat . clone ( ) ; # endif // cv::imshow("7", closeMat); // 尋找邊界 std ::vector <std ::vector <cv ::Point >> contours ; std ::vector <cv ::Vec4i > hierarchy ; cv :: findContours (closeMat , contours , hierarchy , CV_RETR_EXTERNAL , CV_CHAIN_APPROX_SIMPLE , cv :: Point ( 0 , 0 ) ) ; std ::vector <std ::vector <cv ::Point >> contoursPoly (contours . size ( ) ) ; for ( int index = 0 ; index < contours . size ( ) ; index ++ ) { cv :: approxPolyDP (cv :: Mat (contours [index ] ) , contoursPoly [index ] , 5 , true ) ; cv ::Rect rect = cv :: boundingRect (cv :: Mat (contoursPoly [index ] ) ) ; # if 0 // 小於最小矩形則忽略 if (rect .width < minRect . width ( ) || rect .height < minRect . height ( ) ) { continue ; } # endif listRect . append ( QRect (rect .x , rect .y , rect .width , rect .height ) ) ; // cv::rectangle(srcMat, rect, cv::Scalar(0, 255, 0), 2); // cv::rectangle(srcMat2, rect, cv::Scalar(0, 255, 0), 2); } // cv::imshow("8", srcMat2); // cv::waitKey(0); emit signal_findResult ( true , listRect ) ; }cv ::Mat FindDifferenceManager :: image2Mat (QImage image ) { cv ::Mat mat ; switch (image . format ( ) ) { case QImage ::Format_ARGB32 : case QImage ::Format_RGB32 : case QImage ::Format_ARGB32_Premultiplied : mat = cv :: Mat (image . height ( ) , image . width ( ) , CV_8UC4 , ( void * )image . constBits ( ) , image . bytesPerLine ( ) ) ; cv :: cvtColor (mat , mat , CV_BGRA2BGR ) ; break ; case QImage ::Format_RGB888 : mat = cv :: Mat (image . height ( ) , image . width ( ) , CV_8UC3 , ( void * )image . constBits ( ) , image . bytesPerLine ( ) ) ; cv :: cvtColor (mat , mat , CV_BGR2RGB ) ; break ; case QImage ::Format_Indexed8 : case QImage ::Format_Grayscale8 : mat = cv :: Mat (image . height ( ) , image . width ( ) , CV_8UC1 , ( void * )image . constBits ( ) , image . bytesPerLine ( ) ) ; break ; default : qDebug ( ) << __FILE__ << __LINE__ << "error to image2Mat !!! imge.format =" << image . format ( ) ; } return mat ; }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70010283/viewspace-2894375/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 鴻蒙專案實戰(六):識別本地圖片鴻蒙地圖
- 人臉識別檢測專案實戰
- NLP專案實戰02:英文文字識別
- gitee 專案與倉庫的區別Gitee
- 圖片區域性識別怎麼操作
- 工作流應用程式型別的區別是什麼?型別
- GitHub車牌檢測識別專案調研Github
- dom選擇方法的區別
- jQuery實戰之 attr() 和 prop() 的區別jQuery
- C/S,B/S的應用的區別
- PWA 應用和原生應用的一些區別
- 專案與專案群管理:主要區別和相似之處
- PMP|論傳統專案與敏捷專案管理的區別敏捷專案管理
- oracle知識整理(1) union和union all的區別,left join和right join的區別(各種join的區別)Oracle
- 和區別
- #include <> ““區別
- 快取穿透、快取擊穿、快取雪崩區別快取穿透
- TensorFlow系列專題(六):實戰專案Mnist手寫資料集識別
- web應用servlet中Attribute、Parameter、InitParameter的區別WebServlet
- JS 應用篇(一):Undefined與Null的區別JSUndefinedNull
- 如何理解UDP 和 TCP? 區別? 應用場景?UDPTCP
- GPS、基站、IP定位的區別及其應用方向
- go的 & 和 * 的區別,以及應用場景Go
- 【知識分享】應用伺服器和web伺服器的區別伺服器Web
- 微調大型語言模型進行命名實體識別模型
- 交易型應用與消費類應用的區別 | infoworld
- js基本型別和引用型別區別JS型別
- 值型別與引用型別的區別型別
- HashMap底層實現原理/HashMap與HashTable區別/HashMap與HashSet區別HashMap
- 用神經網路來識別人物影象性別神經網路
- Android主專案和Module中R類的區別Android
- 幽默:新手與專家的區別
- 文字識別解決方案-OCR識別應用場景解析
- 微信小商店和微信小店區別是什麼?微信小商店和微信小店的區別
- __weak與__block區別,深層理解兩者區別BloC
- LinkedList和ArrayList的區別、Vector和ArrayList的區別
- http和https的區別/get和post的區別HTTP
- 肢體識別與應用