项目实战:Qt+OpenCV大家来找茬(Qt抓图,穿透应用,识别左右图区别,框选区别,微调位置)
前言
本项目的出现理由只是笔者的一个念头,于是利用专业Qt和Opencv相关的知识开发一个辅助工具,本文章仅用于Qt和Opencv结合的学习。
Demo演示效果
运行包下载地址(供测试学习)
CSDN粉丝0积分下载地址:https://download.csdn.net/download/qq21497936/85372782
QQ群下载地址:1047134658(点击“文件”搜索“findTheDifference”,群内与博文同步更新)
运行包+源码包下载地址(供测试学习)
CSDN下载地址:https://download.csdn.net/download/qq21497936/85372767
(注意:源码本博客后面都有,若是想一步到位,下载这个,源码编译版本为Qt5.9.x mingw32 + openCV3.4.10)
功能列表
- 应用程序可将某Q游戏界面套入内部区域,游戏方便操作;
- 抓图区域调整,可通过右上角区域,调整区域1和区域2的位置;
- 位置微调功能,点击按钮可像对应方向微调一个像素;
- 识别不同,调用opencv算法,识别不同处在游戏图上绘制显示区域;
- 游戏界面区域操作焦点为游戏界面;
- 可清空已经绘制的区域;
Qt技术点
- Qt窗口部分透明
《Qt实用技巧:实现不规则窗口的鼠标消息穿透,包括穿透到桌面和穿透到父窗口》; - Qt窗口透明区域鼠标穿透
《Qt实用技巧:使用非透明窗体鼠标穿透到桌面的设置方法》; - Qt窗口置顶
《Qt实用技巧:Qt窗口置顶》; - Qt绘图
《Qt开发技术:Qt绘图系统(一)绘图系统介绍》
《Qt开发技术:Qt绘图系统(二)QPainter详解》; - Qt双窗口叠加(底窗口+透明窗口层)
《Qt实用技巧:实现窗口透明的五种方法》中的方法五; - QLabel,QGroupBox,QSpinBox,QPushButton控件的使用
- Qt截取屏幕
《Qt实用技巧:截屏功能的实现》
OpenCV技术点
- OpenCV开发环境的搭建
《OpenCV开发笔记(〇):使用mingw530_32编译openCV3.4.1源码,搭建Qt5.9.3的openCV开发环境》 - OpenCV中的cv::Mat
《OpenCV开发笔记(三):OpenCV图像的概念和基本操作》 - OpenCV中QImage转换为cv::Mat
- OpenCV灰度化
《OpenCV开发笔记(六):OpenCV基础数据结构、颜色转换函数和颜色空间》 - OpenCV阈值化
《OpenCV开发笔记(二十八):带你学习图像识别之阈值化》 - OpenCV的中值滤波
《OpenCV开发笔记(十八):算法基础之非线性滤波-中值滤波》 - OpenCV的闭运算
《OpenCV开发笔记(二十四):算法基础之形态学滤波-闭运算》 - OpenCV的寻找边界
《OpenCV开发笔记(二十八):带你学习图像识别之阈值化》 - OpenCv的最小矩形
《OpenCV开发笔记(五十六):红胖子8分钟带你深入了解多种图形拟合逼近轮廓(图文并茂+浅显易懂+程序源码)》
项目模块化部署
项目的环境为Qt5.9.3 mingw32版本,使用QtCreator开发,配合mingw32版本的Opencv3.4.10,下图左侧为项目结构,右侧为实际文件夹部署结构。
Qt代码:DrawWdget
该类的主要作用:
- 覆盖在游戏窗口上
- 全部透明窗口用以当作游戏界面上的画布
- 对鼠标消息穿透(无法点击中)
- 识别出后绘制标记处不同的区域
Ui界面
为自动生成默认的,没有任何改动。
一共绘制两类图形,一类是框出抓取图的界面,一类是识别出后的区域,定义两个缓存变量,用以绘制对应的区域矩形。
DrawWidegt.h
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H
#include <QWidget>
namespace Ui {
class DrawWidget;
}
class DrawWidget : public QWidget
{
Q_OBJECT
public:
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
该类的主要作用:
- 作为主窗口提供一个套入找茬游戏界面的区域;
- 提供可以动态选取抓取区域的控件;
- 提供微调控件,微调应用窗口,并且让DrawWidget窗口与透明区域位置同步改变;
- 提供识别触发按钮,将识别结果反馈到DrawWidget;
- 清空按钮,将识别的结果进行清空,也就是删除识别结果的矩形;
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_OBJECT
public:
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
识别不同处代码类功能:
- 引入OpenCV头文件和库文件
- 提供接口输入2个同样大小的矩形、阈值和能识别的最小矩形。
- 核心算法:先灰度图->阈值化->寻找边界->识别最小矩形
(最开始算法进行了滤波,闭运算,因为实际有可能存在两幅图截屏就有色差导致灰度图色差小,实际有可能原图色差较小导致灰度色差较小,实际有可能不同的点较少导致滤波去掉了这些点,以上三种经过测试都是存在的)。
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_OBJECT
public:
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;
}
项目实战:Qt+OpenCV大家来找茬(Qt抓图,穿透应用,识别左右图区别,框选区别,微调位置)的更多相关文章
- 项目实战:Qt+Ffmpeg+OpenCV相机程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- 【QT】找茬外挂制作
找茬外挂制作 找茬游戏大家肯定都很熟悉吧,两张类似的图片,找里面的不同.在下眼神不大好,经常瞪图片半天也找不到区别.于是乎决定做个辅助工具来解放一下自己的双眼. 一.使用工具 Qt:主要是用来做界面的 ...
- 【大话QT之十六】使用ctkPluginFramework插件系统构建项目实战
"使用ctkPluginFramework插件系统构建项目实战",这篇文章是写博客以来最纠结的一篇文章. 倒不是由于技术都多么困难,而是想去描写叙述一个项目架构採用ctkPlugi ...
- 项目实战:Qt手机模拟器拉伸旋转框架
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)
Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码) 转 https://blog.csdn.net/lhl1124281072/article/details/800 ...
- QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL
QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL 课程1 C语言程序设计高级实用速成课程 基础+进阶+自学 课程2 C语言程序设计Windows GDI图形绘 ...
- Win10下部署VS+Qt+OpenCV+darknet(YOLO)集成环境
VS+Qt集成环境 下载VS与Qt并安装. VS:官网链接 Qt:下载链接 将Qt的bin目录加入PATH路径 bin目录举例:D:\development\Qt\5.12.0\msvc2017_64 ...
- 给缺少Python项目实战经验的人
我们在学习过程中最容易犯的一个错误就是:看的多动手的少,特别是对于一些项目的开发学习就更少了! 没有一个完整的项目开发过程,是不会对整个开发流程以及理论知识有牢固的认知的,对于怎样将所学的理论知识应用 ...
- 【腾讯Bugly干货分享】React Native项目实战总结
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e16a7640ad7b4682c64a7 “8小时内拼工作,8小时外拼成长 ...
随机推荐
- 学习RabbitMQ(三)
1 用户注册后(会立即提示注册成功),过一会发送短信和邮件通知 发布/订阅模型 以上模式一般是用户注册成功后,写入一条数据到mysql,在发送一条消息到MQ! 如果不用消息中间件(或者简单的做成异步发 ...
- 遇到的错误之"Exception in thread “main“ java.lang.NoClassDefFoundError: org/apache/velocity/context/Context at"
问题 Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/velocity/context/ ...
- 使用Visual Studio查看C++类内存分布
书上类继承相关章节到这里就结束了,这里不妨说下C++内存分布结构,我们来看看编译器是怎么处理类成员内存分布的,特别是在继承.虚函数存在的情况下. 工欲善其事,必先利其器,我们先用好Visual Stu ...
- Azure DevOps 中 Dapr项目自动部署流程实践
注:本文中主要讨论 .NET6.0项目在 k8s 中运行的 Dapr 的持续集成流程, 但实际上不是Dapr的项目部署到K8s也是相同流程,只是k8s的yaml配置文件有所不同 流程选择 基于 Dap ...
- 使用Bootstrap typeahead插件实现搜索框自动补全的配置参数。
示例代码: <input type="text" id="addr"/> <input type="text" hidde ...
- 【Android开发】简单好用的阴影库 ShadowLayout
先来看一张使用 ShadowLayout 库实现的各种阴影的效果图,如下图所示: 如上图所示,通过使用 ShadowLayout 可以控制阴影的颜色.范围.显示边界(上下左右四个边界).x 轴和 y ...
- try、catch、finally、return的执行顺序
1. 不管有没有异常,finally里面的语句都会执行 2. 当try和catch中有返回语句时,finally里面的语句还是会执行 3. 如果finally里面没有return语句,try和catc ...
- python---选择排序的实现
选择排序 思想 一趟遍历记录最小的数, 放到第一个位置 再一趟遍历记录剩余列表中最小的数, 继续放置 关键点: 无序区: 第i趟, 无序区为 i~n-1 最小数的位置 import r ...
- ssm整合-ssmbuild
目录 项目结构 导入相关的pom依赖 Maven资源过滤设置 建立基本结构和配置框架 Mybatis层编写 Spring层 Spring整合service层 SpringMVC层 Controller ...
- 讲解CPU之NUMA硬件体系以及机制(lscpu查看相关信息)
先看看从系统层面反映出来的numa cpu信息.采样机器为实体机.80核.128内存. [root@ht2 src]# lscpu Architecture: x86_64 #x86架构下的64位 C ...