683 lines
19 KiB
C++
683 lines
19 KiB
C++
#include "GalaxyCamera.h"
|
||
#include <cstring>
|
||
#include <algorithm>
|
||
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
#endif
|
||
|
||
// 静态成员初始化
|
||
bool GalaxyCamera::s_sdkInitialized = false;
|
||
int GalaxyCamera::s_instanceCount = 0;
|
||
std::mutex GalaxyCamera::s_sdkMutex;
|
||
|
||
GalaxyCamera::GalaxyCamera()
|
||
: m_pCaptureEventHandler(nullptr)
|
||
, m_bIsOpen(false)
|
||
, m_bIsStreaming(false)
|
||
, m_bHasNewFrame(false) {
|
||
std::lock_guard<std::mutex> lock(s_sdkMutex);
|
||
s_instanceCount++;
|
||
}
|
||
|
||
GalaxyCamera::~GalaxyCamera() {
|
||
try {
|
||
StopStreaming();
|
||
Close();
|
||
}
|
||
catch (...) {
|
||
// 忽略清理异常
|
||
}
|
||
|
||
std::lock_guard<std::mutex> lock(s_sdkMutex);
|
||
s_instanceCount--;
|
||
|
||
// 注意:不在析构函数中反初始化SDK
|
||
// SDK应该在程序退出时统一清理,或者由最后一个实际使用的相机来清理
|
||
// 因为DetectAvailableBrands会频繁创建/销毁临时实例
|
||
}
|
||
|
||
// 检查大恒SDK DLL是否可用
|
||
static bool IsGalaxySDKAvailable() {
|
||
#ifdef _WIN32
|
||
// 尝试加载大恒SDK主DLL
|
||
// 使用 LOAD_LIBRARY_AS_DATAFILE 避免触发DLL的依赖加载
|
||
HMODULE hModule = LoadLibraryExA("GxIAPI.dll", nullptr, LOAD_LIBRARY_AS_DATAFILE);
|
||
if (hModule == nullptr) {
|
||
// DLL不在PATH中或不存在
|
||
return false;
|
||
}
|
||
FreeLibrary(hModule);
|
||
|
||
// 进一步检查:尝试真正加载DLL(会检查依赖)
|
||
hModule = LoadLibraryA("GxIAPI.dll");
|
||
if (hModule == nullptr) {
|
||
// DLL存在但依赖项缺失(如缺少MSVCP140D.dll)
|
||
return false;
|
||
}
|
||
FreeLibrary(hModule);
|
||
return true;
|
||
#else
|
||
return true; // 非Windows平台假设可用
|
||
#endif
|
||
}
|
||
|
||
bool GalaxyCamera::Init(const std::string& sdkPath) {
|
||
(void)sdkPath;
|
||
|
||
std::lock_guard<std::mutex> lock(s_sdkMutex);
|
||
|
||
// 如果SDK已经初始化,直接返回成功
|
||
if (s_sdkInitialized) {
|
||
return true;
|
||
}
|
||
|
||
// 首先检查SDK DLL是否可用
|
||
if (!IsGalaxySDKAvailable()) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 尝试获取工厂实例并初始化
|
||
IGXFactory& factory = IGXFactory::GetInstance();
|
||
factory.Init();
|
||
s_sdkInitialized = true;
|
||
return true;
|
||
}
|
||
catch (CGalaxyException& e) {
|
||
(void)e;
|
||
s_sdkInitialized = false;
|
||
return false;
|
||
}
|
||
catch (std::exception& e) {
|
||
(void)e;
|
||
s_sdkInitialized = false;
|
||
return false;
|
||
}
|
||
catch (...) {
|
||
// 捕获所有其他异常
|
||
s_sdkInitialized = false;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
std::vector<DeviceInfo> GalaxyCamera::Discover() {
|
||
std::vector<DeviceInfo> devices;
|
||
m_vectorDeviceInfo.clear();
|
||
|
||
if (!s_sdkInitialized) {
|
||
return devices;
|
||
}
|
||
|
||
try {
|
||
// 枚举设备,超时1000ms
|
||
IGXFactory::GetInstance().UpdateDeviceList(1000, m_vectorDeviceInfo);
|
||
|
||
for (uint32_t i = 0; i < m_vectorDeviceInfo.size(); i++) {
|
||
DeviceInfo appDevInfo;
|
||
|
||
// 获取设备序列号作为ID
|
||
appDevInfo.id = m_vectorDeviceInfo[i].GetSN().c_str();
|
||
|
||
// 获取设备显示名称
|
||
appDevInfo.name = m_vectorDeviceInfo[i].GetDisplayName().c_str();
|
||
|
||
// 标记品牌
|
||
appDevInfo.brand = "Galaxy";
|
||
|
||
devices.push_back(appDevInfo);
|
||
}
|
||
}
|
||
catch (CGalaxyException& e) {
|
||
(void)e;
|
||
}
|
||
catch (std::exception& e) {
|
||
(void)e;
|
||
}
|
||
|
||
return devices;
|
||
}
|
||
|
||
bool GalaxyCamera::Open(const std::string& deviceID) {
|
||
if (m_bIsOpen) {
|
||
Close();
|
||
}
|
||
|
||
if (!s_sdkInitialized) {
|
||
return false;
|
||
}
|
||
|
||
bool bIsDeviceOpen = false;
|
||
bool bIsStreamOpen = false;
|
||
|
||
try {
|
||
// 通过序列号打开设备
|
||
m_objDevicePtr = IGXFactory::GetInstance().OpenDeviceBySN(
|
||
deviceID.c_str(), GX_ACCESS_EXCLUSIVE);
|
||
bIsDeviceOpen = true;
|
||
|
||
// 获取远程属性控制器
|
||
m_objFeatureControlPtr = m_objDevicePtr->GetRemoteFeatureControl();
|
||
|
||
// 设置采集模式为连续采集
|
||
m_objFeatureControlPtr->GetEnumFeature("AcquisitionMode")->SetValue("Continuous");
|
||
|
||
// 设置触发模式为关(软件触发时先关闭,后续按需开启)
|
||
m_objFeatureControlPtr->GetEnumFeature("TriggerMode")->SetValue("Off");
|
||
|
||
// 获取设备流个数
|
||
int nStreamCount = m_objDevicePtr->GetStreamCount();
|
||
if (nStreamCount > 0) {
|
||
m_objStreamPtr = m_objDevicePtr->OpenStream(0);
|
||
m_objStreamFeatureControlPtr = m_objStreamPtr->GetFeatureControl();
|
||
bIsStreamOpen = true;
|
||
}
|
||
else {
|
||
throw std::exception("未发现设备流!");
|
||
}
|
||
|
||
// 对于GigE相机,设置最优包长
|
||
GX_DEVICE_CLASS_LIST objDeviceClass = m_objDevicePtr->GetDeviceInfo().GetDeviceClass();
|
||
if (GX_DEVICE_CLASS_GEV == objDeviceClass) {
|
||
if (m_objFeatureControlPtr->IsImplemented("GevSCPSPacketSize")) {
|
||
int nPacketSize = m_objStreamPtr->GetOptimalPacketSize();
|
||
m_objFeatureControlPtr->GetIntFeature("GevSCPSPacketSize")->SetValue(nPacketSize);
|
||
}
|
||
}
|
||
|
||
// 创建采集回调处理器
|
||
m_pCaptureEventHandler = new CaptureEventHandler(this);
|
||
|
||
m_bIsOpen = true;
|
||
return true;
|
||
}
|
||
catch (CGalaxyException& e) {
|
||
(void)e;
|
||
|
||
if (bIsStreamOpen && !m_objStreamPtr.IsNull()) {
|
||
m_objStreamPtr->Close();
|
||
}
|
||
if (bIsDeviceOpen && !m_objDevicePtr.IsNull()) {
|
||
m_objDevicePtr->Close();
|
||
}
|
||
|
||
m_bIsOpen = false;
|
||
return false;
|
||
}
|
||
catch (std::exception& e) {
|
||
(void)e;
|
||
|
||
if (bIsStreamOpen && !m_objStreamPtr.IsNull()) {
|
||
m_objStreamPtr->Close();
|
||
}
|
||
if (bIsDeviceOpen && !m_objDevicePtr.IsNull()) {
|
||
m_objDevicePtr->Close();
|
||
}
|
||
|
||
m_bIsOpen = false;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
void GalaxyCamera::Close() {
|
||
if (!m_bIsOpen) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 停止采集
|
||
StopStreaming();
|
||
|
||
// 关闭流对象
|
||
if (!m_objStreamPtr.IsNull()) {
|
||
m_objStreamPtr->Close();
|
||
}
|
||
|
||
// 关闭设备
|
||
if (!m_objDevicePtr.IsNull()) {
|
||
m_objDevicePtr->Close();
|
||
}
|
||
}
|
||
catch (CGalaxyException&) {
|
||
// 忽略关闭异常
|
||
}
|
||
catch (std::exception&) {
|
||
// 忽略关闭异常
|
||
}
|
||
|
||
// 释放回调处理器
|
||
if (m_pCaptureEventHandler != nullptr) {
|
||
delete m_pCaptureEventHandler;
|
||
m_pCaptureEventHandler = nullptr;
|
||
}
|
||
|
||
m_bIsOpen = false;
|
||
}
|
||
|
||
bool GalaxyCamera::SetROI(int x, int y, int w, int h) {
|
||
if (!m_bIsOpen || m_objFeatureControlPtr.IsNull()) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 获取最大宽高
|
||
int64_t widthMax = m_objFeatureControlPtr->GetIntFeature("WidthMax")->GetValue();
|
||
int64_t heightMax = m_objFeatureControlPtr->GetIntFeature("HeightMax")->GetValue();
|
||
|
||
// 基本验证
|
||
if (w <= 0 || h <= 0 || x < 0 || y < 0 ||
|
||
(x + w) > widthMax || (y + h) > heightMax) {
|
||
return false;
|
||
}
|
||
|
||
// 大恒相机ROI通常需要是4的倍数
|
||
w = (w / 4) * 4;
|
||
h = (h / 4) * 4;
|
||
x = (x / 4) * 4;
|
||
y = (y / 4) * 4;
|
||
|
||
if (w <= 0) w = 4;
|
||
if (h <= 0) h = 4;
|
||
|
||
// 设置ROI
|
||
m_objFeatureControlPtr->GetIntFeature("Width")->SetValue(w);
|
||
m_objFeatureControlPtr->GetIntFeature("Height")->SetValue(h);
|
||
m_objFeatureControlPtr->GetIntFeature("OffsetX")->SetValue(x);
|
||
m_objFeatureControlPtr->GetIntFeature("OffsetY")->SetValue(y);
|
||
|
||
return true;
|
||
}
|
||
catch (CGalaxyException& e) {
|
||
(void)e;
|
||
return false;
|
||
}
|
||
catch (std::exception& e) {
|
||
(void)e;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool GalaxyCamera::StartStreaming(FrameCallback callback) {
|
||
if (!m_bIsOpen || m_bIsStreaming) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 保存回调函数
|
||
m_frameCallback = callback;
|
||
|
||
// 设置Buffer处理模式
|
||
try {
|
||
m_objStreamFeatureControlPtr->GetEnumFeature("StreamBufferHandlingMode")->SetValue("OldestFirst");
|
||
}
|
||
catch (...) {
|
||
// 部分相机可能不支持此特性,忽略
|
||
}
|
||
|
||
// 注册采集回调
|
||
m_objStreamPtr->RegisterCaptureCallback(m_pCaptureEventHandler, this);
|
||
|
||
// 开启流层采集
|
||
m_objStreamPtr->StartGrab();
|
||
|
||
// 发送开采命令
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
|
||
|
||
m_bIsStreaming = true;
|
||
return true;
|
||
}
|
||
catch (CGalaxyException& e) {
|
||
(void)e;
|
||
|
||
// 清理
|
||
try {
|
||
m_objStreamPtr->StopGrab();
|
||
m_objStreamPtr->UnregisterCaptureCallback();
|
||
}
|
||
catch (...) {}
|
||
|
||
m_bIsStreaming = false;
|
||
return false;
|
||
}
|
||
catch (std::exception& e) {
|
||
(void)e;
|
||
|
||
try {
|
||
m_objStreamPtr->StopGrab();
|
||
m_objStreamPtr->UnregisterCaptureCallback();
|
||
}
|
||
catch (...) {}
|
||
|
||
m_bIsStreaming = false;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
void GalaxyCamera::StopStreaming() {
|
||
if (!m_bIsOpen || !m_bIsStreaming) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 发送停采命令
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
|
||
|
||
// 关闭流层采集
|
||
m_objStreamPtr->StopGrab();
|
||
|
||
// 注销回调函数
|
||
m_objStreamPtr->UnregisterCaptureCallback();
|
||
}
|
||
catch (CGalaxyException&) {
|
||
// 忽略异常
|
||
}
|
||
catch (std::exception&) {
|
||
// 忽略异常
|
||
}
|
||
|
||
m_bIsStreaming = false;
|
||
m_bHasNewFrame = false;
|
||
}
|
||
|
||
bool GalaxyCamera::IsStreaming() const {
|
||
return m_bIsStreaming;
|
||
}
|
||
|
||
bool GalaxyCamera::GrabCurrentFrame(ImageBuffer& out) {
|
||
if (!m_bIsStreaming) {
|
||
return false;
|
||
}
|
||
|
||
std::lock_guard<std::mutex> lock(m_frameMutex);
|
||
|
||
if (!m_latestFramePtr || m_latestFramePtr->data.empty()) {
|
||
return false;
|
||
}
|
||
|
||
// 复制最新帧数据
|
||
out = *m_latestFramePtr;
|
||
m_bHasNewFrame = false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool GalaxyCamera::Capture(ImageBuffer& out) {
|
||
if (!m_bIsOpen) {
|
||
return false;
|
||
}
|
||
|
||
// 如果正在流模式,使用GrabCurrentFrame
|
||
if (m_bIsStreaming) {
|
||
return GrabCurrentFrame(out);
|
||
}
|
||
|
||
try {
|
||
// 单帧采集模式
|
||
// 开启流层采集
|
||
m_objStreamPtr->StartGrab();
|
||
|
||
// 发送开采命令
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStart")->Execute();
|
||
|
||
// 获取一帧图像,超时5000ms
|
||
CImageDataPointer objImageDataPointer = m_objStreamPtr->GetImage(5000);
|
||
|
||
if (objImageDataPointer.IsNull()) {
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
|
||
m_objStreamPtr->StopGrab();
|
||
return false;
|
||
}
|
||
|
||
// 检查图像状态
|
||
if (objImageDataPointer->GetStatus() != GX_FRAME_STATUS_SUCCESS) {
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
|
||
m_objStreamPtr->StopGrab();
|
||
return false;
|
||
}
|
||
|
||
// 转换图像数据
|
||
out.width = static_cast<int>(objImageDataPointer->GetWidth());
|
||
out.height = static_cast<int>(objImageDataPointer->GetHeight());
|
||
out.pixelFormat = convertPixelFormat(objImageDataPointer->GetPixelFormat());
|
||
|
||
// 计算数据大小
|
||
size_t dataSize = objImageDataPointer->GetPayloadSize();
|
||
out.data.resize(dataSize);
|
||
|
||
// 复制图像数据
|
||
void* pBuffer = objImageDataPointer->GetBuffer();
|
||
if (pBuffer) {
|
||
std::memcpy(out.data.data(), pBuffer, dataSize);
|
||
}
|
||
|
||
// 停止采集
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
|
||
m_objStreamPtr->StopGrab();
|
||
|
||
return true;
|
||
}
|
||
catch (CGalaxyException& e) {
|
||
(void)e;
|
||
|
||
try {
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
|
||
m_objStreamPtr->StopGrab();
|
||
}
|
||
catch (...) {}
|
||
|
||
return false;
|
||
}
|
||
catch (std::exception& e) {
|
||
(void)e;
|
||
|
||
try {
|
||
m_objFeatureControlPtr->GetCommandFeature("AcquisitionStop")->Execute();
|
||
m_objStreamPtr->StopGrab();
|
||
}
|
||
catch (...) {}
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool GalaxyCamera::GetIntValue(const std::string& name, int& value) {
|
||
if (!m_bIsOpen || m_objFeatureControlPtr.IsNull()) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 映射参数名称
|
||
std::string gxName = name;
|
||
if (name == "Width" || name == "Height" ||
|
||
name == "OffsetX" || name == "OffsetY") {
|
||
// 直接使用
|
||
}
|
||
|
||
value = static_cast<int>(m_objFeatureControlPtr->GetIntFeature(gxName.c_str())->GetValue());
|
||
return true;
|
||
}
|
||
catch (CGalaxyException&) {
|
||
return false;
|
||
}
|
||
catch (std::exception&) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool GalaxyCamera::SetIntValue(const std::string& name, int value) {
|
||
if (!m_bIsOpen || m_objFeatureControlPtr.IsNull()) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
m_objFeatureControlPtr->GetIntFeature(name.c_str())->SetValue(value);
|
||
return true;
|
||
}
|
||
catch (CGalaxyException&) {
|
||
return false;
|
||
}
|
||
catch (std::exception&) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool GalaxyCamera::GetFloatValue(const std::string& name, float& value) {
|
||
if (!m_bIsOpen || m_objFeatureControlPtr.IsNull()) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 映射参数名称到大恒SDK参数名
|
||
std::string gxName = name;
|
||
if (name == "ExposureTime") {
|
||
gxName = "ExposureTime";
|
||
}
|
||
else if (name == "Gain") {
|
||
gxName = "Gain";
|
||
}
|
||
|
||
value = static_cast<float>(m_objFeatureControlPtr->GetFloatFeature(gxName.c_str())->GetValue());
|
||
return true;
|
||
}
|
||
catch (CGalaxyException&) {
|
||
return false;
|
||
}
|
||
catch (std::exception&) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool GalaxyCamera::SetFloatValue(const std::string& name, float value) {
|
||
if (!m_bIsOpen || m_objFeatureControlPtr.IsNull()) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 映射参数名称
|
||
std::string gxName = name;
|
||
if (name == "ExposureTime") {
|
||
gxName = "ExposureTime";
|
||
}
|
||
else if (name == "Gain") {
|
||
gxName = "Gain";
|
||
}
|
||
|
||
m_objFeatureControlPtr->GetFloatFeature(gxName.c_str())->SetValue(value);
|
||
return true;
|
||
}
|
||
catch (CGalaxyException&) {
|
||
return false;
|
||
}
|
||
catch (std::exception&) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool GalaxyCamera::IsConnected() {
|
||
return m_bIsOpen && !m_objDevicePtr.IsNull();
|
||
}
|
||
|
||
void GalaxyCamera::Cleanup() {
|
||
Close();
|
||
}
|
||
|
||
void GalaxyCamera::UninitSDK() {
|
||
std::lock_guard<std::mutex> lock(s_sdkMutex);
|
||
if (s_sdkInitialized) {
|
||
try {
|
||
IGXFactory::GetInstance().Uninit();
|
||
s_sdkInitialized = false;
|
||
}
|
||
catch (...) {
|
||
// 忽略清理异常
|
||
}
|
||
}
|
||
}
|
||
|
||
// 采集回调处理
|
||
void GalaxyCamera::CaptureEventHandler::DoOnImageCaptured(
|
||
CImageDataPointer& objImageDataPointer, void* pUserParam) {
|
||
|
||
try {
|
||
GalaxyCamera* pCamera = static_cast<GalaxyCamera*>(pUserParam);
|
||
if (pCamera) {
|
||
pCamera->processFrame(objImageDataPointer);
|
||
}
|
||
}
|
||
catch (CGalaxyException&) {
|
||
// 忽略异常
|
||
}
|
||
catch (std::exception&) {
|
||
// 忽略异常
|
||
}
|
||
}
|
||
|
||
void GalaxyCamera::processFrame(CImageDataPointer& objImageDataPointer) {
|
||
if (objImageDataPointer.IsNull()) {
|
||
return;
|
||
}
|
||
|
||
// 检查图像状态
|
||
if (objImageDataPointer->GetStatus() != GX_FRAME_STATUS_SUCCESS) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 创建新的图像缓冲区
|
||
auto newFrame = std::make_shared<ImageBuffer>();
|
||
|
||
newFrame->width = static_cast<int>(objImageDataPointer->GetWidth());
|
||
newFrame->height = static_cast<int>(objImageDataPointer->GetHeight());
|
||
newFrame->pixelFormat = convertPixelFormat(objImageDataPointer->GetPixelFormat());
|
||
|
||
// 获取图像数据大小
|
||
size_t dataSize = objImageDataPointer->GetPayloadSize();
|
||
newFrame->data.resize(dataSize);
|
||
|
||
// 复制图像数据
|
||
void* pBuffer = objImageDataPointer->GetBuffer();
|
||
if (pBuffer) {
|
||
std::memcpy(newFrame->data.data(), pBuffer, dataSize);
|
||
}
|
||
|
||
// 更新最新帧
|
||
{
|
||
std::lock_guard<std::mutex> lock(m_frameMutex);
|
||
m_latestFramePtr = newFrame;
|
||
m_bHasNewFrame = true;
|
||
}
|
||
|
||
// 调用用户回调
|
||
if (m_frameCallback) {
|
||
m_frameCallback(newFrame);
|
||
}
|
||
}
|
||
catch (std::exception&) {
|
||
// 忽略异常
|
||
}
|
||
}
|
||
|
||
PixelFormat GalaxyCamera::convertPixelFormat(GX_PIXEL_FORMAT_ENTRY gxFormat) {
|
||
switch (gxFormat) {
|
||
case GX_PIXEL_FORMAT_MONO8:
|
||
return PixelFormat::Mono8;
|
||
case GX_PIXEL_FORMAT_MONO10:
|
||
return PixelFormat::Mono10;
|
||
case GX_PIXEL_FORMAT_MONO12:
|
||
return PixelFormat::Mono12;
|
||
case GX_PIXEL_FORMAT_MONO16:
|
||
return PixelFormat::Mono16;
|
||
case GX_PIXEL_FORMAT_BAYER_RG8:
|
||
return PixelFormat::BayerRG8;
|
||
case GX_PIXEL_FORMAT_BAYER_GB8:
|
||
return PixelFormat::BayerGB8;
|
||
case GX_PIXEL_FORMAT_BAYER_GR8:
|
||
return PixelFormat::BayerGR8;
|
||
case GX_PIXEL_FORMAT_BAYER_BG8:
|
||
return PixelFormat::BayerBG8;
|
||
default:
|
||
// 对于未知格式,默认返回Mono8
|
||
return PixelFormat::Mono8;
|
||
}
|
||
}
|