基于Qt自定义视觉界面
函数库依赖
1、头文件
- gt_display.h 用于显示图像和图像控件的库
- result_type.h 定义图像数据结构和结果数据结构
- workflow_list.h 函数调用头文件
必要函数接口
1、回调函数,用于接受库内运行时的一帧图像数据
void(*CallbackFun)(const GtMat *image, void *user, int ccd_index);
2、工程设置相关函数
int getMdlCount();
bool setMdlParam(int mdl_position, const QJsonObject &json); //参数设置,mdl_position是模块在流程中的位置
下面两个函数是读取和保存本地绝对路径下工程配置
bool saveProject(const QString &path);//保存工程
bool readProject(const QString &path);//读取本地工程
该函数是启动workflow运行的函数,第一个参数是通过getMDLCount()函数返回,如果是true就表示当前的workflow里面没有功能模块,当前工作流只是能拍照,false就是包含有其他功能模块,第二个参数是运行模式,true是自动循环,false是触发或者运行有限次数模式,第三个参数的意思是运行有限次模式下的次数,无限模式下此参数无效。
bool startProcess(bool capture_only, bool run_forever, int count); // 当仅采集时,capture_only为true,当一直运行的时候,run_forever为true,否则设置运行帧数count即可
bool stopProcess(); // 停止运行
int getLastError(); //获取错误码
3、相机操作相关函数
该函数扫描本地可使用的相机名字信息,返回一个QStringList的结果
QStringList scanCamera(void);
该函数使用上一步扫描到的结果来连接相机,返回值为bool类型,相机连接成功就返回true,否则就返回false
bool connectCamera(const QString name);
4、获取结果相关函数
该函数功能是获取指定模块可用来绘图的图片内容地址指作为,做为display等绘图控件的输入信息
DrawableResult *getDrawableResultPtr(int position);
5、绘图相关函数
该函数是在开始运行workflow之前打开workflow中带有绘制结果功能模块的使能,以便matchshape模块在计算出结果后,自动把结果坐标和ROI局域自动绘制到display的控件上
void startDrawResult(DrawableResult *result);
void stopDrawResult();
该函数是向workflow里注册一个回调函数,当workflow运行完毕的时候,会主动调用此函数,通知外层代码以便进一步处理
bool registerCallback(CallbackFun fun, void *user);
6、设置MatchShape的JSON参数JObject
"MdlParam": {
"angle_step": 1, //特征角度最小步进
"end_angle": 30, //搜索截止角度
"high_thresh": 0, //roi 特征提取阀值上限
"levels": 5, //图像搜索的层数
"low_thresh": 0, //roi特征提取阀值下限
"min_score": 0.800000011920929, //特征匹配的最小匹配百分比
"pattern_rect": [ //roi区域的范围
582,
585,
336,
343
],
"search_number": 1, //特征目标个数
"start_angle": -30, //搜索起始角度
"use_subpixle": true //图像使用亚像素精度
},
函数操作流程
1、读取本地工程,同步界面参数,建立workflow
bool flag = workflow_list->readProject(item_path);
2、 扫描本地相机,同步界面或者确定所使用的相机
camera = workflow_list->scanCamera();
3、保存界面参数到本地JSON配置文件并设置到workflow
workflow_list->setMdlParam(0, json);
workflow_list->saveProject(item_path);
4、注册回调函数关联信号槽启动display绘图功能并启动workflow
ui.display_lay->addWidget(display->createDisplay());//把display的widget添加到一个laylout上
bool is_capture = workflow_list->getMdlCount() == 0;
display->startDrawResult(workflow_list->getDrawableResultPtr(0));
workflow_list->registerCallback(dealResult,this);
connect(display, &GtDisplay::signalUpdateDefaultItem, this, &MatchShapeLite::slotUpdateRoi);
success = workflow_list->startProcess(is_capture, true,0);
5、关闭display绘图工程停止workflow并解除信号连接
display->stopDrawResult();
disconnect(display, &GtDisplay::signalUpdateDefaultItem, this, &MatchShapeLite::slotUpdateRoi);
workflow_list->stopProcess();
代码示例
1、MatchShapeLite.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_MatchShapeLite.h"
#include "gt_display.h"
#include "workflow_list.h"
#include "result_type.h"
#include <QJsonObject>
/*
*回调函数指针声明设置
*/
typedef void(*CallbackFun)(const GtMat *image, void *user, int ccd_index);
class MatchShapeLite : public QMainWindow
{
Q_OBJECT
public:
MatchShapeLite(QWidget *parent = Q_NULLPTR);
~MatchShapeLite();
void openProjectPath(const QString &path);
static void dealResult(const GtMat *image, void *user, int index);
public slots:
void slotopen();
void slotrun();
void slotquit();
void slotsave();
void slotUpdateRoi(bool valid, double reserve0, double reserve1,
double reserve2, double reserve3, double reserve4, QString &name);//display里面roi设置变更信号回调信号槽函数
void slotscan();
void slotconnect();
/*
*下面四个信号和槽函数用于线程里使用信号和槽机制,否则不予不同线程的函数将无法使用
*/
void slotupdate(QPixmap map);//这里带参数的信号和槽函数必须使用参数的值复制的形式,引用无效
void slotresult();
signals:
void signupdate(QPixmap map);
void signresult();
private:
Ui::MatchShapeLiteClass ui;
WorkflowList *workflow_list; //必要的工作流配置对象
GtDisplay * display; //必要的界面显示对象
QString item_path; //工程打开路径保存
QJsonObject json; //工作配置临时保存
QStringList camera; //链接相机信息保存
QStatusBar *sBar; //增加状态栏
QLabel *label; //状态栏里面用于显示结果
char *image_data_; //图像原始数据保存位置
QPixmap map; //回调参考图片复制到map
};
2、MatchShapeLite.cpp
#include "MatchShapeLite.h"
#include <QFileDialog>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QPixmap>
#include <QDebug>
#include <QMessageBox>
#include <QStatusBar>
MatchShapeLite::MatchShapeLite(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//this->setWindowOpacity(0.7);
//this->setWindowFlags(Qt::FramelessWindowHint);
ui.run->setEnabled(false);
ui.quit->setEnabled(false);
ui.connect->setEnabled(false);
workflow_list = new WorkflowList;//创建工作流对象
display = new GtDisplay;//创建显示widget
connect(display, &GtDisplay::signalUpdateDefaultItem, this, &MatchShapeLite::slotUpdateRoi);//设置显示widget里面roi窗口的设置变动信号
ui.display_lay->addWidget(display->createDisplay()); //向一个已知的布局中加入显示widget
connect(ui.openfile,&QPushButton::clicked,this,&MatchShapeLite::slotopen);
connect(ui.run,&QPushButton::clicked,this,&MatchShapeLite::slotrun);
connect(ui.quit,&QPushButton::clicked,this,&MatchShapeLite::slotquit);
connect(ui.save,&QPushButton::clicked,this,&MatchShapeLite::slotsave);
connect(ui.scan,&QPushButton::clicked,this,&MatchShapeLite::slotscan);
connect(this, &MatchShapeLite::signupdate, this, &MatchShapeLite::slotupdate);
connect(this, &MatchShapeLite::signresult,this,&MatchShapeLite::slotresult);
json["levels"] = 5;
json["search_number"] = 1;
json["min_score"] = 0.8;
json["use_subpixle"] = true;
json["low_thresh"] = 0;
json["high_thresh"] = 0;
json["start_angle"] = -30;
json["end_angle"] = 30;
json["angle_step"] = 1;
QJsonArray pattern_arr;
pattern_arr.append(50);
pattern_arr.append(50);
pattern_arr.append(100);
pattern_arr.append(100);
json["pattern_rect"] = pattern_arr;
sBar = statusBar();
label = new QLabel(this);
sBar->addWidget(label);
label->setText("result::");
image_data_ =(char*)malloc(15052800);
}
MatchShapeLite::~MatchShapeLite()
{
if (display)
{
delete display;
display = NULL;
}
}
void MatchShapeLite::slotopen()
{
QString default_path = "Data/projects";
QString path = QFileDialog::getExistingDirectory(this, tr("Open Project Directory"), default_path);
if (path == "" || path.isNull())
{
return;
}
QDir dir(path);
item_path = dir.absolutePath();
if (dir.exists())
{
bool flag = workflow_list->readProject(item_path);
if (!flag)
{
return;
}
}
QJsonObject json_object;
QJsonDocument json_document;
path = item_path + "/module_info.json";
QFile file(path);
QByteArray byteArray;
if (!file.open(QIODevice::ReadOnly))
{
return;
}
byteArray = file.readAll();
QJsonParseError jsonErr;
json_document = QJsonDocument::fromJson(byteArray, &jsonErr);
if (jsonErr.error != QJsonParseError::NoError && json_document.isNull())
{
file.close();
return;
}
file.close();
json_object = json_document.object();
QJsonObject CameraInfo,MdlParam,MdlInfo;
QJsonArray MdlInfos,pattern_rect;
CameraInfo = json_object.value("CameraInfo").toObject();
MdlInfos = json_object.value("MdlInfos").toArray();
MdlInfo = MdlInfos.at(0).toObject();
MdlParam = MdlInfo.value("MdlParam").toObject();
pattern_rect = MdlParam.value("pattern_rect").toArray();
json = MdlParam;
ui.s_angle->setText(QString("%1").arg((int)MdlParam.value("start_angle").toDouble()));
ui.l_angle->setText(QString("%1").arg((int)MdlParam.value("end_angle").toDouble()));
ui.m_score->setText(QString("%1").arg(MdlParam.value("min_score").toDouble()));
ui.m_num->setText(QString("%1").arg(MdlParam.value("search_number").toInt()));
if (!CameraInfo.value("EmulateModeStatus").toBool())
{
bool rtn;
QString pix_path = item_path + "/ReferImage/0.bmp";
QPixmap pix;
rtn = pix.load(pix_path);
display->setImage(pix);
}
QRect roi(pattern_rect.at(0).toInt(), pattern_rect.at(1).toInt(), pattern_rect.at(2).toInt(), pattern_rect.at(3).toInt());
display->addRectItem("target",roi);
ui.run->setEnabled(true);
}
void MatchShapeLite::slotsave()
{
json["search_number"] = ui.m_num->text().toInt();
json["min_score"] = ui.m_score->text().toDouble();
json["start_angle"] = ui.s_angle->text().toInt();
json["end_angle"] = ui.l_angle->text().toInt();
bool rtn = workflow_list->setMdlParam(0, json);
workflow_list->saveProject(item_path);
}
void MatchShapeLite::slotrun()
{
json["search_number"] = ui.m_num->text().toInt();
json["min_score"] = ui.m_score->text().toDouble();
json["start_angle"] = ui.s_angle->text().toInt();
json["end_angle"] = ui.l_angle->text().toInt();
bool is_capture = workflow_list->getMdlCount() == 0;
display->startDrawResult(workflow_list->getDrawableResultPtr(0));
workflow_list->registerCallback(dealResult,this);
bool success = workflow_list->setMdlParam(0, json);
success = workflow_list->startProcess(is_capture, true,0);
if (!success)
{
return;
}
if (workflow_list->isRunning())
{
ui.run->setEnabled(false);
ui.quit->setEnabled(true);
}
else
{
}
}
void MatchShapeLite::slotquit()
{
display->stopDrawResult();
workflow_list->stopProcess();
ui.run->setEnabled(true);
ui.quit->setEnabled(false);
}
void MatchShapeLite::slotUpdateRoi(bool valid, double reserve0, double reserve1,
double reserve2, double reserve3, double reserve4, QString &name)
{
if (valid)
{
QJsonArray pattern_arr;
pattern_arr.append(reserve0);
pattern_arr.append(reserve1);
pattern_arr.append(reserve2);
pattern_arr.append(reserve3);
json["pattern_rect"] = pattern_arr;
}
}
void MatchShapeLite::dealResult(const GtMat *image, void *user, int index)
{
int size = image->rows * image->cols * image->channel;
if (size > 15052800)
{
return;
}
if (user == nullptr || image->image_data == nullptr)
{
return;
}
MatchShapeLite *lite = static_cast<MatchShapeLite*>(user);
if (lite == nullptr)
{
return;
}
memcpy(lite->image_data_, image->image_data, size);
lite->map = QPixmap::fromImage(QImage((uchar*)lite->image_data_,
image->cols, image->rows, image->cols * image->channel,
image->channel == 3 ? QImage::Format_RGB888 : QImage::Format_Indexed8));
emit lite->signupdate(lite->map);
emit lite->signresult();
}
void MatchShapeLite::slotscan()
{
camera = workflow_list->scanCamera();
if (camera.length())
{
ui.camershow->addItems(camera);
ui.connect->setEnabled(true);
}
}
void MatchShapeLite::slotconnect()
{
QString str = ui.camershow->currentText();
bool rtn = workflow_list->connectCamera(str);
}
void MatchShapeLite::slotupdate(QPixmap map)
{
display->setImage(map);
}
void MatchShapeLite::slotresult()
{
QStringList res = workflow_list->getMdlResultList(0);
QString show;
for (int i = 0; i < res.length(); i++) show.append(res.at(i));
label->setText(show);
}