基于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);
}

QT界面示例

图片