大恒水星相机开发记录
前面的话:
最近搞了一个大恒的相机MER-500-14GC,本着这可是行业龙头的工业相机嘛,终归是在学校摸到了真正的工业级产品了。(٩(๑>◡<๑)۶)
想着用opencv调用相机(主要是对opencv比较熟悉嘛,教程也多),不过就是videoCapture嘛,如果是usb口,那直接给编号就可以了,如果的Gige口,那根据规则编一个rtsp流的url就行了嘛,之前海康的相机就是这么用的。但是大恒不提供这个接口。。。o(╥﹏╥)o
阿西吧,这相机绝对是我用过的最难用的相机了。。。(也可能是我c++和Visual Studio用的不熟练吧,我一般都用Clion的,也有可能是大恒都用HALCON的,我还没学这个软件)
目标
本文主要记录博主使用大恒MER-500-14GC相机自己开发,目标环境是linux和QT(c++)
Windows
windows(c++)下的准备工作
- 准备相机啦
- 去官网下资料:这资料里自带文档这里下的是windows的,毕竟官方文档提供的是windows的例程。
- 安装啦
- 准备好Visual Studio
- 在Visual Studio中新建一个项目,这个项目要和opencv链接好,不会的教程看这个大佬写的超级好
- 大恒sdk在VS下环境配置,这个在大恒的资料中就有官方文档,但是有点小错,我这里在重复一遍
-
在解决方案资源管理窗口中选中用户创建的工程,然后点击菜单中的project->properties弹出Property page窗口。
选择Configuration Properties->C/C++ ->General在Additional Include Directories中填写GalaxyIncludes.h所在目录路径地址(依用户安装目录为准)。我的GalaxyIncludes.h路径是:G:\GalaxySDK\Samples\C++ SDK\inc。环境是X64的环境,记着那个opencv的环境也是X64,最后编译环境也是X64
-
配置lib文件
然后选择Configuration Properties->Linker->General在Additional Library Directories中填写GxIAPICPPEx.lib所在目录路径地址(依用户安装目录为准)。我的是:G:\GalaxySDK\Samples\C++ SDK\lib\x64
然后选择Configuration Properties->Linker->Input在Additional Dependencies中填写GxIAPICPPEx.lib
,并不像图中这样啊
VS(c++)中调用相机
首先先说官方文档提供的例程:
这个例程在改了一些代码中各种的小错后,我始终是运行不起来,总是报错,错误代码-8,如下
阿西吧,为啥啊??趟坑路上处处是雷Σ_(꒪ཀ꒪」∠)
大佬的代码
这里的原文参考自这里:感谢这位大佬拯救了我
- 首先在这个路径G:\GalaxySDK\Samples\C++ SDK\inc下的gxsmartptr.h中添加一行
#include "GalaxyException.h"
- 然后上代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include "GalaxyException.h"
//using namespace cv;
using namespace std;
#include <GalaxyIncludes.h>
cv::Mat img;
//用户继承掉线事件处理类
class CSampleDeviceOfflineEventHandler : public IDeviceOfflineEventHandler
{
public:
void DoOnDeviceOfflineEvent(void* pUserParam)
{
cout << "收到设备掉线事件!" << endl;
}
};
//用户继承属性更新事件处理类
class CSampleFeatureEventHandler : public IFeatureEventHandler
{
public:
void DoOnFeatureEvent(const GxIAPICPP::gxstring& strFeatureName, void* pUserParam)
{
cout << "收到曝光结束事件!" << endl;
}
};
//用户继承采集事件处理类
class CSampleCaptureEventHandler : public ICaptureEventHandler
{
public:
void DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam)
{
cout << "收到一帧图像!" << endl;
cout << "ImageInfo: " << objImageDataPointer->GetStatus() << endl;
cout << "ImageInfo: " << objImageDataPointer->GetWidth() << endl;
cout << "ImageInfo: " << objImageDataPointer->GetHeight() << endl;
cout << "ImageInfo: " << objImageDataPointer->GetPayloadSize() << endl;
img.create(objImageDataPointer->GetHeight(), objImageDataPointer->GetWidth(), CV_8UC3);
void* pRGB24Buffer = NULL;
//假设原始数据是BayerRG8图像
pRGB24Buffer = objImageDataPointer->ConvertToRGB24(GX_BIT_0_7, GX_RAW2RGB_NEIGHBOUR, true);
memcpy(img.data, pRGB24Buffer, (objImageDataPointer->GetHeight()) * (objImageDataPointer->GetWidth()) * 3);
cv::flip(img, img, 0);
cv::imshow("sss", img);
cv::waitKey(1);
cout << "帧数:" << objImageDataPointer->GetFrameID() << endl;
}
};
int main(int argc, char* argv[])
{
//声明事件回调对象指针
IDeviceOfflineEventHandler* pDeviceOfflineEventHandler = NULL;///<掉线事件回调对象
IFeatureEventHandler* pFeatureEventHandler = NULL;///<远端设备事件回调对象
ICaptureEventHandler* pCaptureEventHandler = NULL;///<采集回调对象
//初始化
IGXFactory::GetInstance().Init();
try
{
do
{
//枚举设备
gxdeviceinfo_vector vectorDeviceInfo;
IGXFactory::GetInstance().UpdateDeviceList(1000, vectorDeviceInfo);
if (0 == vectorDeviceInfo.size())
{
cout << "无可用设备!" << endl;
break;
}
cout << vectorDeviceInfo[0].GetVendorName() << endl;
cout << vectorDeviceInfo[0].GetSN() << endl;
//打开第一台设备以及设备下面第一个流
CGXDevicePointer ObjDevicePtr = IGXFactory::GetInstance().OpenDeviceBySN(
vectorDeviceInfo[0].GetSN(),
GX_ACCESS_EXCLUSIVE);
CGXStreamPointer ObjStreamPtr = ObjDevicePtr->OpenStream(0);
//注册设备掉线事件【目前只有千兆网系列相机支持此事件通知】
GX_DEVICE_OFFLINE_CALLBACK_HANDLE hDeviceOffline = NULL;
pDeviceOfflineEventHandler = new CSampleDeviceOfflineEventHandler();
hDeviceOffline = ObjDevicePtr->RegisterDeviceOfflineCallback(pDeviceOfflineEventHandler, NULL);
//获取远端设备属性控制器
CGXFeatureControlPointer ObjFeatureControlPtr = ObjDevicePtr->GetRemoteFeatureControl();
//设置曝光时间(示例中写死us,只是示例,并不代表真正可工作参数)
//ObjFeatureControlPtr->GetFloatFeature("ExposureTime")->SetValue(50);
//注册远端设备事件:曝光结束事件【目前只有千兆网系列相机支持曝光结束事件】
//选择事件源
//ObjFeatureControlPtr->GetEnumFeature("EventSelector")->SetValue("ExposureEnd");
//使能事件
//ObjFeatureControlPtr->GetEnumFeature("EventNotification")->SetValue("On");
//GX_FEATURE_CALLBACK_HANDLE hFeatureEvent = NULL;
//pFeatureEventHandler = new CSampleFeatureEventHandler();
//hFeatureEvent = ObjFeatureControlPtr->RegisterFeatureCallback(
// "EventExposureEnd",
// pFeatureEventHandler,
// NULL);
//注册回调采集
pCaptureEventHandler = new CSampleCaptureEventHandler();
ObjStreamPtr->RegisterCaptureCallback(pCaptureEventHandler, NULL);
//发送开采命令
ObjStreamPtr->StartGrab();
ObjFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
//此时开采成功,控制台打印信息,直到输入任意键继续
getchar();
//发送停采命令
ObjFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
ObjStreamPtr->StopGrab();
//注销采集回调
ObjStreamPtr->UnregisterCaptureCallback();
//注销远端设备事件
//ObjFeatureControlPtr->UnregisterFeatureCallback(hFeatureEvent);
//注销设备掉线事件
//ObjDevicePtr->UnregisterDeviceOfflineCallback(hDeviceOffline);
//释放资源
ObjStreamPtr->Close();
ObjDevicePtr->Close();
} while (0);
}
catch (CGalaxyException& e)
{
cout << "错误码: " << e.GetErrorCode() << endl;
cout << "错误描述信息: " << e.what() << endl;
}
catch (std::exception& e)
{
cout << "错误描述信息: " << e.what() << endl;
}
//反初始化库
IGXFactory::GetInstance().Uninit();
//销毁事件回调指针
if (NULL != pCaptureEventHandler)
{
delete pCaptureEventHandler;
pCaptureEventHandler = NULL;
}
if (NULL != pDeviceOfflineEventHandler)
{
delete pDeviceOfflineEventHandler;
pDeviceOfflineEventHandler = NULL;
}
if (NULL != pFeatureEventHandler)
{
delete pFeatureEventHandler;
pFeatureEventHandler = NULL;
}
return 0;
}
这里我出现了两个结果
-
成功执行,显示图像和图像信息
-
失败,错误代码-8 。。。阿西吧,这里我找了半天错,就是那种同样的代码咋关掉再打开就报错啦??后来发现可能是
也许是这个问题吧,解决方法嘛就果断重启相机试试,哦吼,成了。。。这里之后再看看咋改吧,目前先这样。
windows(python)
比起c++我python更熟悉一些,于是乎又去看了看pyhton的接口
G:\GalaxySDK\Samples\Python SDK这个文件夹中写好了官方给的接口,哦吼吼,这个接口真不错,比C++那个靠谱多了
我相机彩色的于是乎选了那个color的,完美运行
这个大概需要一些。。。opencv啊PIL啊numpy啊大概的包吧,这些我都有了就不讲咋安了,都是conda install 或者pip 嘛。
官方提供的那个readme我没用那种安装方法,conda多好,环境这里就不讲了。
OK我们来看看代码,嗯嗯嗯。。。官方接口都给到numpy了,最后用的PIL显示,这不就简单了嘛,分分钟改成opencv的Mat格式。
import gxipy as gx
from PIL import Image
import cv2
def main():
# print the demo information
print("")
print("-------------------------------------------------------------")
print("Sample to show how to acquire color image continuously and show acquired image.")
print("-------------------------------------------------------------")
print("")
print("Initializing......")
print("")
# create a device manager
device_manager = gx.DeviceManager()
dev_num, dev_info_list = device_manager.update_device_list()
if dev_num == 0:
print("Number of enumerated devices is 0")
return
# open the first device
cam = device_manager.open_device_by_index(1)
# exit when the camera is a mono camera
if cam.PixelColorFilter.is_implemented() is False:
print("This sample does not support mono camera.")
cam.close_device()
return
# set continuous acquisition
cam.TriggerMode.set(gx.GxSwitchEntry.OFF)
# set exposure
cam.ExposureTime.set(10000.0)
# set gain
cam.Gain.set(10.0)
# get param of improving image quality
if cam.GammaParam.is_readable():
gamma_value = cam.GammaParam.get()
gamma_lut = gx.Utility.get_gamma_lut(gamma_value)
else:
gamma_lut = None
if cam.ContrastParam.is_readable():
contrast_value = cam.ContrastParam.get()
contrast_lut = gx.Utility.get_contrast_lut(contrast_value)
else:
contrast_lut = None
if cam.ColorCorrectionParam.is_readable():
color_correction_param = cam.ColorCorrectionParam.get()
else:
color_correction_param = 0
# start data acquisition
cam.stream_on()
# acquisition image: num is the image number
num = 1
for i in range(num):
# get raw image
raw_image = cam.data_stream[0].get_image()
if raw_image is None:
print("Getting image failed.")
continue
# get RGB image from raw image
rgb_image = raw_image.convert("RGB")
if rgb_image is None:
continue
# improve image quality
rgb_image.image_improvement(color_correction_param, contrast_lut, gamma_lut)
# create numpy array with data from raw image
numpy_image = rgb_image.get_numpy_array()
if numpy_image is None:
continue
# show acquired image
# 这里改用opencv显示
cv_img = cv2.cvtColor(numpy_image, cv2.COLOR_BGR2RGB)
cv2.imshow("opencv", cv_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 这里用PIL显示
img = Image.fromarray(numpy_image, 'RGB')
img.show()
# print height, width, and frame ID of the acquisition image
print("Frame ID: %d Height: %d Width: %d"
% (raw_image.get_frame_id(), raw_image.get_height(), raw_image.get_width()))
# stop data acquisition
cam.stream_off()
# close device
cam.close_device()
if __name__ == "__main__":
main()
还是python简单啊,唉,要不是行业里都是C++部署,python多好用啊,唉。
相机的内部设定
照出来的图像各种参数,颜色,饱和度,伽马值,亮度啥的这些其实是用官方文档里写的接口去调的,调好了直接写在相机内部,这里由于本博主太菜,且发现用demo也能调,所以嘛就不费事了。
下载的资料中,官方提供了一个工具demo,GalaxyView.exe,这个咋用官方文档里写的清清楚楚,我只讲一下用这个设置相机,这里如图:
把插件下面第2,3,4全打开
可以看到这里可以进行各种设定,原理这里我也不是很懂,之前我都是采集上来用opencv或者imaug去调的,而像这种工业相机应该是要用自己的库,所以这种调整处理是大恒官方写的,文档里有方法,这里就不深究了。
这里调好了就写入到设备里,这样就OK了。
ubuntu系统
c++接口
-
根据readme安装,这里会在环境变量中添加几个路径,所以安装完了不能改路径
-
安装完成后进入看bin目录下的GalaxyView和GxGigeIPConfig和windows下的一样设置一下ip
-
重点:我是直接网口连的电脑主板,在上一步发现读取不到图像信息。询问技术客服后解决
- 方法:设置网口的mtu<字节> 设置网络设备的MTU
- 之前是1500,现在设置成8192
- 这里也要设置成8192(默认就是,但是还是要看一眼)
- 方法:设置网口的mtu<字节> 设置网络设备的MTU
-
OK,这样运行提供的例子就没问题了
python接口
这里下载的linux文件没有提供python接口
其实直接把windows提供的python—SDK拿过来用就行了