#include "IKapDevice.h" #include #include // 静态工厂方法实现 int IIKapDevice::CreateObject(IIKapDevice** ppDevice) { if (ppDevice == nullptr) return -1; *ppDevice = new CIKapDevice(); return (*ppDevice) ? 0 : -1; } CIKapDevice::CIKapDevice() : m_hDevice(nullptr) , m_hStream(nullptr) , m_bIsGrabbing(false) , m_bLibInitialized(false) , m_imageCallback(nullptr) , m_pUserData(nullptr) , m_nDeviceIndex(0) , m_bDeviceOpened(false) { } CIKapDevice::~CIKapDevice() { // 确保资源被释放 if (m_bIsGrabbing.load()) { StopGrabbing(); } if (m_bDeviceOpened) { CloseDevice(); } if (m_bLibInitialized.load()) { TerminateLibrary(); } } int CIKapDevice::InitLibrary() { if (m_bLibInitialized.load()) return 0; ITKSTATUS status = ItkManInitialize(); if (status != ITKSTATUS_OK) { std::cerr << "ItkManInitialize failed, status: " << status << std::endl; return -1; } m_bLibInitialized.store(true); return 0; } int CIKapDevice::TerminateLibrary() { if (!m_bLibInitialized.load()) return 0; ITKSTATUS status = ItkManTerminate(); if (status != ITKSTATUS_OK) { std::cerr << "ItkManTerminate failed, status: " << status << std::endl; return -1; } m_bLibInitialized.store(false); return 0; } int CIKapDevice::EnumerateDevices(unsigned int& nCount) { if (!m_bLibInitialized.load()) { std::cerr << "Library not initialized" << std::endl; return -1; } ITKSTATUS status = ItkManGetDeviceCount(&nCount); if (status != ITKSTATUS_OK) { std::cerr << "ItkManGetDeviceCount failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::GetDeviceInfo(unsigned int nIndex, IKapDeviceInfo& deviceInfo) { if (!m_bLibInitialized.load()) { std::cerr << "Library not initialized" << std::endl; return -1; } ITKDEV_INFO devInfo; memset(&devInfo, 0, sizeof(devInfo)); ITKSTATUS status = ItkManGetDeviceInfo(nIndex, &devInfo); if (status != ITKSTATUS_OK) { std::cerr << "ItkManGetDeviceInfo failed, status: " << status << std::endl; return -1; } // 复制设备信息 strncpy(deviceInfo.vendorName, devInfo.VendorName, sizeof(deviceInfo.vendorName) - 1); deviceInfo.vendorName[sizeof(deviceInfo.vendorName) - 1] = '\0'; strncpy(deviceInfo.modelName, devInfo.ModelName, sizeof(deviceInfo.modelName) - 1); deviceInfo.modelName[sizeof(deviceInfo.modelName) - 1] = '\0'; strncpy(deviceInfo.serialNumber, devInfo.SerialNumber, sizeof(deviceInfo.serialNumber) - 1); deviceInfo.serialNumber[sizeof(deviceInfo.serialNumber) - 1] = '\0'; strncpy(deviceInfo.userDefinedName, devInfo.UserDefinedName, sizeof(deviceInfo.userDefinedName) - 1); deviceInfo.userDefinedName[sizeof(deviceInfo.userDefinedName) - 1] = '\0'; return 0; } int CIKapDevice::OpenDevice(unsigned int nIndex, int accessMode) { std::lock_guard lock(m_mutex); if (m_bDeviceOpened) { std::cerr << "Device already opened" << std::endl; return -1; } if (!m_bLibInitialized.load()) { std::cerr << "Library not initialized" << std::endl; return -1; } // 打开设备 ITKSTATUS status = ItkDevOpen(nIndex, accessMode, &m_hDevice); if (status != ITKSTATUS_OK || m_hDevice == nullptr) { std::cerr << "ItkDevOpen failed, status: " << status << std::endl; return -1; } m_nDeviceIndex = nIndex; m_bDeviceOpened = true; // 创建数据流和Buffer if (CreateStreamAndBuffer() != 0) { CloseDevice(); return -1; } return 0; } int CIKapDevice::CloseDevice() { std::lock_guard lock(m_mutex); if (!m_bDeviceOpened) return 0; // 释放数据流和Buffer ReleaseStreamAndBuffer(); // 关闭设备 if (m_hDevice != nullptr) { ITKSTATUS status = ItkDevClose(m_hDevice); if (status != ITKSTATUS_OK) { std::cerr << "ItkDevClose failed, status: " << status << std::endl; } m_hDevice = nullptr; } m_bDeviceOpened = false; return 0; } int CIKapDevice::IsConnected(bool& bConnected) { if (!m_bDeviceOpened || m_hDevice == nullptr) { bConnected = false; return 0; } #ifdef _WIN32 // Windows 平台:使用新版 API bool connected = false; ITKSTATUS status = ItkDevIsConnected(m_hDevice, &connected); if (status != ITKSTATUS_OK) { std::cerr << "ItkDevIsConnected failed, status: " << status << std::endl; return -1; } bConnected = connected; #else // Linux/ARM 平台:旧版 SDK 没有 IsConnected 接口,简化实现 // 假设设备打开后就是连接状态 bConnected = (m_hDevice != nullptr); #endif return 0; } int CIKapDevice::CreateStreamAndBuffer() { if (m_hDevice == nullptr) return -1; // 获取数据流数量 uint32_t streamCount = 0; ITKSTATUS status = ItkDevGetStreamCount(m_hDevice, &streamCount); if (status != ITKSTATUS_OK || streamCount == 0) { std::cerr << "ItkDevGetStreamCount failed or no stream available" << std::endl; return -1; } #ifdef _WIN32 // Windows 平台:使用新版 API ItkDevAllocStreamEx(自动分配buffer) status = ItkDevAllocStreamEx(m_hDevice, 0, m_nBufferCount, &m_hStream); if (status != ITKSTATUS_OK || m_hStream == nullptr) { std::cerr << "ItkDevAllocStreamEx failed, status: " << status << std::endl; return -1; } // 获取所有 Buffer m_vecBuffers.resize(m_nBufferCount); for (unsigned int i = 0; i < m_nBufferCount; ++i) { status = ItkStreamGetBuffer(m_hStream, i, &m_vecBuffers[i]); if (status != ITKSTATUS_OK) { std::cerr << "ItkStreamGetBuffer failed for index " << i << std::endl; ReleaseStreamAndBuffer(); return -1; } } #else // Linux/ARM 平台:使用旧版 API ItkDevAllocStream(需要手动创建buffer) // 旧版 API 需要传入单个 buffer,简化实现:使用 nullptr 让SDK自动分配 status = ItkDevAllocStream(m_hDevice, 0, nullptr, &m_hStream); if (status != ITKSTATUS_OK || m_hStream == nullptr) { std::cerr << "ItkDevAllocStream failed, status: " << status << std::endl; return -1; } // ARM 版本不支持 GetBuffer,buffer 由 SDK 内部管理 m_vecBuffers.clear(); #endif return 0; } int CIKapDevice::ReleaseStreamAndBuffer() { // 清空 Buffer 列表 m_vecBuffers.clear(); // 释放数据流 if (m_hStream != nullptr) { ItkDevFreeStream(m_hStream); m_hStream = nullptr; } return 0; } int CIKapDevice::GrabSingleFrame(ImageData& imageData, unsigned int nTimeout) { if (!m_bDeviceOpened || m_hDevice == nullptr || m_hStream == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } #ifdef _WIN32 // Windows 平台:使用主动取图 API // 开始采集单帧 ITKSTATUS status = ItkStreamStart(m_hStream, 1); if (status != ITKSTATUS_OK) { std::cerr << "ItkStreamStart failed, status: " << status << std::endl; return -1; } // 等待单帧图像 ITKBUFFER hReadyBuffer = nullptr; status = ItkStreamWaitOneFrameReady(m_hStream, &hReadyBuffer, (long long)nTimeout); if (status != ITKSTATUS_OK || hReadyBuffer == nullptr) { std::cerr << "ItkStreamWaitOneFrameReady failed or timeout, status: " << status << std::endl; ItkStreamStop(m_hStream); return -1; } // 复制图像数据 int ret = CopyImageData(hReadyBuffer, imageData); // 清除buffer(返还给stream) ItkStreamClearBuffer(m_hStream, hReadyBuffer); // 停止采集 ItkStreamStop(m_hStream); return ret; #else // Linux/ARM 平台:旧版 SDK 不支持 WaitOneFrameReady // 简化实现:返回不支持错误 std::cerr << "GrabSingleFrame not supported on ARM platform (old SDK)" << std::endl; return -1; #endif } int CIKapDevice::CopyImageData(ITKBUFFER hBuffer, ImageData& imageData) { if (hBuffer == nullptr) return -1; // 获取 Buffer 信息 ITK_BUFFER_INFO bufferInfo; memset(&bufferInfo, 0, sizeof(bufferInfo)); ITKSTATUS status = ItkBufferGetInfo(hBuffer, &bufferInfo); if (status != ITKSTATUS_OK) { std::cerr << "ItkBufferGetInfo failed, status: " << status << std::endl; return -1; } // 填充图像数据结构 imageData.width = static_cast(bufferInfo.ImageWidth); imageData.height = static_cast(bufferInfo.ImageHeight); imageData.pixelFormat = static_cast(bufferInfo.PixelFormat); imageData.imageSize = static_cast(bufferInfo.ImageSize); imageData.timestamp = bufferInfo.TimestampNs; imageData.frameID = bufferInfo.BlockID; // 分配内存并复制图像数据 if (imageData.pData != nullptr) { delete[] imageData.pData; } imageData.pData = new unsigned char[imageData.imageSize]; // 使用ItkBufferRead读取数据 status = ItkBufferRead(hBuffer, 0, imageData.pData, (uint32_t)imageData.imageSize); if (status != ITKSTATUS_OK) { std::cerr << "ItkBufferRead failed, status: " << status << std::endl; delete[] imageData.pData; imageData.pData = nullptr; return -1; } return 0; } int CIKapDevice::StartGrabbing(ImageCallback callback, void* pUser) { if (m_bIsGrabbing.load()) { std::cerr << "Already grabbing" << std::endl; return -1; } if (!m_bDeviceOpened || m_hDevice == nullptr || m_hStream == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } if (callback == nullptr) { std::cerr << "Callback is null" << std::endl; return -1; } m_imageCallback = callback; m_pUserData = pUser; m_bIsGrabbing.store(true); // 启动采集线程 m_grabbingThread = std::thread(&CIKapDevice::GrabbingThread, this); return 0; } int CIKapDevice::StopGrabbing() { if (!m_bIsGrabbing.load()) return 0; // 设置停止标志 m_bIsGrabbing.store(false); // 等待线程结束 if (m_grabbingThread.joinable()) { m_grabbingThread.join(); } m_imageCallback = nullptr; m_pUserData = nullptr; return 0; } bool CIKapDevice::IsGrabbing() { return m_bIsGrabbing.load(); } void CIKapDevice::GrabbingThread() { // 开始连续采集 ITKSTATUS status = ItkStreamStart(m_hStream, 0); // 0表示连续采集 if (status != ITKSTATUS_OK) { std::cerr << "ItkStreamStart failed in thread" << std::endl; m_bIsGrabbing.store(false); return; } while (m_bIsGrabbing.load()) { // 等待图像 ITKBUFFER hReadyBuffer = nullptr; status = ItkStreamWaitOneFrameReady(m_hStream, &hReadyBuffer, 1000); if (status == ITKSTATUS_OK && hReadyBuffer != nullptr) { // 复制图像数据 ImageData imageData; imageData.pData = nullptr; if (CopyImageData(hReadyBuffer, imageData) == 0) { // 调用回调函数 if (m_imageCallback) { m_imageCallback(imageData, m_pUserData); } // 释放图像数据内存 if (imageData.pData != nullptr) { delete[] imageData.pData; imageData.pData = nullptr; } } // 清除buffer(返还给stream继续使用) ItkStreamClearBuffer(m_hStream, hReadyBuffer); } } // 停止采集 ItkStreamStop(m_hStream); } int CIKapDevice::SetExposureTime(double exposureTime) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } ITKSTATUS status = ItkDevSetDouble(m_hDevice, "ExposureTime", exposureTime); if (status != ITKSTATUS_OK) { std::cerr << "SetExposureTime failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::GetExposureTime(double& exposureTime) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } ITKSTATUS status = ItkDevGetDouble(m_hDevice, "ExposureTime", &exposureTime); if (status != ITKSTATUS_OK) { std::cerr << "GetExposureTime failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::SetGain(double gain) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } ITKSTATUS status = ItkDevSetDouble(m_hDevice, "Gain", gain); if (status != ITKSTATUS_OK) { std::cerr << "SetGain failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::GetGain(double& gain) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } ITKSTATUS status = ItkDevGetDouble(m_hDevice, "Gain", &gain); if (status != ITKSTATUS_OK) { std::cerr << "GetGain failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::SetTriggerMode(bool bEnable) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } const char* triggerMode = bEnable ? "On" : "Off"; ITKSTATUS status = ItkDevFromString(m_hDevice, "TriggerMode", triggerMode); if (status != ITKSTATUS_OK) { std::cerr << "SetTriggerMode failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::ExecuteSoftwareTrigger() { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } ITKSTATUS status = ItkDevExecuteCommand(m_hDevice, "TriggerSoftware"); if (status != ITKSTATUS_OK) { std::cerr << "ExecuteSoftwareTrigger failed, status: " << status << std::endl; return -1; } return 0; } int CIKapDevice::GetWidth(unsigned int& width) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } int64_t value = 0; ITKSTATUS status = ItkDevGetInt64(m_hDevice, "Width", &value); if (status != ITKSTATUS_OK) { std::cerr << "GetWidth failed, status: " << status << std::endl; return -1; } width = static_cast(value); return 0; } int CIKapDevice::GetHeight(unsigned int& height) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } int64_t value = 0; ITKSTATUS status = ItkDevGetInt64(m_hDevice, "Height", &value); if (status != ITKSTATUS_OK) { std::cerr << "GetHeight failed, status: " << status << std::endl; return -1; } height = static_cast(value); return 0; } int CIKapDevice::SetROI(unsigned int offsetX, unsigned int offsetY, unsigned int width, unsigned int height) { if (!m_bDeviceOpened || m_hDevice == nullptr) { std::cerr << "Device not opened" << std::endl; return -1; } ITKSTATUS status; // 设置 OffsetX status = ItkDevSetInt64(m_hDevice, "OffsetX", offsetX); if (status != ITKSTATUS_OK) { std::cerr << "Set OffsetX failed" << std::endl; return -1; } // 设置 OffsetY status = ItkDevSetInt64(m_hDevice, "OffsetY", offsetY); if (status != ITKSTATUS_OK) { std::cerr << "Set OffsetY failed" << std::endl; return -1; } // 设置 Width status = ItkDevSetInt64(m_hDevice, "Width", width); if (status != ITKSTATUS_OK) { std::cerr << "Set Width failed" << std::endl; return -1; } // 设置 Height status = ItkDevSetInt64(m_hDevice, "Height", height); if (status != ITKSTATUS_OK) { std::cerr << "Set Height failed" << std::endl; return -1; } return 0; } int CIKapDevice::GetLibraryVersion(unsigned int& version) { ITKSTATUS status = ItkManGetVersion(&version); if (status != ITKSTATUS_OK) { std::cerr << "ItkManGetVersion failed, status: " << status << std::endl; return -1; } return 0; }