大恒MER-1070-10GC相机 LINUX环境 QT开发记录
大恒工业相机MER-1070-10GC开发记录
目录
- 前言
- 相机参数介绍
- 前期准备
- SDK下载
- 客户端软件调试
- 开发流程
- 1 QT配置文件
- 2 相机初始化
- 2.1 创建相机类
- 2.2 相机采集回调函数
- 2.3 编写采集线程
- 2.4 QLabel显示图片
- 总结
前言
实验室正好有一个大恒型号为MER-1070-10GC的面阵相机,于是便用该相机学习工业相机的开发,写下本篇博客作为开发记录,也当作学习之路的一次小小实践。
本次开发环境为Ubuntu18,开发软件为QT5,配合Opencv进行图像处理。主要完成相机的基本配置、初始化及打开,并且通过回调函数的方法获得图片,显示在UI界面。同时Opencv获取到图片,可以根据自己的要求进行图像处理。
相机参数介绍
详情见大恒相机官方文档 水星系列GIgE应用说明书
名称 | 参数 |
---|---|
型号 | MER-1070-10GC |
分辨率 | 3840 ×\times× 2748 |
像素深度 | 8bit、12bit |
快门时间 | 42μ\muμ ~ 1s |
图像数据格式 | Bayer GR8 / Bayer GR12 |
输入输出接口 | 1个光耦输入接口,一个光耦输出接口,2个双向GPIO |
数据接口 | 百兆以太网或千兆以太网 |
光谱相应图
前期准备
SDK下载
首先前往大恒相机官网下载相应软件开发SDK 大恒相机SDK下载地址。根据需求选择相应的选项,本次开发采用C/C++语言,因此下载第一个选项。
下载完成后在Linux中解压,在opt目录下有Galaxy_Linux-x86_Gige-U3_32bits-64bits_1.2.1911.9122文件夹,运行.run文件进行安装。bin文件夹内有客户端程序GalaxyView和IP配置软件GxGigeIPConfig,还有动态链接库文件,头文件在inc文件夹内,doc文件夹内有C软件开发说明书,里面有详细操作及编程介绍至此,SDK和客户端软件下载完成
客户端软件调试
相机上电,通过网线连接电脑,首先通过IP配置软件给相机配置IP地址,然后打开GalaxyView测试相机。在该软件中,可以调整相机的曝光、增益、白平衡、ROI区域、触发模式、采集模式等参数,最后可以导出配置文件,为后续开发提供便捷。
开发流程
C软件开发说明书已经上传到我的资源 大恒相机C软件开发说明书
1 QT配置文件
在QT正式开发前,需要将上述下载的API库加入.pro配置文件,否则是无法在程序中调用相机SDK的,同时将Opencv库加入配置文件。
# camera lib
LIBS += -L$$PWD/../../../../../usr/lib/libgxiapi.so -lgxiapiINCLUDEPATH += $$PWD/../../../../../opt/Galaxy_Linux-x86_Gige-U3_32bits-64bits_1.2.1911.9122/Galaxy_camera/inc
DEPENDPATH += $$PWD/../../../../../opt/Galaxy_Linux-x86_Gige-U3_32bits-64bits_1.2.1911.9122/Galaxy_camera/inc# opecncv
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_core
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_highgui
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_imgcodecs
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_video
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_videoio
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_shape
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lopencv_imgprocINCLUDEPATH += /usr/include/opencv2
DEPENDPATH += /usr/include/opencv2
2 相机初始化
2.1 创建相机类
为了方便相机操作,创建相机类。
class Camera
{public:Camera();uint32_t Enum_Camera(); //枚举相机 bool Open_Camera(); //打开相机bool Close_Camera(); //关闭相机bool Init_Camera(); //初始化相机/*注册回调函数*/bool Register_Callback_Fun();/*注销回调函数*/bool Unregister_Callback_Fun(); GX_DEV_HANDLE cam_handle = nullptr; //相机句柄
};
定义成员函数
#include "camera.h"
#include <QDebug>
#define DEVICE_INDEX_TO_OPEN "1"
extern void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame);Camera::Camera()
{}uint32_t Camera::Enum_Camera()
{GX_STATUS status = GX_STATUS_SUCCESS;status = GXInitLib(); //初始化库uint32_t nDeviceNum = 0;status = GXUpdateDeviceList(&nDeviceNum, 1000);if(status == GX_STATUS_SUCCESS && nDeviceNum > 0){GX_DEVICE_BASE_INFO *pBaseinfo = new GX_DEVICE_BASE_INFO[nDeviceNum];size_t nSize = nDeviceNum * sizeof(GX_DEVICE_BASE_INFO);status = GXGetAllDeviceBaseInfo(pBaseinfo, &nSize);if(status == GX_STATUS_SUCCESS){for(uint32_t i=0; i<nDeviceNum; i++){qDebug() << "No: " << i+1 << " camera enum successfully!";qDebug() << "szDeviceID: " << pBaseinfo[i].szDeviceID;qDebug() << "szDisplayName: " << pBaseinfo[i].szDisplayName;}delete []pBaseinfo;return nDeviceNum;}}elseqDebug() << "enum error!";return 1;
}bool Camera::Open_Camera()
{GX_STATUS status = GX_STATUS_SUCCESS;GX_OPEN_PARAM stOpenParam;stOpenParam.accessMode = GX_ACCESS_EXCLUSIVE;stOpenParam.openMode = GX_OPEN_INDEX;stOpenParam.pszContent = DEVICE_INDEX_TO_OPEN;status = GXOpenDevice(&stOpenParam, &cam_handle);if(status == GX_STATUS_SUCCESS){qDebug() << ">>>>>open camera success!>>>>>";return true;}elsereturn false;
}bool Camera::Close_Camera()
{GX_STATUS status = GX_STATUS_SUCCESS;status = GXUnregisterCaptureCallback(cam_handle); //注销采集回调函数if(status != GX_STATUS_SUCCESS)qDebug() << "unregister failed!!!" << endl;status =GXCloseDevice(cam_handle);if(status == GX_STATUS_SUCCESS){qDebug() << ">>>>>close camera success>>>>>";GXCloseLib(); //注销库return true;}elsereturn false;
}bool Camera::Init_Camera()
{uint32_t nDeviceNum = Enum_Camera();if(nDeviceNum == 0){qDebug() << ">>>>>init failed!>>>>>";return false;}if(Open_Camera()){qDebug() << ">>>>>init success!>>>>>";return true;}qDebug() << ">>>>>init failed!>>>>>";return false;
}bool Camera::Register_Callback_Fun()
{GX_STATUS status = GX_STATUS_SUCCESS;status = GXRegisterCaptureCallback(cam_handle, nullptr, OnFrameCallbackFun);if(status == GX_STATUS_SUCCESS)return true;elsereturn false;
}bool Camera::Unregister_Callback_Fun()
{GX_STATUS status = GX_STATUS_SUCCESS;status = GXUnregisterCaptureCallback(cam_handle);if(status == GX_STATUS_SUCCESS)return true;elsereturn false;
}
在初始化相机的时候可以设置相机采集图像的大小
GXSetInt(my_cam->cam_handle, GX_INT_WIDTH, 1024);GXSetInt(my_cam->cam_handle, GX_INT_HEIGHT, 768);
设置相机采集模式及触发模式,这里设置为连续采集且无触发,一旦发送开采命令,相机将连续采图,直到发送停采命令。
GX_STATUS status = GX_STATUS_SUCCESS;
status = GXSetEnum(my_cam->cam_handle, GX_ENUM_ACQUISITION_MODE,GX_ACQ_MODE_CONTINUOUS);
if(GX_STATUS_SUCCESS != status)qDebug() << "set acquisition mode failed..." << status << endl;
status = GXSetEnum(my_cam->cam_handle, GX_ENUM_TRIGGER_MODE, GX_TRIGGER_MODE_OFF);
if(GX_STATUS_SUCCESS != status)qDebug() << "set trigger mode failed...." << status << endl;
至此相机参数配置完成,初始化完成。
2.2 相机采集回调函数
相机触发后进入回调函数,用户可以在这里完成不同需求。本例展示在回调函数中接收相机内存的BAYER图,通过DxRaw8toRGB24
函数转换成RGB图,再转换到opencv::Mat类型的图像数据,在工作线程中通过cv::imshow显示图像。由于是连续触发,所以图片帧连续进入回调函数,我们在界面所看到的其实是视频流的形式。
因为回调函数频繁地进入,所以我将显示图片过程放在下面2.3节的工作线程中,防止在回调函数中imshow函数调用花费大量时间导致图片帧卡死。回调函数里只做相机内存和计算机内存间图像的拷贝工作。
#include "thread.h"
#include <QDebug>
#include "widget.h"int64_t nPayLoadSize;
unsigned char *pRGB24Buf;
unsigned char *pRawBuf;
cv::Mat img_buff;
cv::Mat img;
int count = 0;/*图像回调处理函数*/
void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame)
{if(pFrame->status == GX_FRAME_STATUS_SUCCESS){qDebug() << ">>>>>entered the callback fun!>>>>>";/*打印图片长宽信息*/
// qDebug() << "width: " << pFrame->nWidth << "height" << pFrame->nHeight;memcpy(pRawBuf, pFrame->pImgBuf, pFrame->nImgSize);DxRaw8toRGB24(pRawBuf, pRGB24Buf, pFrame->nWidth,pFrame->nHeight, RAW2RGB_NEIGHBOUR,BAYERRG, false);memcpy(img.data, pRGB24Buf, 1024*768*3); //img为cv::Mat格式qDebug() << "frame: " << count++; //显示已拍摄的帧数}return;
}
全局变量 *pRGB24Buf
和 *pRawBuf
的初始化见2.3节工作线程中。
2.3 编写采集线程
建立thread.h头文件,创建工作线程类,以及定义回调函数(回调函数中也是开启一个单独的线程进行处理,故这里将它算在线程文件中)
#include "thread.h"
#include <QDebug>
#include "widget.h"int64_t nPayLoadSize;
unsigned char *pRGB24Buf;
unsigned char *pRawBuf;cv::Mat img_buff;
cv::Mat img;
int count = 0;Start_Work::Start_Work(QObject *parent) : QThread (parent)
{my_cam = new Camera();
}Start_Work::~Start_Work()
{if(my_cam != nullptr)delete my_cam;
}void Start_Work::run()
{bool IsOk = false;IsOk = my_cam->Init_Camera();if(!IsOk)qDebug() << "init camera failed" << endl;GX_STATUS status = GX_STATUS_SUCCESS;GXSetInt(my_cam->cam_handle, GX_INT_WIDTH, 1024);GXSetInt(my_cam->cam_handle, GX_INT_HEIGHT, 768);GXGetInt(my_cam->cam_handle, GX_INT_PAYLOAD_SIZE, &nPayLoadSize);pRawBuf = new unsigned char[nPayLoadSize];pRGB24Buf = new unsigned char[1024*768*3];img.create(768, 1024, CV_8UC3); //创建cv::MatIsOk = my_cam->Register_Callback_Fun();if(!IsOk)qDebug() << "register failed!" << endl;/*发送采集命令*/status = GXSendCommand(my_cam->cam_handle, GX_COMMAND_ACQUISITION_START);if(GX_STATUS_SUCCESS != status)qDebug() << "send command error..." << endl;qDebug() << "start_work thread going...." << endl;/*连续显示300帧图片,然后退出循环,发送停采命令*/while(1){cv::imshow("test", img);if(count == 300)break;}status = GXSendCommand(my_cam->cam_handle, GX_COMMAND_ACQUISITION_STOP);if(status == GX_STATUS_SUCCESS){IsOk = my_cam->Close_Camera();if(!IsOk)qDebug() << "close camera error!!!!" << endl;elseqDebug() << "close camera success" << endl;}/*释放内存!*/if(pRawBuf != nullptr){delete [] pRawBuf;pRawBuf = nullptr;}if(pRGB24Buf != nullptr){delete [] pRGB24Buf;pRGB24Buf = nullptr;}
}
进入300次回调函数,显示300帧图片,测试成功。
此时cv::Mat格式的图片也采集到,可以结合要求进行处理
2.4 QLabel显示图片
使用QT开发时肯定不希望用opencv的imshow来显示,将图片显示在UI界面才是正确的。接下来就来完成这件事。首先在widget.ui放置一个QLabel,然后在widget.h和widget.cpp中申明定义slot槽函数:showimage(cv::Mat)
,参数是cv::Mat变量。这个函数负责在收到emit信号后在QLabel对象pic_show上显示图片。
void Widget::showimage(cv::Mat img)
{cv::cvtColor(img, img, CV_BGRA2RGB);const unsigned char *pSrc = (const unsigned char*)img.data;QImage image(pSrc, img.cols, img.rows, img.step, QImage::Format_RGB888);pix = QPixmap::fromImage(image.scaled(ui->pic_show->width(),ui->pic_show->height(),Qt::KeepAspectRatio));ui->pic_show->setPixmap(pix);ui->pic_show->show();
}
在thread.h的Start_Work类中申明信号send_image(cv::Mat)
signals:void send_image(cv::Mat);
同时在widget类的构造函数中绑定信号和槽
connect(start_thread, SIGNAL(send_image(cv::Mat)), this, SLOT(showimage(cv::Mat)),Qt::BlockingQueuedConnection);
最后一步替换2.3节中Start_Work::run()
中while(1)中的内容,在循环中emit发送信号即可
while(1)emit send_image(img);
编译运行,调试结果如下
总结
以上就是关于大恒相机的C语言SDK下的初步开发流程,我们完成了采集图片,抓取图片,转换为Opencv::Mat格式,显示图片的功能。Mat格式的图片方便利用Opencv对图像进行后续处理。
除此之外,在后续开发过程中,要注意多线程开发中对全局图片变量的加锁处理,以防止多个线程对资源的争夺,可以采用信号量的方法建立图片缓存区,保证线程之间不冲突。
大恒MER-1070-10GC相机 LINUX环境 QT开发记录相关推荐
- 2 Linux环境基础开发工具
2 Linux环境基础开发工具 2.1 Linux软件包管理器yum 2.1.1 软件安装的方式 1. 源码安装 大多数开源的软件都是源码的形式.拿过来自己编译,安装. 优点:源码安装兼容性好. 缺点 ...
- 【Linux】Linux环境基础开发工具使用 —— yum | vim | gcc g++ | gdb | make makefile | 进度条 | git
Linux环境基础开发工具使用 1. Linux软件包管理器yum 1.1 什么是软件包 1.2 软件安装三板斧 1.2.1 查看软件包 1.2.2 安装软件 1.2.3 卸载软件 2. vim 2. ...
- 【Linux】基础:Linux环境基础开发工具——make与Makefile
[Linux]题解:Linux环境基础开发工具--make与Makefile 摘要:Makefile是一个文件定义了一系列的规则来指定编译过程以及更复杂的功能操作,make是一个命令工具,是一个解ma ...
- linux 基于qt开发的音乐,Linux下用QT开发音乐播放器.pdf
嵌入式课程设计报告 - Linux 在 下开发音乐播放器 李荣贵 141578 一.概述 按课程要求,在Linux环境下开发了一款简易的音乐播放器软件, Mini 名为 " 音乐播放器&qu ...
- 大恒工业相机搭建双目相机(软件)
本文主要介绍使用大恒工业水星139相机搭建双目相机的软件过程.以下主要介绍相机采集图像以及保存的过程. #include <vector> #include <string> ...
- Linux环境下开发板Tiny4412应用,实现交叉编译及minicom的调配,将代码编译后下载到开发板并运行
一.实验目的 1.熟悉Linux环境,学习使用命令行操控计算机系统,学会基础的ubuntu机器操作. 2.初步学习使用开发板Tiny4412,查看实验说明以及开发板说明书,学习基本使用步骤. 3.安装 ...
- 【Linux环境基础开发工具】软件包管理器-yum
写在前面 今天我打算介绍如何在Linux环境下载软件, Linux作为一个操作系统,就像windows一样,当然是存在软件的. 目录 写在前面 怎么在Linux环境安装软件 源代码安装 rpm安装包安 ...
- PyCharm采用Docker镜像直接进行Linux环境项目开发
前言:因为本地是windows环境,之前开发工具的时候,都是先写windows版本,上服务器的时候再改linux相关参数目录等等,版本迭代控制非常恶心.docker直接搞定可以本地开发,完成之后打包上 ...
- linux环境qt输入框不能切换中文输入法是什么原因
如果 Linux 环境下使用 Qt 应用程序时输入框不能切换到中文输入法,这可能是因为没有安装相应的输入法软件或没有将输入法与 Qt 应用程序正确集成. 在 Linux 上常用的中文输入法有 ibus ...
- linux环境QT做静态库,QT静态库的创建与使用
最近研究一下静态库的开发: 最初学习的资料是: QT静态库的创建与使用(全网最细)_路漫漫其远,吾求索的博客-CSDN博客_qt生成静态库 建立一个静态库成功. 我这里总结一下: 1,如果同时打开静态 ...
最新文章
- luogu P4258 [WC2016]挑战NPC(一般图的最大匹配,带花树,建图、拆点技巧)
- R语言:生成正态分布数据生成--rnorm,dnorm,pnorm,qnorm
- Week2 Teamework from Z.XML 软件分析与用户需求调查(四)Bing桌面及助手的现状与发展...
- 生成有控制台的WIN32程序
- 【数据结构与算法】之深入解析“正则表达式匹配”的求解思路与算法示例
- idea(mac) 使用收集
- python控制树莓派相机_玩转树莓派-Raspberry,控制单反相机进行可编程摄影
- vasp计算脚本放在服务器的位置,vasp计算所需服务器配置
- 12V升压100V,12V升压200V,300V电源转换升压模块
- 《Erlang/OTP并发编程实战》第八章 分布式 Erlang/OTP 简介
- adb inputswipe shell_[Android]通过adb shell input上报命令模拟屏幕点击事件【转】
- Deep Unordered Composition Rivals Syntactic Methods for Text Classification
- 如果iPhone被标记被盗或丢失 苹果将拒绝维修
- spring --jia包依赖坐标收集
- 梦幻古龙服务器 文档,梦幻古龙GM命令大全较完整
- 时间的基本概念及GPS北斗卫星时钟授时技术
- 手机qq2.0 for android,QQ农场手机版|QQ农场for Android 2.02 官方安装版_手机游戏 www.qqtn.com...
- jquary学习(一)jquary简介
- 某马程序员NodeJS速学笔记
- Manjaro deepin 睡眠后无法唤醒