commit 5abc95def577649e9f5baa7c89d9b1db0b824cf3 Author: leon <501646023@qq.com> Date: Mon Dec 16 12:30:52 2024 +0800 first commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5c68531 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,61 @@ +cmake_minimum_required(VERSION 3.10) + +PROJECT(lidar_camera) + +set(CMAKE_SOURCE_DIR "./") + + +message(STATUS "========================") +message(STATUS ${CMAKE_SYSTEM_NAME}) +message(STATUS ${CMAKE_SYSTEM_PROCESSOR}) +message(STATUS "========================") + + +find_package(OpenCV 3.2) +if(NOT OpenCV_FOUND) + message(FATAL_ERROR "OpenCV > 3.2 not found.") +endif() +MESSAGE(${OpenCV_VERSION}) + +# 检测操作系统和架构 +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(PLATFORM "linux/x64") + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(PLATFORM "linux/aarch64") + else() + message(FATAL_ERROR "Unsupported architecture on Linux") + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PLATFORM "windows/x64") + else() + message(FATAL_ERROR "Unsupported architecture on Windows") + endif() +else() + message(FATAL_ERROR "Unsupported operating system") +endif() + +# 输出当前系统和架构 +message(STATUS "operating system: ${PLATFORM}") + +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/output/") + +INCLUDE_DIRECTORIES( + "/opt/HuarayTech/MVviewer/include" + "/usr/include" +) +# LINK_DIRECTORIES( +# "/opt/HuarayTech/MVviewer/lib" +# "/opt/HuarayTech/MVviewer/bin" +# ) + +aux_source_directory(${CMAKE_SOURCE_DIR}/ SRCLIST) + +add_executable(${PROJECT_NAME} ${SRCLIST}) + +# target_link_libraries(${PROJECT_NAME} MVSDK) +target_link_libraries(${PROJECT_NAME} dl) +# target_link_libraries(${PROJECT_NAME} lrt) +target_link_libraries(${PROJECT_NAME} pthread) +target_link_libraries(${PROJECT_NAME} "/opt/HuarayTech/MVviewer/lib" ${OpenCV_LIBS}) diff --git a/CameraDriver.cpp b/CameraDriver.cpp new file mode 100644 index 0000000..4672cb3 --- /dev/null +++ b/CameraDriver.cpp @@ -0,0 +1,1086 @@ +#include "CameraDriver.h" + +extern "C"{ + +// ***********开始: 这部分处理与SDK操作相机无关,用于显示设备列表 *********** +// ***********BEGIN: These functions are not related to API call and used to display device info*********** +// 数据帧回调函数 +// Data frame callback function +static void onGetFrame(IMV_Frame* pFrame, void* pUser) +{ + if (pFrame == NULL) + { + printf("pFrame is NULL\n"); + return; + } + + printf("Get frame blockId = %llu\n", pFrame->frameInfo.blockId); + + return; +} + +static void displayDeviceInfo(IMV_DeviceList deviceInfoList) +{ + IMV_DeviceInfo* pDevInfo = NULL; + unsigned int cameraIndex = 0; + char vendorNameCat[11]; + char cameraNameCat[16]; + + // 打印Title行 + // Print title line + printf("\nIdx Type Vendor Model S/N DeviceUserID IP Address \n"); + printf("------------------------------------------------------------------------------\n"); + + for (cameraIndex = 0; cameraIndex < deviceInfoList.nDevNum; cameraIndex++) + { + pDevInfo = &deviceInfoList.pDevInfo[cameraIndex]; + // 设备列表的相机索引 最大表示字数:3 + // Camera index in device list, display in 3 characters + printf("%-3d", cameraIndex + 1); + + // 相机的设备类型(GigE,U3V,CL,PCIe) + // Camera type + switch (pDevInfo->nCameraType) + { + case typeGigeCamera:printf(" GigE");break; + case typeU3vCamera:printf(" U3V ");break; + case typeCLCamera:printf(" CL ");break; + case typePCIeCamera:printf(" PCIe");break; + default:printf(" ");break; + } + + // 制造商信息 最大表示字数:10 + // Camera vendor name, display in 10 characters + if (strlen(pDevInfo->vendorName) > 10) + { + memcpy(vendorNameCat, pDevInfo->vendorName, 7); + vendorNameCat[7] = '\0'; + strcat(vendorNameCat, "..."); + printf(" %-10.10s", vendorNameCat); + } + else + { + printf(" %-10.10s", pDevInfo->vendorName); + } + + // 相机的型号信息 最大表示字数:10 + // Camera model name, display in 10 characters + printf(" %-10.10s", pDevInfo->modelName); + + // 相机的序列号 最大表示字数:15 + // Camera serial number, display in 15 characters + printf(" %-15.15s", pDevInfo->serialNumber); + + // 自定义用户ID 最大表示字数:15 + // Camera user id, display in 15 characters + if (strlen(pDevInfo->cameraName) > 15) + { + memcpy(cameraNameCat, pDevInfo->cameraName, 12); + cameraNameCat[12] = '\0'; + strcat(cameraNameCat, "..."); + printf(" %-15.15s", cameraNameCat); + } + else + { + printf(" %-15.15s", pDevInfo->cameraName); + } + + // GigE相机时获取IP地址 + // IP address of GigE camera + if (pDevInfo->nCameraType == typeGigeCamera) + { + printf(" %s", pDevInfo->DeviceSpecificInfo.gigeDeviceInfo.ipAddress); + } + + printf("\n"); + } + + return; +} + +static char* trim(char* pStr) +{ + char* pDst = pStr; + char* pTemStr = NULL; + + if (pDst != NULL) + { + pTemStr = pDst + strlen(pStr) - 1; + while (*pDst == ' ') + { + pDst++; + } + while ((pTemStr > pDst) && (*pTemStr == ' ')) + { + *pTemStr-- = '\0'; + } + } + return pDst; +} + +static int isInputValid(char* pInpuStr) +{ + char numChar; + char* pStr = pInpuStr; + while (*pStr != '\0') + { + numChar = *pStr; + if ((numChar > '9') || (numChar < '0')) + { + return -1; + } + pStr++; + } + return 0; +} + +static unsigned int selectDevice(unsigned int cameraCnt) +{ + char inputStr[256]; + char* pTrimStr; + int inputIndex = -1; + int ret = -1; + char* find = NULL; + + printf("\nPlease input the camera index: "); + while (1) + { + memset(inputStr, 0, sizeof(inputStr)); + fgets(inputStr, sizeof(inputStr), stdin); + + // 清空输入缓存 + // clear flush + fflush(stdin); + + // fgets比gets多吃一个换行符号,取出换行符号 + // fgets eats one more line feed symbol than gets, and takes out the line feed symbol + find = strchr(inputStr, '\n'); + if (find) { *find = '\0'; } + + pTrimStr = trim(inputStr); + ret = isInputValid(pTrimStr); + if (ret == 0) + { + inputIndex = atoi(pTrimStr); + // 输入的序号从1开始 + // Input index starts from 1 + inputIndex -= 1; + if ((inputIndex >= 0) && (inputIndex < (int)cameraCnt)) + { + break; + } + } + + printf("Input invalid! Please input the camera index: "); + } + return (unsigned int)inputIndex; +} + +// ***********结束: 这部分处理与SDK操作相机无关,用于显示设备列表 *********** +// ***********END: These functions are not related to API call and used to display device info*********** +static int setSoftTriggerConf(void* libHandle, IMV_HANDLE devHandle) +{ + int ret = IMV_OK; + // 获取设置触发源为软触发函数地址 + DLL_SetEnumFeatureSymbol DLLSetEnumFeatureSymbol = (DLL_SetEnumFeatureSymbol)dlsym(libHandle, "IMV_SetEnumFeatureSymbol"); + if (NULL == DLLSetEnumFeatureSymbol) + { + printf("Get IMV_SetEnumFeatureSymbol address failed!\n"); + return ret; + } + + // 设置触发源为软触发 + // Set trigger source to Software + ret = DLLSetEnumFeatureSymbol(devHandle, "TriggerSource", "Software"); + if (IMV_OK != ret) + { + printf("Set triggerSource value failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置触发器 + // Set trigger selector to FrameStart + ret = DLLSetEnumFeatureSymbol(devHandle, "TriggerSelector", "FrameStart"); + if (IMV_OK != ret) + { + printf("Set triggerSelector value failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置触发模式 + // Set trigger mode to On + ret = DLLSetEnumFeatureSymbol(devHandle, "TriggerMode", "On"); + if (IMV_OK != ret) + { + printf("Set triggerMode value failed! ErrorCode[%d]\n", ret); + return ret; + } + + return ret; +} + +// Image convert +static int imageConvert(void* libHandle, IMV_HANDLE devHandle, IMV_Frame frame, IMV_EPixelType convertFormat,void** data, int& w, int& h) +{ + IMV_PixelConvertParam stPixelConvertParam; + unsigned char* pDstBuf = NULL; + unsigned int nDstBufSize = 0; + int ret = IMV_OK; + FILE* hFile = NULL; + const char* pFileName = NULL; + const char* pConvertFormatStr = NULL; + + // 获取设置触发源为软触发函数地址 + DLL_PixelConvert DLLPixelConvert = (DLL_PixelConvert)dlsym(libHandle, "IMV_PixelConvert"); + if (NULL == DLLPixelConvert) + { + printf("Get IMV_PixelConvert address failed!\n"); + return ret; + } + + switch (convertFormat) + { + case gvspPixelRGB8: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height * 3; + pFileName = (const char*)"convertRGB8.bmp"; + pConvertFormatStr = (const char*)"RGB8"; + break; + + case gvspPixelBGR8: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height * 3; + pFileName = (const char*)"convertBGR8.bmp"; + pConvertFormatStr = (const char*)"BGR8"; + break; + case gvspPixelBGRA8: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height * 4; + pFileName = (const char*)"convertBGRA8.bmp"; + pConvertFormatStr = (const char*)"BGRA8"; + break; + case gvspPixelMono8: + default: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height; + pFileName = (const char*)"convertMono8.bmp"; + pConvertFormatStr = (const char*)"Mono8"; + break; + } + + pDstBuf = (unsigned char*)malloc(nDstBufSize); + if (NULL == pDstBuf) + { + printf("malloc pDstBuf failed!\n"); + return -1; + } + + // 图像转换成BGR8 + // convert image to BGR8 + memset(&stPixelConvertParam, 0, sizeof(stPixelConvertParam)); + stPixelConvertParam.nWidth = frame.frameInfo.width; + stPixelConvertParam.nHeight = frame.frameInfo.height; + stPixelConvertParam.ePixelFormat = frame.frameInfo.pixelFormat; + stPixelConvertParam.pSrcData = frame.pData; + stPixelConvertParam.nSrcDataLen = frame.frameInfo.size; + stPixelConvertParam.nPaddingX = frame.frameInfo.paddingX; + stPixelConvertParam.nPaddingY = frame.frameInfo.paddingY; + stPixelConvertParam.eBayerDemosaic = demosaicNearestNeighbor; + stPixelConvertParam.eDstPixelFormat = convertFormat; + stPixelConvertParam.pDstBuf = pDstBuf; + stPixelConvertParam.nDstBufSize = nDstBufSize; + + ret = DLLPixelConvert(devHandle, &stPixelConvertParam); + if (IMV_OK == ret) + { + printf("image convert to %s successfully! nDstDataLen (%u)\n", + pConvertFormatStr, stPixelConvertParam.nDstBufSize); + memcpy(*data, pDstBuf, nDstBufSize); + w = frame.frameInfo.width; + h = frame.frameInfo.height; + // cv::Mat im(h, w, CV_8UC3, pDstBuf); + // cv::imwrite("/home/caowei/catkin_ws/output1.png", im); + // cv::imwrite("output1.png", im); + } + else + { + printf("image convert to %s failed! ErrorCode[%d]\n", pConvertFormatStr, ret); + } + + if (pDstBuf) + { + free(pDstBuf); + pDstBuf = NULL; + } + + return IMV_OK; +} + +static void sendToRos(IMV_Frame frame) +{ + IMV_FlipImageParam stFlipImageParam; + unsigned int nChannelNum = 0; + int ret = IMV_OK; + FILE* hFile = NULL; + + memset(&stFlipImageParam, 0, sizeof(stFlipImageParam)); + + if (gvspPixelBGR8 == frame.frameInfo.pixelFormat) + { + stFlipImageParam.pSrcData = frame.pData; + stFlipImageParam.nSrcDataLen = frame.frameInfo.width * frame.frameInfo.height * BGR_CHANNEL_NUM; + stFlipImageParam.ePixelFormat = frame.frameInfo.pixelFormat; + nChannelNum = BGR_CHANNEL_NUM; + } + else + { + printf("image convert to BGR8 failed! ErrorCode[%d]\n", ret); + } + + // 向ros发送/image消息 + do + { + + } while (false); + +} + +static int ret = IMV_OK; +static unsigned int cameraIndex = 0; +static IMV_HANDLE devHandle = NULL; +static void* libHandle = NULL; +static IMV_Frame frame; + + +static DLL_EnumDevices DLLEnumDevices = NULL; +static DLL_CreateHandle DLLCreateHandle = NULL; +static DLL_DestroyHandle DLLDestroyHandle = NULL; +static DLL_Open DLLOpen = NULL; +static DLL_AttachGrabbing DLLAttachGrabbing = NULL; +static DLL_StartGrabbing DLLStartGrabbing = NULL; +static DLL_StopGrabbing DLLStopGrabbing = NULL; +static DLL_Close DLLClose = NULL; +static DLL_GetFrame DLLGetFrame = NULL; +static DLL_ReleaseFrame DLLReleaseFrame = NULL; +static DLL_ClearFrameBuffer DLLClearFrameBuffer = NULL; +static DLL_ExecuteCommandFeature DLLExecuteCommandFeature = NULL; +static DLL_SetIntFeatureValue DLLSetIntFeatureValue = NULL; +static DLL_SetDoubleFeatureValue DLLSetDoubleFeatureValue = NULL; + +int camera_init() +{ + // Load SDK library +#ifdef _WIN32 + libHandle = 0; +#else + libHandle = dlopen("libMVSDK.so", RTLD_LAZY); +#endif + if (NULL == libHandle) + { + printf("Load MVSDKmd.dll library failed!\n"); + return IMV_ERROR; + } + + // 获取发现设备接口函数地址 + // Get discover camera interface address + DLLEnumDevices = (DLL_EnumDevices)dlsym(libHandle, "IMV_EnumDevices"); + if (NULL == DLLEnumDevices) + { + printf("Get IMV_EnumDevices address failed!\n"); + return IMV_ERROR; + } + + + // 获取发现设备接口函数地址 + // Get discover camera interface address + //DLL_EnumDevices DLLEnumDevices = (DLL_EnumDevices)dlsym(libHandle, "IMV_EnumDevices"); + //if (NULL == DLLEnumDevices) + //{ + // printf("Get IMV_EnumDevices address failed!\n"); + // return 0; + //} + + // 获取创建设备句柄接口函数地址 + // Get create Device Handle interface address + DLLCreateHandle = (DLL_CreateHandle)dlsym(libHandle, "IMV_CreateHandle"); + if (NULL == DLLCreateHandle) + { + printf("Get IMV_CreateHandle address failed!\n"); + return IMV_ERROR; + } + + // 获取销毁设备句柄接口函数地址 + // Get destroy Device Handle interface address + DLLDestroyHandle = (DLL_DestroyHandle)dlsym(libHandle, "IMV_DestroyHandle"); + if (NULL == DLLDestroyHandle) + { + printf("Get IMV_DestroyHandle address failed!\n"); + return IMV_ERROR; + } + + // 获取打开相机接口函数地址 + // Get open camera interface address + DLLOpen = (DLL_Open)dlsym(libHandle, "IMV_Open"); + if (NULL == DLLOpen) + { + printf("Get IMV_Open address failed!\n"); + return IMV_ERROR; + } + + // 获取注册数据帧回调接口函数地址 + // Get register data frame callback interface address + DLLAttachGrabbing = (DLL_AttachGrabbing)dlsym(libHandle, "IMV_AttachGrabbing"); + if (NULL == DLLAttachGrabbing) + { + printf("Get IMV_AttachGrabbing address failed!\n"); + return IMV_ERROR; + } + + // 获取开始拉流接口函数地址 + // Get start grabbing interface address + DLLStartGrabbing = (DLL_StartGrabbing)dlsym(libHandle, "IMV_StartGrabbing"); + if (NULL == DLLStartGrabbing) + { + printf("Get IMV_StartGrabbing address failed!\n"); + return IMV_ERROR; + } + + // 获取停止拉流接口函数地址 + // Get stop grabbing interface address + DLLStopGrabbing = (DLL_StopGrabbing)dlsym(libHandle, "IMV_StopGrabbing"); + if (NULL == DLLStopGrabbing) + { + printf("Get IMV_StopGrabbing address failed!\n"); + return IMV_ERROR; + } + + // 获取 + + // 获取关闭相机接口函数地址 + // Get close camera interface address + DLLClose = (DLL_Close)dlsym(libHandle, "IMV_Close"); + if (NULL == DLLClose) + { + printf("Get IMV_Close address failed!\n"); + return IMV_ERROR; + } + + // 获取获取一帧图像函数地址 + DLLGetFrame = (DLL_GetFrame)dlsym(libHandle, "IMV_GetFrame"); + if (NULL == DLLGetFrame) + { + printf("Get IMV_GetFrame address failed!\n"); + return IMV_ERROR; + } + + DLLReleaseFrame = (DLL_ReleaseFrame)dlsym(libHandle, "IMV_ReleaseFrame"); + if (NULL == DLLReleaseFrame) + { + printf("Get IMV_ReleaseFrame address failed!\n"); + return IMV_ERROR; + } + + DLLClearFrameBuffer = (DLL_ClearFrameBuffer)dlsym(libHandle, "IMV_ClearFrameBuffer"); + if (NULL == DLLClearFrameBuffer) + { + printf("Get IMV_ClearFrameBuffer address failed!\n"); + return IMV_ERROR; + } + + DLLExecuteCommandFeature = (DLL_ExecuteCommandFeature)dlsym(libHandle, "IMV_ExecuteCommandFeature"); + if (NULL == DLLExecuteCommandFeature) + { + printf("Get IMV_ExecuteCommandFeature address failed!\n"); + return IMV_ERROR; + } + + DLLSetIntFeatureValue = (DLL_SetIntFeatureValue)dlsym(libHandle, "IMV_SetIntFeatureValue"); + if (NULL == DLLSetIntFeatureValue) + { + printf("Get IMV_SetIntFeatureValue address failed!\n"); + return IMV_ERROR; + } + + DLLSetDoubleFeatureValue = (DLL_SetDoubleFeatureValue)dlsym(libHandle, "IMV_SetDoubleFeatureValue"); + if (NULL == DLLSetDoubleFeatureValue) + { + printf("Get IMV_SetDoubleFeatureValue address failed!\n"); + return IMV_ERROR; + } + + ////////////////////// 检查接口结束 + // 发现设备 + // discover camera + IMV_DeviceList deviceInfoList; + ret = DLLEnumDevices(&deviceInfoList, interfaceTypeAll); + if (IMV_OK != ret) + { + printf("Enumeration devices failed! ErrorCode[%d]\n", ret); + return ret; + } + + if (deviceInfoList.nDevNum < 1) + { + printf("no camera\n"); + return IMV_ERROR; + } + + // 打印相机基本信息(序号,类型,制造商信息,型号,序列号,用户自定义ID,IP地址) + // Print camera info (Index, Type, Vendor, Model, Serial number, DeviceUserID, IP Address) + + displayDeviceInfo(deviceInfoList); + // 选择需要连接的相机 + // Select one camera to connect to + // cameraIndex = selectDevice(deviceInfoList.nDevNum); + cameraIndex = 0; // 第一个相机 + + // 创建设备句柄 + // Create Device Handle + ret = DLLCreateHandle(&devHandle, modeByIndex, (void*)&cameraIndex); + if (IMV_OK != ret) + { + printf("Create devHandle failed! ErrorCode[%d]\n", ret); + return IMV_ERROR; + } + + return IMV_OK; +} + +int camera_start(int epx_time) +{ + + // 打开相机 + ret = DLLOpen(devHandle); + if (IMV_OK != ret) + { + printf("Open camera failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置软触发模式 + ret = setSoftTriggerConf(libHandle, devHandle); + if (IMV_OK != ret) + { + printf("setSoftTriggerConf failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "Width", 9344); + if (IMV_OK != ret) + { + printf("Set feature value Width failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "Height", 7000); + if (IMV_OK != ret) + { + printf("Set feature value Height failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "OffsetX", 0); + if (IMV_OK != ret) + { + printf("Set feature value OffsetX failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "OffsetY", 0); + if (IMV_OK != ret) + { + printf("Set feature value OffsetY failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置属性值曝光 + // Set feature value + ret = DLLSetDoubleFeatureValue(devHandle, "ExposureTime", epx_time); + if (IMV_OK != ret) + { + printf("Set feature value failed! ErrorCode[%d]\n", ret); + return ret; + } + + return IMV_OK; +} + +int camera_cap(void** data, int& w, int& h, int time_out) +{ + // 开始拉流 + ret = DLLStartGrabbing(devHandle); + if (IMV_OK != ret) + { + printf("Start grabbing failed! ErrorCode[%d]\n", ret); + return 0; + } + + // 清除帧数据缓存 + ret = DLLClearFrameBuffer(devHandle); + if (IMV_OK != ret) + { + printf("Clear frame buffer failed! ErrorCode[%d]\n", ret); + return ret; + } + + /////////////////////////获取一帧图像//////////////////////////// + // 执行软触发 + ret = DLLExecuteCommandFeature(devHandle, "TriggerSoftware"); + if (IMV_OK != ret) + { + printf("Execute TriggerSoftware failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 获取一帧图像, TIMEOUT 5000ms + ret = DLLGetFrame(devHandle, &frame, time_out); + if (IMV_OK != ret && -101 != ret) + { + printf("Get frame failed! ErrorCode[%d]\n", ret); + return ret; + } + + printf("width %d\n", frame.frameInfo.width); + printf("Height %d\n", frame.frameInfo.height); + + ret = imageConvert(libHandle, devHandle, frame, gvspPixelBGR8, data, w, h); + if (IMV_OK != ret) + { + printf("imageConvert failed! ErrorCode[%d]\n", ret); + return ret; + } + + // printf("11111111111111\n", ret); + // cv::Mat im(frame.frameInfo.height, frame.frameInfo.width, CV_8UC3, frame.pData); + // cv::imwrite("/home/caowei/catkin_ws/output.png", im); + // cv::imwrite("output.png", im); + // printf("22222222222222\n", ret); + // // 向ros送 /image消息 + // sendToRos(frame); + + // 释放图像缓存 + ret = DLLReleaseFrame(devHandle, &frame); + if (IMV_OK != ret) + { + printf("Release frame failed! ErrorCode[%d]\n", ret); + return ret; + } + //////////////////////////////////////////////////////////////// + + // // 取图2秒 + // // get frame 2 seconds + // sleep(2000); + // 停止拉流 + // Stop grabbing + ret = DLLStopGrabbing(devHandle); + if (IMV_OK != ret) + { + printf("Stop grabbing failed! ErrorCode[%d]\n", ret); + return ret; + } + + return IMV_OK; +} + +int camera_stop() +{ + // 关闭相机 + // Close camera + ret = DLLClose(devHandle); + if (IMV_OK != ret) + { + printf("Close camera failed! ErrorCode[%d]\n", ret); + return 0; + } + + // 销毁设备句柄 + // Destroy Device Handle + if (NULL != devHandle) + { + // 销毁设备句柄 + // Destroy Device Handle + DLLDestroyHandle(devHandle); + } + + if (NULL != libHandle) + { + dlclose(libHandle); + } + + printf("end...\n"); +} +int main() +{ + char* data = (char*)malloc(9344*7000*3); + int w, h; + + ret = camera_init(); + if (ret != IMV_OK) return ret; + + ret = camera_start(12 * 10000); + if (ret != IMV_OK) return ret; + + ret = camera_cap((void**) & data, w, h, 5000); + if (ret != IMV_OK) return ret; + + cv::Mat im(h,w, CV_8UC3, data); + cv::imwrite("/home/caowei/catkin_ws/output.png", im); + cv::imwrite("output.png", im); + + ret = camera_cap((void**) & data, w, h, 5000); + if (ret != IMV_OK) return ret; + + cv::Mat im2(h,w, CV_8UC3, data); + cv::imwrite("/home/caowei/catkin_ws/output2.png", im2); + cv::imwrite("output2.png", im2); + + camera_stop(); + + if (data) + free(data); + return 0; +} +// +// +//int main() +//{ +// int ret = IMV_OK; +// unsigned int cameraIndex = 0; +// IMV_HANDLE devHandle = NULL; +// void* libHandle = NULL; +// DLL_DestroyHandle DLLDestroyHandle = NULL; +// IMV_Frame frame; +// +// // 加载SDK库 +// // Load SDK library +//#ifdef _WIN32 +// libHandle = 0; +//#else +// libHandle = dlopen("libMVSDK.so", RTLD_LAZY); +//#endif +// +// if (NULL == libHandle) +// { +// printf("Load MVSDKmd.dll library failed!\n"); +// return 0; +// } +// +// // 获取发现设备接口函数地址 +// // Get discover camera interface address +// DLLEnumDevices = (DLL_EnumDevices)dlsym(libHandle, "IMV_EnumDevices"); +// if (NULL == DLLEnumDevices) +// { +// printf("Get IMV_EnumDevices address failed!\n"); +// return 0; +// } +// +// // 获取创建设备句柄接口函数地址 +// // Get create Device Handle interface address +// DLLCreateHandle = (DLL_CreateHandle)dlsym(libHandle, "IMV_CreateHandle"); +// if (NULL == DLLCreateHandle) +// { +// printf("Get IMV_CreateHandle address failed!\n"); +// return 0; +// } +// +// // 获取销毁设备句柄接口函数地址 +// // Get destroy Device Handle interface address +// DLLDestroyHandle = (DLL_DestroyHandle)dlsym(libHandle, "IMV_DestroyHandle"); +// if (NULL == DLLDestroyHandle) +// { +// printf("Get IMV_DestroyHandle address failed!\n"); +// return 0; +// } +// +// // 获取打开相机接口函数地址 +// // Get open camera interface address +// DLLOpen = (DLL_Open)dlsym(libHandle, "IMV_Open"); +// if (NULL == DLLOpen) +// { +// printf("Get IMV_Open address failed!\n"); +// return 0; +// } +// +// // 获取注册数据帧回调接口函数地址 +// // Get register data frame callback interface address +// DLLAttachGrabbing = (DLL_AttachGrabbing)dlsym(libHandle, "IMV_AttachGrabbing"); +// if (NULL == DLLAttachGrabbing) +// { +// printf("Get IMV_AttachGrabbing address failed!\n"); +// return 0; +// } +// +// // 获取开始拉流接口函数地址 +// // Get start grabbing interface address +// DLLStartGrabbing = (DLL_StartGrabbing)dlsym(libHandle, "IMV_StartGrabbing"); +// if (NULL == DLLStartGrabbing) +// { +// printf("Get IMV_StartGrabbing address failed!\n"); +// return 0; +// } +// +// // 获取停止拉流接口函数地址 +// // Get stop grabbing interface address +// DLLStopGrabbing = (DLL_StopGrabbing)dlsym(libHandle, "IMV_StopGrabbing"); +// if (NULL == DLLStopGrabbing) +// { +// printf("Get IMV_StopGrabbing address failed!\n"); +// return 0; +// } +// +// // 获取 +// +// // 获取关闭相机接口函数地址 +// // Get close camera interface address +// DLLClose = (DLL_Close)dlsym(libHandle, "IMV_Close"); +// if (NULL == DLLClose) +// { +// printf("Get IMV_Close address failed!\n"); +// return 0; +// } +// +// // 获取获取一帧图像函数地址 +// DLLGetFrame = (DLL_GetFrame)dlsym(libHandle, "IMV_GetFrame"); +// if (NULL == DLLGetFrame) +// { +// printf("Get IMV_GetFrame address failed!\n"); +// return 0; +// } +// +// DLLReleaseFrame = (DLL_ReleaseFrame)dlsym(libHandle, "IMV_ReleaseFrame"); +// if (NULL == DLLReleaseFrame) +// { +// printf("Get IMV_ReleaseFrame address failed!\n"); +// return 0; +// } +// +// DLLClearFrameBuffer = (DLL_ClearFrameBuffer)dlsym(libHandle, "IMV_ClearFrameBuffer"); +// if (NULL == DLLClearFrameBuffer) +// { +// printf("Get IMV_ClearFrameBuffer address failed!\n"); +// return 0; +// } +// +// DLLExecuteCommandFeature = (DLL_ExecuteCommandFeature)dlsym(libHandle, "IMV_ExecuteCommandFeature"); +// if (NULL == DLLExecuteCommandFeature) +// { +// printf("Get IMV_ExecuteCommandFeature address failed!\n"); +// return 0; +// } +// +// DLLSetIntFeatureValue = (DLL_SetIntFeatureValue)dlsym(libHandle, "IMV_SetIntFeatureValue"); +// if (NULL == DLLSetIntFeatureValue) +// { +// printf("Get IMV_SetIntFeatureValue address failed!\n"); +// return 0; +// } +// +// DLLSetDoubleFeatureValue = (DLL_SetDoubleFeatureValue)dlsym(libHandle, "IMV_SetDoubleFeatureValue"); +// if (NULL == DLLSetDoubleFeatureValue) +// { +// printf("Get IMV_SetDoubleFeatureValue address failed!\n"); +// return 0; +// } +// +// +//////////////////////// 检查接口结束 +// // 发现设备 +// // discover camera +// IMV_DeviceList deviceInfoList; +// ret = DLLEnumDevices(&deviceInfoList, interfaceTypeAll); +// if (IMV_OK != ret) +// { +// printf("Enumeration devices failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// if (deviceInfoList.nDevNum < 1) +// { +// printf("no camera\n"); +// return 0; +// } +// +// // 打印相机基本信息(序号,类型,制造商信息,型号,序列号,用户自定义ID,IP地址) +// // Print camera info (Index, Type, Vendor, Model, Serial number, DeviceUserID, IP Address) +// +// displayDeviceInfo(deviceInfoList); +// // 选择需要连接的相机 +// // Select one camera to connect to +// // cameraIndex = selectDevice(deviceInfoList.nDevNum); +// cameraIndex = 0; // 第一个相机 +// +// // 创建设备句柄 +// // Create Device Handle +// ret = DLLCreateHandle(&devHandle, modeByIndex, (void*)&cameraIndex); +// if (IMV_OK != ret) +// { +// printf("Create devHandle failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// // 打开相机 +// ret = DLLOpen(devHandle); +// if (IMV_OK != ret) +// { +// printf("Open camera failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// // 设置软触发模式 +// ret = setSoftTriggerConf(libHandle, devHandle); +// if (IMV_OK != ret) +// { +// printf("setSoftTriggerConf failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// ret = DLLSetIntFeatureValue(devHandle, "Width", 9344); +// if (IMV_OK != ret) +// { +// printf("Set feature value Width failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// ret = DLLSetIntFeatureValue(devHandle, "Height", 7000); +// if (IMV_OK != ret) +// { +// printf("Set feature value Height failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// ret = DLLSetIntFeatureValue(devHandle, "OffsetX", 0); +// if (IMV_OK != ret) +// { +// printf("Set feature value OffsetX failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// ret = DLLSetIntFeatureValue(devHandle, "OffsetY", 0); +// if (IMV_OK != ret) +// { +// printf("Set feature value OffsetY failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// // 设置属性值曝光 +// // Set feature value +// ret = DLLSetDoubleFeatureValue(devHandle, "ExposureTime", 12*10000); +// if (IMV_OK != ret) +// { +// printf("Set feature value failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// // // 非多线程,不需要注册回调 +// // // 注册数据帧回调函数 +// // // Register data frame callback function +// // ret = DLLAttachGrabbing(devHandle, onGetFrame, NULL); +// // if (IMV_OK != ret) +// // { +// // printf("Attach grabbing failed! ErrorCode[%d]\n", ret); +// // return 0; +// // } +// +// // 开始拉流 +// // Start grabbing +// ret = DLLStartGrabbing(devHandle); +// if (IMV_OK != ret) +// { +// printf("Start grabbing failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// /////////////////////////获取一帧图像//////////////////////////// +// +// // 清除帧数据缓存 +// // Clear frame buffer +// ret = DLLClearFrameBuffer(devHandle); +// if (IMV_OK != ret) +// { +// printf("Clear frame buffer failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// // 执行软触发 +// // Execute soft trigger +// ret = DLLExecuteCommandFeature(devHandle, "TriggerSoftware"); +// if (IMV_OK != ret) +// { +// printf("Execute TriggerSoftware failed! ErrorCode[%d]\n", ret); +// return ret; +// } +// +// +// // 获取一帧图像, TIMEOUT 5000ms +// ret = DLLGetFrame(devHandle, &frame, 5000); +// if (IMV_OK != ret) +// { +// printf("Get frame failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// printf("width %d\n", frame.frameInfo.width); +// printf("Height %d\n", frame.frameInfo.height); +// +// ret = imageConvert(libHandle, devHandle, frame, gvspPixelBGR8); +// if (IMV_OK != ret) +// { +// printf("imageConvert failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// // printf("11111111111111\n", ret); +// // cv::Mat im(frame.frameInfo.width, frame.frameInfo.height, CV_8UC3, frame.pData); +// // cv::imwrite("/home/caowei/catkin_ws/output.png", im); +// // cv::imwrite("output.png", im); +// // printf("22222222222222\n", ret); +// // // 向ros送 /image消息 +// // sendToRos(frame); +// +// // 释放图像缓存 +// ret = DLLReleaseFrame(devHandle, &frame); +// if (IMV_OK != ret) +// { +// printf("Release frame failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// //////////////////////////////////////////////////////////////// +// +// // // 取图2秒 +// // // get frame 2 seconds +// // sleep(2000); +// +// // 停止拉流 +// // Stop grabbing +// ret = DLLStopGrabbing(devHandle); +// if (IMV_OK != ret) +// { +// printf("Stop grabbing failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// // 关闭相机 +// // Close camera +// ret = DLLClose(devHandle); +// if (IMV_OK != ret) +// { +// printf("Close camera failed! ErrorCode[%d]\n", ret); +// return 0; +// } +// +// // 销毁设备句柄 +// // Destroy Device Handle +// if (NULL != devHandle) +// { +// // 销毁设备句柄 +// // Destroy Device Handle +// DLLDestroyHandle(devHandle); +// } +// +// if (NULL != libHandle) +// { +// dlclose(libHandle); +// } +// +// printf("end...\n"); +// // getchar(); +// +// return 0; +//} + +} \ No newline at end of file diff --git a/CameraDriver.h b/CameraDriver.h new file mode 100644 index 0000000..1cc0acb --- /dev/null +++ b/CameraDriver.h @@ -0,0 +1,99 @@ +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#endif // !_WIN32 +#include "IMVApi.h" +#include "IMVDefines.h" + +#include +#include + +extern "C"{ + +#define MONO_CHANNEL_NUM 1 +#define RGB_CHANNEL_NUM 3 +#define BGR_CHANNEL_NUM 3 + +#define sleep(ms) usleep(1000 * ms) + +typedef const char* (IMV_CALL * DLL_GetVersion) (); +typedef int (IMV_CALL * DLL_EnumDevices) (OUT IMV_DeviceList *pDeviceList, IN unsigned int interfaceType); +typedef int (IMV_CALL * DLL_EnumDevicesByUnicast) (OUT IMV_DeviceList *pDeviceList, IN const char* pIpAddress); +typedef int (IMV_CALL * DLL_CreateHandle) (OUT IMV_HANDLE* handle, IN IMV_ECreateHandleMode mode, IN void* pIdentifier); +typedef int (IMV_CALL * DLL_DestroyHandle) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_GetDeviceInfo) (IN IMV_HANDLE handle, OUT IMV_DeviceInfo *pDevInfo); +typedef int (IMV_CALL * DLL_Open) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_OpenEx) (IN IMV_HANDLE handle, IN IMV_ECameraAccessPermission accessPermission); +typedef bool (IMV_CALL * DLL_IsOpen) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_Close) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_GIGE_ForceIpAddress) (IN IMV_HANDLE handle, IN const char* pIpAddress, IN const char* pSubnetMask, IN const char* pGateway); +typedef int (IMV_CALL * DLL_GIGE_GetAccessPermission) (IN IMV_HANDLE handle, IMV_ECameraAccessPermission* pAccessPermission); +typedef int (IMV_CALL * DLL_GIGE_SetAnswerTimeout) (IN IMV_HANDLE handle, IN unsigned int timeout); +typedef int (IMV_CALL * DLL_DownLoadGenICamXML) (IN IMV_HANDLE handle, IN const char* pFullFileName); +typedef int (IMV_CALL * DLL_SaveDeviceCfg) (IN IMV_HANDLE handle, IN const char* pFullFileName); +typedef int (IMV_CALL * DLL_LoadDeviceCfg) (IN IMV_HANDLE handle, IN const char* pFullFileName, OUT IMV_ErrorList* pErrorList); +typedef int (IMV_CALL * DLL_WriteUserPrivateData) (IN IMV_HANDLE handle, IN void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_ReadUserPrivateData) (IN IMV_HANDLE handle, OUT void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_WriteUARTData) (IN IMV_HANDLE handle, IN void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_ReadUARTData) (IN IMV_HANDLE handle, OUT void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_SubscribeConnectArg) (IN IMV_HANDLE handle, IN IMV_ConnectCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SubscribeParamUpdateArg) (IN IMV_HANDLE handle, IN IMV_ParamUpdateCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SubscribeStreamArg) (IN IMV_HANDLE handle, IN IMV_StreamCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SubscribeMsgChannelArg) (IN IMV_HANDLE handle, IN IMV_MsgChannelCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SetBufferCount) (IN IMV_HANDLE handle, IN unsigned int nSize); +typedef int (IMV_CALL * DLL_ClearFrameBuffer) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_GIGE_SetInterPacketTimeout) (IN IMV_HANDLE handle, IN unsigned int nTimeout); +typedef int (IMV_CALL * DLL_GIGE_SetSingleResendMaxPacketNum) (IN IMV_HANDLE handle, IN unsigned int maxPacketNum); +typedef int (IMV_CALL * DLL_GIGE_SetMaxLostPacketNum) (IN IMV_HANDLE handle, IN unsigned int maxLostPacketNum); +typedef int (IMV_CALL * DLL_StartGrabbing) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_StartGrabbingEx) (IN IMV_HANDLE handle, IN uint64_t maxImagesGrabbed, IN IMV_EGrabStrategy strategy); +typedef bool (IMV_CALL * DLL_IsGrabbing) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_StopGrabbing) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_AttachGrabbing) (IN IMV_HANDLE handle, IN IMV_FrameCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_GetFrame) (IN IMV_HANDLE handle, OUT IMV_Frame* pFrame, IN unsigned int timeoutMS); +typedef int (IMV_CALL * DLL_ReleaseFrame) (IN IMV_HANDLE handle, IN IMV_Frame* pFrame); +typedef int (IMV_CALL * DLL_CloneFrame) (IN IMV_HANDLE handle, IN IMV_Frame* pFrame, OUT IMV_Frame* pCloneFrame); +typedef int (IMV_CALL * DLL_GetChunkDataByIndex) (IN IMV_HANDLE handle, IN IMV_Frame* pFrame, IN unsigned int index, OUT IMV_ChunkDataInfo *pChunkDataInfo); +typedef int (IMV_CALL * DLL_GetStatisticsInfo) (IN IMV_HANDLE handle, OUT IMV_StreamStatisticsInfo* pStreamStatsInfo); +typedef int (IMV_CALL * DLL_ResetStatisticsInfo) (IN IMV_HANDLE handle); +typedef bool (IMV_CALL * DLL_FeatureIsAvailable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsReadable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsWriteable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsStreamable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsValid) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef int (IMV_CALL * DLL_GetIntFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_GetIntFeatureMin) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_GetIntFeatureMax) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_GetIntFeatureInc) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_SetIntFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN int64_t intValue); +typedef int (IMV_CALL * DLL_GetDoubleFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); +typedef int (IMV_CALL * DLL_GetDoubleFeatureMin) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); +typedef int (IMV_CALL * DLL_GetDoubleFeatureMax) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); +typedef int (IMV_CALL * DLL_SetDoubleFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN double doubleValue); +typedef int (IMV_CALL * DLL_GetBoolFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT bool* pBoolValue); +typedef int (IMV_CALL * DLL_SetBoolFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN bool boolValue); +typedef int (IMV_CALL * DLL_GetEnumFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT uint64_t* pEnumValue); +typedef int (IMV_CALL * DLL_SetEnumFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN uint64_t enumValue); +typedef int (IMV_CALL * DLL_GetEnumFeatureSymbol) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_String* pEnumSymbol); +typedef int (IMV_CALL * DLL_SetEnumFeatureSymbol) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN const char* pEnumSymbol); +typedef int (IMV_CALL * DLL_GetEnumFeatureEntryNum) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT unsigned int* pEntryNum); +typedef int (IMV_CALL * DLL_GetEnumFeatureEntrys) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_EnumEntryList* pEnumEntryList); +typedef int (IMV_CALL * DLL_GetStringFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_String* pStringValue); +typedef int (IMV_CALL * DLL_SetStringFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN const char* pStringValue); +typedef int (IMV_CALL * DLL_ExecuteCommandFeature) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef int (IMV_CALL * DLL_PixelConvert) (IN IMV_HANDLE handle, IN_OUT IMV_PixelConvertParam* pstPixelConvertParam); +typedef int (IMV_CALL * DLL_OpenRecord) (IN IMV_HANDLE handle, IN IMV_RecordParam *pstRecordParam); +typedef int (IMV_CALL * DLL_InputOneFrame) (IN IMV_HANDLE handle, IN IMV_RecordFrameInfoParam *pstRecordFrameInfoParam); +typedef int (IMV_CALL * DLL_CloseRecord) (IN IMV_HANDLE handle); + + +int camera_init(); +int camera_start(int epx_time = 12 * 10000); +int camera_stop(); +int camera_cap(void** data, int& w, int& h, int time_out); + +} \ No newline at end of file diff --git a/CameraPublisher.cpp b/CameraPublisher.cpp new file mode 100644 index 0000000..833340a --- /dev/null +++ b/CameraPublisher.cpp @@ -0,0 +1,794 @@ +#include +#include +#include +#include +#include +#include +#include "IMVApi.h" +#include "IMVDefines.h" + +#include +#include + +extern "C"{ + +#define MONO_CHANNEL_NUM 1 +#define RGB_CHANNEL_NUM 3 +#define BGR_CHANNEL_NUM 3 + +#define sleep(ms) usleep(1000 * ms) + +typedef const char* (IMV_CALL * DLL_GetVersion) (); +typedef int (IMV_CALL * DLL_EnumDevices) (OUT IMV_DeviceList *pDeviceList, IN unsigned int interfaceType); +typedef int (IMV_CALL * DLL_EnumDevicesByUnicast) (OUT IMV_DeviceList *pDeviceList, IN const char* pIpAddress); +typedef int (IMV_CALL * DLL_CreateHandle) (OUT IMV_HANDLE* handle, IN IMV_ECreateHandleMode mode, IN void* pIdentifier); +typedef int (IMV_CALL * DLL_DestroyHandle) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_GetDeviceInfo) (IN IMV_HANDLE handle, OUT IMV_DeviceInfo *pDevInfo); +typedef int (IMV_CALL * DLL_Open) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_OpenEx) (IN IMV_HANDLE handle, IN IMV_ECameraAccessPermission accessPermission); +typedef bool (IMV_CALL * DLL_IsOpen) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_Close) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_GIGE_ForceIpAddress) (IN IMV_HANDLE handle, IN const char* pIpAddress, IN const char* pSubnetMask, IN const char* pGateway); +typedef int (IMV_CALL * DLL_GIGE_GetAccessPermission) (IN IMV_HANDLE handle, IMV_ECameraAccessPermission* pAccessPermission); +typedef int (IMV_CALL * DLL_GIGE_SetAnswerTimeout) (IN IMV_HANDLE handle, IN unsigned int timeout); +typedef int (IMV_CALL * DLL_DownLoadGenICamXML) (IN IMV_HANDLE handle, IN const char* pFullFileName); +typedef int (IMV_CALL * DLL_SaveDeviceCfg) (IN IMV_HANDLE handle, IN const char* pFullFileName); +typedef int (IMV_CALL * DLL_LoadDeviceCfg) (IN IMV_HANDLE handle, IN const char* pFullFileName, OUT IMV_ErrorList* pErrorList); +typedef int (IMV_CALL * DLL_WriteUserPrivateData) (IN IMV_HANDLE handle, IN void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_ReadUserPrivateData) (IN IMV_HANDLE handle, OUT void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_WriteUARTData) (IN IMV_HANDLE handle, IN void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_ReadUARTData) (IN IMV_HANDLE handle, OUT void* pBuffer, IN_OUT unsigned int* pLength); +typedef int (IMV_CALL * DLL_SubscribeConnectArg) (IN IMV_HANDLE handle, IN IMV_ConnectCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SubscribeParamUpdateArg) (IN IMV_HANDLE handle, IN IMV_ParamUpdateCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SubscribeStreamArg) (IN IMV_HANDLE handle, IN IMV_StreamCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SubscribeMsgChannelArg) (IN IMV_HANDLE handle, IN IMV_MsgChannelCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_SetBufferCount) (IN IMV_HANDLE handle, IN unsigned int nSize); +typedef int (IMV_CALL * DLL_ClearFrameBuffer) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_GIGE_SetInterPacketTimeout) (IN IMV_HANDLE handle, IN unsigned int nTimeout); +typedef int (IMV_CALL * DLL_GIGE_SetSingleResendMaxPacketNum) (IN IMV_HANDLE handle, IN unsigned int maxPacketNum); +typedef int (IMV_CALL * DLL_GIGE_SetMaxLostPacketNum) (IN IMV_HANDLE handle, IN unsigned int maxLostPacketNum); +typedef int (IMV_CALL * DLL_StartGrabbing) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_StartGrabbingEx) (IN IMV_HANDLE handle, IN uint64_t maxImagesGrabbed, IN IMV_EGrabStrategy strategy); +typedef bool (IMV_CALL * DLL_IsGrabbing) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_StopGrabbing) (IN IMV_HANDLE handle); +typedef int (IMV_CALL * DLL_AttachGrabbing) (IN IMV_HANDLE handle, IN IMV_FrameCallBack proc, IN void* pUser); +typedef int (IMV_CALL * DLL_GetFrame) (IN IMV_HANDLE handle, OUT IMV_Frame* pFrame, IN unsigned int timeoutMS); +typedef int (IMV_CALL * DLL_ReleaseFrame) (IN IMV_HANDLE handle, IN IMV_Frame* pFrame); +typedef int (IMV_CALL * DLL_CloneFrame) (IN IMV_HANDLE handle, IN IMV_Frame* pFrame, OUT IMV_Frame* pCloneFrame); +typedef int (IMV_CALL * DLL_GetChunkDataByIndex) (IN IMV_HANDLE handle, IN IMV_Frame* pFrame, IN unsigned int index, OUT IMV_ChunkDataInfo *pChunkDataInfo); +typedef int (IMV_CALL * DLL_GetStatisticsInfo) (IN IMV_HANDLE handle, OUT IMV_StreamStatisticsInfo* pStreamStatsInfo); +typedef int (IMV_CALL * DLL_ResetStatisticsInfo) (IN IMV_HANDLE handle); +typedef bool (IMV_CALL * DLL_FeatureIsAvailable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsReadable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsWriteable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsStreamable) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef bool (IMV_CALL * DLL_FeatureIsValid) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef int (IMV_CALL * DLL_GetIntFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_GetIntFeatureMin) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_GetIntFeatureMax) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_GetIntFeatureInc) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); +typedef int (IMV_CALL * DLL_SetIntFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN int64_t intValue); +typedef int (IMV_CALL * DLL_GetDoubleFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); +typedef int (IMV_CALL * DLL_GetDoubleFeatureMin) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); +typedef int (IMV_CALL * DLL_GetDoubleFeatureMax) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); +typedef int (IMV_CALL * DLL_SetDoubleFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN double doubleValue); +typedef int (IMV_CALL * DLL_GetBoolFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT bool* pBoolValue); +typedef int (IMV_CALL * DLL_SetBoolFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN bool boolValue); +typedef int (IMV_CALL * DLL_GetEnumFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT uint64_t* pEnumValue); +typedef int (IMV_CALL * DLL_SetEnumFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN uint64_t enumValue); +typedef int (IMV_CALL * DLL_GetEnumFeatureSymbol) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_String* pEnumSymbol); +typedef int (IMV_CALL * DLL_SetEnumFeatureSymbol) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN const char* pEnumSymbol); +typedef int (IMV_CALL * DLL_GetEnumFeatureEntryNum) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT unsigned int* pEntryNum); +typedef int (IMV_CALL * DLL_GetEnumFeatureEntrys) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_EnumEntryList* pEnumEntryList); +typedef int (IMV_CALL * DLL_GetStringFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_String* pStringValue); +typedef int (IMV_CALL * DLL_SetStringFeatureValue) (IN IMV_HANDLE handle, IN const char* pFeatureName, IN const char* pStringValue); +typedef int (IMV_CALL * DLL_ExecuteCommandFeature) (IN IMV_HANDLE handle, IN const char* pFeatureName); +typedef int (IMV_CALL * DLL_PixelConvert) (IN IMV_HANDLE handle, IN_OUT IMV_PixelConvertParam* pstPixelConvertParam); +typedef int (IMV_CALL * DLL_OpenRecord) (IN IMV_HANDLE handle, IN IMV_RecordParam *pstRecordParam); +typedef int (IMV_CALL * DLL_InputOneFrame) (IN IMV_HANDLE handle, IN IMV_RecordFrameInfoParam *pstRecordFrameInfoParam); +typedef int (IMV_CALL * DLL_CloseRecord) (IN IMV_HANDLE handle); + + + +// ***********开始: 这部分处理与SDK操作相机无关,用于显示设备列表 *********** +// ***********BEGIN: These functions are not related to API call and used to display device info*********** +// 数据帧回调函数 +// Data frame callback function +static void onGetFrame(IMV_Frame* pFrame, void* pUser) +{ + if (pFrame == NULL) + { + printf("pFrame is NULL\n"); + return; + } + + printf("Get frame blockId = %llu\n", pFrame->frameInfo.blockId); + + return; +} + +static void displayDeviceInfo(IMV_DeviceList deviceInfoList) +{ + IMV_DeviceInfo* pDevInfo = NULL; + unsigned int cameraIndex = 0; + char vendorNameCat[11]; + char cameraNameCat[16]; + + // 打印Title行 + // Print title line + printf("\nIdx Type Vendor Model S/N DeviceUserID IP Address \n"); + printf("------------------------------------------------------------------------------\n"); + + for (cameraIndex = 0; cameraIndex < deviceInfoList.nDevNum; cameraIndex++) + { + pDevInfo = &deviceInfoList.pDevInfo[cameraIndex]; + // 设备列表的相机索引 最大表示字数:3 + // Camera index in device list, display in 3 characters + printf("%-3d", cameraIndex + 1); + + // 相机的设备类型(GigE,U3V,CL,PCIe) + // Camera type + switch (pDevInfo->nCameraType) + { + case typeGigeCamera:printf(" GigE");break; + case typeU3vCamera:printf(" U3V ");break; + case typeCLCamera:printf(" CL ");break; + case typePCIeCamera:printf(" PCIe");break; + default:printf(" ");break; + } + + // 制造商信息 最大表示字数:10 + // Camera vendor name, display in 10 characters + if (strlen(pDevInfo->vendorName) > 10) + { + memcpy(vendorNameCat, pDevInfo->vendorName, 7); + vendorNameCat[7] = '\0'; + strcat(vendorNameCat, "..."); + printf(" %-10.10s", vendorNameCat); + } + else + { + printf(" %-10.10s", pDevInfo->vendorName); + } + + // 相机的型号信息 最大表示字数:10 + // Camera model name, display in 10 characters + printf(" %-10.10s", pDevInfo->modelName); + + // 相机的序列号 最大表示字数:15 + // Camera serial number, display in 15 characters + printf(" %-15.15s", pDevInfo->serialNumber); + + // 自定义用户ID 最大表示字数:15 + // Camera user id, display in 15 characters + if (strlen(pDevInfo->cameraName) > 15) + { + memcpy(cameraNameCat, pDevInfo->cameraName, 12); + cameraNameCat[12] = '\0'; + strcat(cameraNameCat, "..."); + printf(" %-15.15s", cameraNameCat); + } + else + { + printf(" %-15.15s", pDevInfo->cameraName); + } + + // GigE相机时获取IP地址 + // IP address of GigE camera + if (pDevInfo->nCameraType == typeGigeCamera) + { + printf(" %s", pDevInfo->DeviceSpecificInfo.gigeDeviceInfo.ipAddress); + } + + printf("\n"); + } + + return; +} + +static char* trim(char* pStr) +{ + char* pDst = pStr; + char* pTemStr = NULL; + + if (pDst != NULL) + { + pTemStr = pDst + strlen(pStr) - 1; + while (*pDst == ' ') + { + pDst++; + } + while ((pTemStr > pDst) && (*pTemStr == ' ')) + { + *pTemStr-- = '\0'; + } + } + return pDst; +} + +static int isInputValid(char* pInpuStr) +{ + char numChar; + char* pStr = pInpuStr; + while (*pStr != '\0') + { + numChar = *pStr; + if ((numChar > '9') || (numChar < '0')) + { + return -1; + } + pStr++; + } + return 0; +} + +static unsigned int selectDevice(unsigned int cameraCnt) +{ + char inputStr[256]; + char* pTrimStr; + int inputIndex = -1; + int ret = -1; + char* find = NULL; + + printf("\nPlease input the camera index: "); + while (1) + { + memset(inputStr, 0, sizeof(inputStr)); + fgets(inputStr, sizeof(inputStr), stdin); + + // 清空输入缓存 + // clear flush + fflush(stdin); + + // fgets比gets多吃一个换行符号,取出换行符号 + // fgets eats one more line feed symbol than gets, and takes out the line feed symbol + find = strchr(inputStr, '\n'); + if (find) { *find = '\0'; } + + pTrimStr = trim(inputStr); + ret = isInputValid(pTrimStr); + if (ret == 0) + { + inputIndex = atoi(pTrimStr); + // 输入的序号从1开始 + // Input index starts from 1 + inputIndex -= 1; + if ((inputIndex >= 0) && (inputIndex < (int)cameraCnt)) + { + break; + } + } + + printf("Input invalid! Please input the camera index: "); + } + return (unsigned int)inputIndex; +} + +// ***********结束: 这部分处理与SDK操作相机无关,用于显示设备列表 *********** +// ***********END: These functions are not related to API call and used to display device info*********** +static int setSoftTriggerConf(void* libHandle, IMV_HANDLE devHandle) +{ + int ret = IMV_OK; + // 获取设置触发源为软触发函数地址 + DLL_SetEnumFeatureSymbol DLLSetEnumFeatureSymbol = (DLL_SetEnumFeatureSymbol)dlsym(libHandle, "IMV_SetEnumFeatureSymbol"); + if (NULL == DLLSetEnumFeatureSymbol) + { + printf("Get IMV_SetEnumFeatureSymbol address failed!\n"); + return ret; + } + + // 设置触发源为软触发 + // Set trigger source to Software + ret = DLLSetEnumFeatureSymbol(devHandle, "TriggerSource", "Software"); + if (IMV_OK != ret) + { + printf("Set triggerSource value failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置触发器 + // Set trigger selector to FrameStart + ret = DLLSetEnumFeatureSymbol(devHandle, "TriggerSelector", "FrameStart"); + if (IMV_OK != ret) + { + printf("Set triggerSelector value failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置触发模式 + // Set trigger mode to On + ret = DLLSetEnumFeatureSymbol(devHandle, "TriggerMode", "On"); + if (IMV_OK != ret) + { + printf("Set triggerMode value failed! ErrorCode[%d]\n", ret); + return ret; + } + + return ret; +} + +// Image convert +static int imageConvert(void* libHandle, IMV_HANDLE devHandle, IMV_Frame frame, IMV_EPixelType convertFormat) +{ + IMV_PixelConvertParam stPixelConvertParam; + unsigned char* pDstBuf = NULL; + unsigned int nDstBufSize = 0; + int ret = IMV_OK; + FILE* hFile = NULL; + const char* pFileName = NULL; + const char* pConvertFormatStr = NULL; + + // 获取设置触发源为软触发函数地址 + DLL_PixelConvert DLLPixelConvert = (DLL_PixelConvert)dlsym(libHandle, "IMV_PixelConvert"); + if (NULL == DLLPixelConvert) + { + printf("Get IMV_PixelConvert address failed!\n"); + return ret; + } + + switch (convertFormat) + { + case gvspPixelRGB8: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height * 3; + pFileName = (const char*)"convertRGB8.bmp"; + pConvertFormatStr = (const char*)"RGB8"; + break; + + case gvspPixelBGR8: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height * 3; + pFileName = (const char*)"convertBGR8.bmp"; + pConvertFormatStr = (const char*)"BGR8"; + break; + case gvspPixelBGRA8: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height * 4; + pFileName = (const char*)"convertBGRA8.bmp"; + pConvertFormatStr = (const char*)"BGRA8"; + break; + case gvspPixelMono8: + default: + nDstBufSize = sizeof(unsigned char) * frame.frameInfo.width * frame.frameInfo.height; + pFileName = (const char*)"convertMono8.bmp"; + pConvertFormatStr = (const char*)"Mono8"; + break; + } + + pDstBuf = (unsigned char*)malloc(nDstBufSize); + if (NULL == pDstBuf) + { + printf("malloc pDstBuf failed!\n"); + return -1; + } + + // 图像转换成BGR8 + // convert image to BGR8 + memset(&stPixelConvertParam, 0, sizeof(stPixelConvertParam)); + stPixelConvertParam.nWidth = frame.frameInfo.width; + stPixelConvertParam.nHeight = frame.frameInfo.height; + stPixelConvertParam.ePixelFormat = frame.frameInfo.pixelFormat; + stPixelConvertParam.pSrcData = frame.pData; + stPixelConvertParam.nSrcDataLen = frame.frameInfo.size; + stPixelConvertParam.nPaddingX = frame.frameInfo.paddingX; + stPixelConvertParam.nPaddingY = frame.frameInfo.paddingY; + stPixelConvertParam.eBayerDemosaic = demosaicNearestNeighbor; + stPixelConvertParam.eDstPixelFormat = convertFormat; + stPixelConvertParam.pDstBuf = pDstBuf; + stPixelConvertParam.nDstBufSize = nDstBufSize; + + ret = DLLPixelConvert(devHandle, &stPixelConvertParam); + if (IMV_OK == ret) + { + printf("image convert to %s successfully! nDstDataLen (%u)\n", + pConvertFormatStr, stPixelConvertParam.nDstBufSize); + + // cv::Mat im(stPixelConvertParam.nHeight, stPixelConvertParam.nWidth, CV_8UC3, stPixelConvertParam.pDstBuf); + // // 内参矩阵 + // cv::Mat cameraMatrix = (cv::Mat_(3, 3) << 11057.154, 0, 4538.85, 0, 11044.943, 3350.918, 0, 0, 1); + // // 设置畸变系数 + // cv::Mat distCoeffs = (cv::Mat_(1, 5) << 0.311583980, -14.5864013, -0.00630134677, -0.00466401902, 183.662957); + // // 准备输出图像 + // cv::Mat undistortedImg; + // // 使用cv::undistort函数进行校正 + // cv::undistort(src, undistortedImg, cameraMatrix, distCoeffs); + + cv::imwrite("/home/caowei/catkin_ws/output.png", undistortedImg); + cv::imwrite("output.png", undistortedImg); + + // hFile = fopen(pFileName, "wb"); + // if (hFile != NULL) + // { + // fwrite((void*)pDstBuf, 1, stPixelConvertParam.nDstBufSize, hFile); + // fclose(hFile); + // } + // else + // { + // // 如果打开失败,请用root权限执行 + // // If opefailed, Run as root + // printf("Open file (%s) failed!\n", pFileName); + // } + } + else + { + printf("image convert to %s failed! ErrorCode[%d]\n", pConvertFormatStr, ret); + } + + if (pDstBuf) + { + free(pDstBuf); + pDstBuf = NULL; + } + + return IMV_OK; +} + +static void sendToRos(IMV_Frame frame) +{ + IMV_FlipImageParam stFlipImageParam; + unsigned int nChannelNum = 0; + int ret = IMV_OK; + FILE* hFile = NULL; + + memset(&stFlipImageParam, 0, sizeof(stFlipImageParam)); + + if (gvspPixelBGR8 == frame.frameInfo.pixelFormat) + { + stFlipImageParam.pSrcData = frame.pData; + stFlipImageParam.nSrcDataLen = frame.frameInfo.width * frame.frameInfo.height * BGR_CHANNEL_NUM; + stFlipImageParam.ePixelFormat = frame.frameInfo.pixelFormat; + nChannelNum = BGR_CHANNEL_NUM; + } + else + { + printf("image convert to BGR8 failed! ErrorCode[%d]\n", ret); + } + + // 向ros发送/image消息 + do + { + + } while (false); + +} + + +int main() +{ + int ret = IMV_OK; + unsigned int cameraIndex = 0; + IMV_HANDLE devHandle = NULL; + void* libHandle = NULL; + DLL_DestroyHandle DLLDestroyHandle = NULL; + IMV_Frame frame; + + // 加载SDK库 + // Load SDK library + libHandle = dlopen("libMVSDK.so", RTLD_LAZY); + if (NULL == libHandle) + { + printf("Load MVSDKmd.dll library failed!\n"); + return 0; + } + + // 获取发现设备接口函数地址 + // Get discover camera interface address + DLL_EnumDevices DLLEnumDevices = (DLL_EnumDevices)dlsym(libHandle, "IMV_EnumDevices"); + if (NULL == DLLEnumDevices) + { + printf("Get IMV_EnumDevices address failed!\n"); + return 0; + } + + // 获取创建设备句柄接口函数地址 + // Get create Device Handle interface address + DLL_CreateHandle DLLCreateHandle = (DLL_CreateHandle)dlsym(libHandle, "IMV_CreateHandle"); + if (NULL == DLLCreateHandle) + { + printf("Get IMV_CreateHandle address failed!\n"); + return 0; + } + + // 获取销毁设备句柄接口函数地址 + // Get destroy Device Handle interface address + DLLDestroyHandle = (DLL_DestroyHandle)dlsym(libHandle, "IMV_DestroyHandle"); + if (NULL == DLLDestroyHandle) + { + printf("Get IMV_DestroyHandle address failed!\n"); + return 0; + } + + // 获取打开相机接口函数地址 + // Get open camera interface address + DLL_Open DLLOpen = (DLL_Open)dlsym(libHandle, "IMV_Open"); + if (NULL == DLLOpen) + { + printf("Get IMV_Open address failed!\n"); + return 0; + } + + // 获取注册数据帧回调接口函数地址 + // Get register data frame callback interface address + DLL_AttachGrabbing DLLAttachGrabbing = (DLL_AttachGrabbing)dlsym(libHandle, "IMV_AttachGrabbing"); + if (NULL == DLLAttachGrabbing) + { + printf("Get IMV_AttachGrabbing address failed!\n"); + return 0; + } + + // 获取开始拉流接口函数地址 + // Get start grabbing interface address + DLL_StartGrabbing DLLStartGrabbing = (DLL_StartGrabbing)dlsym(libHandle, "IMV_StartGrabbing"); + if (NULL == DLLStartGrabbing) + { + printf("Get IMV_StartGrabbing address failed!\n"); + return 0; + } + + // 获取停止拉流接口函数地址 + // Get stop grabbing interface address + DLL_StopGrabbing DLLStopGrabbing = (DLL_StopGrabbing)dlsym(libHandle, "IMV_StopGrabbing"); + if (NULL == DLLStopGrabbing) + { + printf("Get IMV_StopGrabbing address failed!\n"); + return 0; + } + + // 获取 + + // 获取关闭相机接口函数地址 + // Get close camera interface address + DLL_Close DLLClose = (DLL_Close)dlsym(libHandle, "IMV_Close"); + if (NULL == DLLClose) + { + printf("Get IMV_Close address failed!\n"); + return 0; + } + + // 获取获取一帧图像函数地址 + DLL_GetFrame DLLGetFrame = (DLL_GetFrame)dlsym(libHandle, "IMV_GetFrame"); + if (NULL == DLLGetFrame) + { + printf("Get IMV_GetFrame address failed!\n"); + return 0; + } + + DLL_ReleaseFrame DLLReleaseFrame = (DLL_ReleaseFrame)dlsym(libHandle, "IMV_ReleaseFrame"); + if (NULL == DLLReleaseFrame) + { + printf("Get IMV_ReleaseFrame address failed!\n"); + return 0; + } + + DLL_ClearFrameBuffer DLLClearFrameBuffer = (DLL_ClearFrameBuffer)dlsym(libHandle, "IMV_ClearFrameBuffer"); + if (NULL == DLLClearFrameBuffer) + { + printf("Get IMV_ClearFrameBuffer address failed!\n"); + return 0; + } + + DLL_ExecuteCommandFeature DLLExecuteCommandFeature = (DLL_ExecuteCommandFeature)dlsym(libHandle, "IMV_ExecuteCommandFeature"); + if (NULL == DLLExecuteCommandFeature) + { + printf("Get IMV_ExecuteCommandFeature address failed!\n"); + return 0; + } + + DLL_SetIntFeatureValue DLLSetIntFeatureValue = (DLL_SetIntFeatureValue)dlsym(libHandle, "IMV_SetIntFeatureValue"); + if (NULL == DLLSetIntFeatureValue) + { + printf("Get IMV_SetIntFeatureValue address failed!\n"); + return 0; + } + + DLL_SetDoubleFeatureValue DLLSetDoubleFeatureValue = (DLL_SetDoubleFeatureValue)dlsym(libHandle, "IMV_SetDoubleFeatureValue"); + if (NULL == DLLSetDoubleFeatureValue) + { + printf("Get IMV_SetDoubleFeatureValue address failed!\n"); + return 0; + } + + + +////////////////////// 检查接口结束 + // 发现设备 + // discover camera + IMV_DeviceList deviceInfoList; + ret = DLLEnumDevices(&deviceInfoList, interfaceTypeAll); + if (IMV_OK != ret) + { + printf("Enumeration devices failed! ErrorCode[%d]\n", ret); + return 0; + } + + if (deviceInfoList.nDevNum < 1) + { + printf("no camera\n"); + return 0; + } + + // 打印相机基本信息(序号,类型,制造商信息,型号,序列号,用户自定义ID,IP地址) + // Print camera info (Index, Type, Vendor, Model, Serial number, DeviceUserID, IP Address) + + displayDeviceInfo(deviceInfoList); + // 选择需要连接的相机 + // Select one camera to connect to + // cameraIndex = selectDevice(deviceInfoList.nDevNum); + cameraIndex = 0; // 第一个相机 + + // 创建设备句柄 + // Create Device Handle + ret = DLLCreateHandle(&devHandle, modeByIndex, (void*)&cameraIndex); + if (IMV_OK != ret) + { + printf("Create devHandle failed! ErrorCode[%d]\n", ret); + return 0; + } + + // 打开相机 + ret = DLLOpen(devHandle); + if (IMV_OK != ret) + { + printf("Open camera failed! ErrorCode[%d]\n", ret); + return 0; + } + + // 设置软触发模式 + ret = setSoftTriggerConf(libHandle, devHandle); + if (IMV_OK != ret) + { + printf("setSoftTriggerConf failed! ErrorCode[%d]\n", ret); + return 0; + } + + ret = DLLSetIntFeatureValue(devHandle, "Width", 9344); + if (IMV_OK != ret) + { + printf("Set feature value Width failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "Height", 7000); + if (IMV_OK != ret) + { + printf("Set feature value Height failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "OffsetX", 0); + if (IMV_OK != ret) + { + printf("Set feature value OffsetX failed! ErrorCode[%d]\n", ret); + return ret; + } + + ret = DLLSetIntFeatureValue(devHandle, "OffsetY", 0); + if (IMV_OK != ret) + { + printf("Set feature value OffsetY failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 设置属性值曝光 + // Set feature value + ret = DLLSetDoubleFeatureValue(devHandle, "ExposureTime", 12*10000); + if (IMV_OK != ret) + { + printf("Set feature value failed! ErrorCode[%d]\n", ret); + return ret; + } + + // // 非多线程,不需要注册回调 + // // 注册数据帧回调函数 + // // Register data frame callback function + // ret = DLLAttachGrabbing(devHandle, onGetFrame, NULL); + // if (IMV_OK != ret) + // { + // printf("Attach grabbing failed! ErrorCode[%d]\n", ret); + // return 0; + // } + + // 开始拉流 + // Start grabbing + ret = DLLStartGrabbing(devHandle); + if (IMV_OK != ret) + { + printf("Start grabbing failed! ErrorCode[%d]\n", ret); + return 0; + } + + /////////////////////////获取一帧图像//////////////////////////// + + // 清除帧数据缓存 + // Clear frame buffer + ret = DLLClearFrameBuffer(devHandle); + if (IMV_OK != ret) + { + printf("Clear frame buffer failed! ErrorCode[%d]\n", ret); + return ret; + } + + // 执行软触发 + // Execute soft trigger + ret = DLLExecuteCommandFeature(devHandle, "TriggerSoftware"); + if (IMV_OK != ret) + { + printf("Execute TriggerSoftware failed! ErrorCode[%d]\n", ret); + return ret; + } + + + // 获取一帧图像, TIMEOUT 5000ms + ret = DLLGetFrame(devHandle, &frame, 5000); + if (IMV_OK != ret) + { + printf("Get frame failed! ErrorCode[%d]\n", ret); + return 0; + } + + printf("width %d\n", frame.frameInfo.width); + printf("Height %d\n", frame.frameInfo.height); + + ret = imageConvert(libHandle, devHandle, frame, gvspPixelBGR8); + if (IMV_OK != ret) + { + printf("imageConvert failed! ErrorCode[%d]\n", ret); + return 0; + } + // printf("11111111111111\n", ret); + // cv::Mat im(frame.frameInfo.width, frame.frameInfo.height, CV_8UC3, frame.pData); + // cv::imwrite("/home/caowei/catkin_ws/output.png", im); + // cv::imwrite("output.png", im); + // printf("22222222222222\n", ret); + // // 向ros送 /image消息 + // sendToRos(frame); + + // 释放图像缓存 + ret = DLLReleaseFrame(devHandle, &frame); + if (IMV_OK != ret) + { + printf("Release frame failed! ErrorCode[%d]\n", ret); + return 0; + } + //////////////////////////////////////////////////////////////// + + // // 取图2秒 + // // get frame 2 seconds + // sleep(2000); + + // 停止拉流 + // Stop grabbing + ret = DLLStopGrabbing(devHandle); + if (IMV_OK != ret) + { + printf("Stop grabbing failed! ErrorCode[%d]\n", ret); + return 0; + } + + // 关闭相机 + // Close camera + ret = DLLClose(devHandle); + if (IMV_OK != ret) + { + printf("Close camera failed! ErrorCode[%d]\n", ret); + return 0; + } + + // 销毁设备句柄 + // Destroy Device Handle + if (NULL != devHandle) + { + // 销毁设备句柄 + // Destroy Device Handle + DLLDestroyHandle(devHandle); + } + + if (NULL != libHandle) + { + dlclose(libHandle); + } + + printf("end...\n"); + // getchar(); + + return 0; +} + +} \ No newline at end of file diff --git a/Corners.cpp b/Corners.cpp new file mode 100644 index 0000000..75a59c7 --- /dev/null +++ b/Corners.cpp @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include + +#include "opencv2/opencv.hpp" +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "lidar_camera_calibration/Utils.h" + +int iteration_count = 0; +std::vector< std::vector > stored_corners; + +bool getCorners(cv::Mat img, pcl::PointCloud scan, cv::Mat P, int num_of_markers, int MAX_ITERS) +{ + + ROS_INFO_STREAM("iteration number: " << iteration_count << "\n"); + + /*Masking happens here */ + cv::Mat edge_mask = cv::Mat::zeros(img.size(), CV_8UC1); + //edge_mask(cv::Rect(520, 205, 300, 250))=1; + edge_mask(cv::Rect(0, 0, img.cols, img.rows))=1; + img.copyTo(edge_mask, edge_mask); + //pcl::io::savePCDFileASCII ("/home/vishnu/final1.pcd", scan.point_cloud); + + img = edge_mask; + + //cv:imwrite("/home/vishnu/marker.png", edge_mask); + + pcl::PointCloud pc = scan; + //scan = Velodyne::Velodyne(filtered_pc); + + cv::Rect frame(0, 0, img.cols, img.rows); + + //pcl::io::savePCDFileASCII("/home/vishnu/final2.pcd", scan.point_cloud); + + cv::Mat image_edge_laser = project(P, frame, scan, NULL); + cv::threshold(image_edge_laser, image_edge_laser, 10, 255, 0); + + cv::Mat combined_rgb_laser; + std::vector rgb_laser_channels; + + rgb_laser_channels.push_back(image_edge_laser); + rgb_laser_channels.push_back(cv::Mat::zeros(image_edge_laser.size(), CV_8UC1)); + rgb_laser_channels.push_back(img); + + cv::merge(rgb_laser_channels, combined_rgb_laser); + /*cv::namedWindow("combined", cv::WINDOW_NORMAL); + cv::imshow("combined", combined_rgb_laser); + cv::waitKey(5); + */ + + std::map, std::vector > c2D_to_3D; + std::vector point_3D; + + /* store correspondences */ + for(pcl::PointCloud::iterator pt = pc.points.begin(); pt < pc.points.end(); pt++) + { + + // behind the camera + if (pt->z < 0) + { + continue; + } + + cv::Point xy = project(*pt, P); + if (xy.inside(frame)) + { + //create a map of 2D and 3D points + point_3D.clear(); + point_3D.push_back(pt->x); + point_3D.push_back(pt->y); + point_3D.push_back(pt->z); + c2D_to_3D[std::pair(xy.x, xy.y)] = point_3D; + } + } + + /* print the correspondences */ + /*for(std::map, std::vector >::iterator it=c2D_to_3D.begin(); it!=c2D_to_3D.end(); ++it) + { + std::cout << it->first.first << "," << it->first.second << " --> " << it->second[0] << "," <second[1] << "," <second[2] << "\n"; + }*/ + + /* get region of interest */ + + const int QUADS=num_of_markers; + std::vector LINE_SEGMENTS(QUADS, 4); //assuming each has 4 edges and 4 corners + + pcl::PointCloud::Ptr board_corners(new pcl::PointCloud); + + pcl::PointCloud::Ptr marker(new pcl::PointCloud); + std::vector c_3D; + std::vector c_2D; + + + cv::namedWindow("cloud", cv::WINDOW_NORMAL); + cv::namedWindow("polygon", cv::WINDOW_NORMAL); + //cv::namedWindow("combined", cv::WINDOW_NORMAL); + + std::string pkg_loc = ros::package::getPath("lidar_camera_calibration"); + std::ofstream outfile(pkg_loc + "/conf/points.txt", std::ios_base::trunc); + outfile << QUADS*4 << "\n"; + + for(int q=0; q line_model; + for(int i=0; i polygon; + int collected; + + // get markings in the first iteration only + if(iteration_count == 0) + { + polygon.clear(); + collected = 0; + // for test + cv::setMouseCallback("cloud", onMouse, &_point_); //仅仅用于激活 + std::ifstream infile("/conf/self_define_point.txt"); + std::string line; + + cv::imshow("cloud", image_edge_laser); + cv::imwrite("cloud.png", image_edge_laser); + cv::waitKey(0); + while(collected != LINE_SEGMENTS[q]) + { + + cv::setMouseCallback("cloud", onMouse, &_point_); + std::getline(infile, line); + _point_.x = atoi(line); + std::getline(infile, line); + _point_.y = atoi(line); + + + ++collected; + //std::cout << _point_.x << " " << _point_.y << "\n"; + polygon.push_back(_point_); + } + stored_corners.push_back(polygon); + } + infile.close(); + polygon = stored_corners[4*q+i]; + + cv::Mat polygon_image = cv::Mat::zeros(image_edge_laser.size(), CV_8UC1); + + rgb_laser_channels.clear(); + rgb_laser_channels.push_back(image_edge_laser); + rgb_laser_channels.push_back(cv::Mat::zeros(image_edge_laser.size(), CV_8UC1)); + rgb_laser_channels.push_back(cv::Mat::zeros(image_edge_laser.size(), CV_8UC1)); + cv::merge(rgb_laser_channels, combined_rgb_laser); + + for( int j = 0; j < 4; j++ ) + { + cv::line(combined_rgb_laser, polygon[j], polygon[(j+1)%4], cv::Scalar(0, 255, 0)); + } + + // initialize PointClouds + pcl::PointCloud::Ptr cloud (new pcl::PointCloud); + pcl::PointCloud::Ptr final (new pcl::PointCloud); + + for(std::map, std::vector >::iterator it=c2D_to_3D.begin(); it!=c2D_to_3D.end(); ++it) + { + + if (cv::pointPolygonTest(cv::Mat(polygon), cv::Point(it->first.first, it->first.second), true) > 0) + { + cloud->push_back(pcl::PointXYZ(it->second[0],it->second[1],it->second[2])); + rectangle(combined_rgb_laser, cv::Point(it->first.first, it->first.second), cv::Point(it->first.first, it->first.second), cv::Scalar(0, 0, 255), 3, 8, 0); // RED point + } + } + + if(cloud->size() < 2){ return false;} + + cv::imshow("polygon", combined_rgb_laser); + cv::waitKey(4); + + //pcl::io::savePCDFileASCII("/home/vishnu/line_cloud.pcd", *cloud); + + + + std::vector inliers; + Eigen::VectorXf model_coefficients; + + + // created RandomSampleConsensus object and compute the appropriated model + pcl::SampleConsensusModelLine::Ptr model_l(new pcl::SampleConsensusModelLine (cloud)); + + pcl::RandomSampleConsensus ransac(model_l); + // ransac.setDistanceThreshold (0.01); + ransac.setDistanceThreshold (0.001); + ransac.computeModel(); + ransac.getInliers(inliers); + ransac.getModelCoefficients(model_coefficients); + line_model.push_back(model_coefficients); + + std::cout << "Line coefficients are:" << "\n" << model_coefficients << "\n"; + // copies all inliers of the model computed to another PointCloud + pcl::copyPointCloud(*cloud, inliers, *final); + //pcl::io::savePCDFileASCII("/home/vishnu/RANSAC_line_cloud.pcd", *final); + *marker += *final; + } + + + + /* calculate approximate intersection of lines */ + + + Eigen::Vector4f p1, p2, p_intersect; + pcl::PointCloud::Ptr corners(new pcl::PointCloud); + for(int i=0; ipush_back(pcl::PointXYZ(p_intersect(0), p_intersect(1), p_intersect(2))); + std::cout << "Point of intersection is approximately: \n" << p_intersect << "\n"; + //std::cout << "Distance between the lines: " << (p1 - p2).squaredNorm () << "\n"; + std::cout << p_intersect(0) << " " << p_intersect(1) << " " << p_intersect(2) << "\n"; + outfile << p_intersect(0) << " " << p_intersect(1) << " " << p_intersect(2) << "\n"; + + } + + *board_corners += *corners; + + std::cout << "Distance between the corners:\n"; + for(int i=0; i<4; i++) + { + std::cout << + + sqrt( + pow(c_3D[4*q+i].x - c_3D[4*q+(i+1)%4].x, 2) + + pow(c_3D[4*q+i].y - c_3D[4*q+(i+1)%4].y, 2) + + pow(c_3D[4*q+i].z - c_3D[4*q+(i+1)%4].z, 2) + ) + + << std::endl; + } + + + } + outfile.close(); + + iteration_count++; + if(iteration_count == MAX_ITERS) + { + ros::shutdown(); + } + return true; + /* store point cloud with intersection points */ + //pcl::io::savePCDFileASCII("/home/vishnu/RANSAC_marker.pcd", *marker); + //pcl::io::savePCDFileASCII("/home/vishnu/RANSAC_corners.pcd", *board_corners); +} diff --git a/Corners.cpp.bak b/Corners.cpp.bak new file mode 100644 index 0000000..83d5eef --- /dev/null +++ b/Corners.cpp.bak @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include + +#include "opencv2/opencv.hpp" +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "lidar_camera_calibration/Utils.h" + +int iteration_count = 0; +std::vector< std::vector > stored_corners; + +bool getCorners(cv::Mat img, pcl::PointCloud scan, cv::Mat P, int num_of_markers, int MAX_ITERS) +{ + + ROS_INFO_STREAM("iteration number: " << iteration_count << "\n"); + + /*Masking happens here */ + cv::Mat edge_mask = cv::Mat::zeros(img.size(), CV_8UC1); + //edge_mask(cv::Rect(520, 205, 300, 250))=1; + edge_mask(cv::Rect(0, 0, img.cols, img.rows))=1; + img.copyTo(edge_mask, edge_mask); + //pcl::io::savePCDFileASCII ("/home/vishnu/final1.pcd", scan.point_cloud); + + img = edge_mask; + + //cv:imwrite("/home/vishnu/marker.png", edge_mask); + + pcl::PointCloud pc = scan; + //scan = Velodyne::Velodyne(filtered_pc); + + cv::Rect frame(0, 0, img.cols, img.rows); + + //pcl::io::savePCDFileASCII("/home/vishnu/final2.pcd", scan.point_cloud); + + cv::Mat image_edge_laser = project(P, frame, scan, NULL); + cv::threshold(image_edge_laser, image_edge_laser, 10, 255, 0); + + + + + cv::Mat combined_rgb_laser; + std::vector rgb_laser_channels; + + rgb_laser_channels.push_back(image_edge_laser); + rgb_laser_channels.push_back(cv::Mat::zeros(image_edge_laser.size(), CV_8UC1)); + rgb_laser_channels.push_back(img); + + cv::merge(rgb_laser_channels, combined_rgb_laser); + /*cv::namedWindow("combined", cv::WINDOW_NORMAL); + cv::imshow("combined", combined_rgb_laser); + cv::waitKey(5); + */ + + std::map, std::vector > c2D_to_3D; + std::vector point_3D; + + /* store correspondences */ + for(pcl::PointCloud::iterator pt = pc.points.begin(); pt < pc.points.end(); pt++) + { + + // behind the camera + if (pt->z < 0) + { + continue; + } + + cv::Point xy = project(*pt, P); + if (xy.inside(frame)) + { + //create a map of 2D and 3D points + point_3D.clear(); + point_3D.push_back(pt->x); + point_3D.push_back(pt->y); + point_3D.push_back(pt->z); + c2D_to_3D[std::pair(xy.x, xy.y)] = point_3D; + } + } + + /* print the correspondences */ + /*for(std::map, std::vector >::iterator it=c2D_to_3D.begin(); it!=c2D_to_3D.end(); ++it) + { + std::cout << it->first.first << "," << it->first.second << " --> " << it->second[0] << "," <second[1] << "," <second[2] << "\n"; + }*/ + + /* get region of interest */ + + const int QUADS=num_of_markers; + std::vector LINE_SEGMENTS(QUADS, 4); //assuming each has 4 edges and 4 corners + + pcl::PointCloud::Ptr board_corners(new pcl::PointCloud); + + pcl::PointCloud::Ptr marker(new pcl::PointCloud); + std::vector c_3D; + std::vector c_2D; + + + cv::namedWindow("cloud", cv::WINDOW_NORMAL); + cv::namedWindow("polygon", cv::WINDOW_NORMAL); + //cv::namedWindow("combined", cv::WINDOW_NORMAL); + + std::string pkg_loc = ros::package::getPath("lidar_camera_calibration"); + std::ofstream outfile(pkg_loc + "/conf/points.txt", std::ios_base::trunc); + outfile << QUADS*4 << "\n"; + + for(int q=0; q line_model; + for(int i=0; i polygon; + int collected; + + // get markings in the first iteration only + if(iteration_count == 0) + { + polygon.clear(); + collected = 0; + while(collected != LINE_SEGMENTS[q]) + { + + cv::setMouseCallback("cloud", onMouse, &_point_); + + cv::imshow("cloud", image_edge_laser); + cv::waitKey(0); + ++collected; + //std::cout << _point_.x << " " << _point_.y << "\n"; + polygon.push_back(_point_); + } + stored_corners.push_back(polygon); + } + + polygon = stored_corners[4*q+i]; + + cv::Mat polygon_image = cv::Mat::zeros(image_edge_laser.size(), CV_8UC1); + + rgb_laser_channels.clear(); + rgb_laser_channels.push_back(image_edge_laser); + rgb_laser_channels.push_back(cv::Mat::zeros(image_edge_laser.size(), CV_8UC1)); + rgb_laser_channels.push_back(cv::Mat::zeros(image_edge_laser.size(), CV_8UC1)); + cv::merge(rgb_laser_channels, combined_rgb_laser); + + for( int j = 0; j < 4; j++ ) + { + cv::line(combined_rgb_laser, polygon[j], polygon[(j+1)%4], cv::Scalar(0, 255, 0)); + } + + // initialize PointClouds + pcl::PointCloud::Ptr cloud (new pcl::PointCloud); + pcl::PointCloud::Ptr final (new pcl::PointCloud); + + for(std::map, std::vector >::iterator it=c2D_to_3D.begin(); it!=c2D_to_3D.end(); ++it) + { + + if (cv::pointPolygonTest(cv::Mat(polygon), cv::Point(it->first.first, it->first.second), true) > 0) + { + cloud->push_back(pcl::PointXYZ(it->second[0],it->second[1],it->second[2])); + rectangle(combined_rgb_laser, cv::Point(it->first.first, it->first.second), cv::Point(it->first.first, it->first.second), cv::Scalar(0, 0, 255), 3, 8, 0); // RED point + } + } + + if(cloud->size() < 2){ return false;} + + cv::imshow("polygon", combined_rgb_laser); + cv::waitKey(4); + + //pcl::io::savePCDFileASCII("/home/vishnu/line_cloud.pcd", *cloud); + + + + std::vector inliers; + Eigen::VectorXf model_coefficients; + + + // created RandomSampleConsensus object and compute the appropriated model + pcl::SampleConsensusModelLine::Ptr model_l(new pcl::SampleConsensusModelLine (cloud)); + + pcl::RandomSampleConsensus ransac(model_l); + ransac.setDistanceThreshold (0.01); + ransac.computeModel(); + ransac.getInliers(inliers); + ransac.getModelCoefficients(model_coefficients); + line_model.push_back(model_coefficients); + + std::cout << "Line coefficients are:" << "\n" << model_coefficients << "\n"; + // copies all inliers of the model computed to another PointCloud + pcl::copyPointCloud(*cloud, inliers, *final); + //pcl::io::savePCDFileASCII("/home/vishnu/RANSAC_line_cloud.pcd", *final); + *marker += *final; + } + + + + /* calculate approximate intersection of lines */ + + + Eigen::Vector4f p1, p2, p_intersect; + pcl::PointCloud::Ptr corners(new pcl::PointCloud); + for(int i=0; ipush_back(pcl::PointXYZ(p_intersect(0), p_intersect(1), p_intersect(2))); + std::cout << "Point of intersection is approximately: \n" << p_intersect << "\n"; + //std::cout << "Distance between the lines: " << (p1 - p2).squaredNorm () << "\n"; + std::cout << p_intersect(0) << " " << p_intersect(1) << " " << p_intersect(2) << "\n"; + outfile << p_intersect(0) << " " << p_intersect(1) << " " << p_intersect(2) << "\n"; + + } + + *board_corners += *corners; + + std::cout << "Distance between the corners:\n"; + for(int i=0; i<4; i++) + { + std::cout << + + sqrt( + pow(c_3D[4*q+i].x - c_3D[4*q+(i+1)%4].x, 2) + + pow(c_3D[4*q+i].y - c_3D[4*q+(i+1)%4].y, 2) + + pow(c_3D[4*q+i].z - c_3D[4*q+(i+1)%4].z, 2) + ) + + << std::endl; + } + + + } + outfile.close(); + + iteration_count++; + if(iteration_count == MAX_ITERS) + { + ros::shutdown(); + } + return true; + /* store point cloud with intersection points */ + //pcl::io::savePCDFileASCII("/home/vishnu/RANSAC_marker.pcd", *marker); + //pcl::io::savePCDFileASCII("/home/vishnu/RANSAC_corners.pcd", *board_corners); +} diff --git a/IMVApi.h b/IMVApi.h new file mode 100644 index 0000000..e7fb265 --- /dev/null +++ b/IMVApi.h @@ -0,0 +1,1071 @@ +/// \mainpage +/// \~chinese +/// \htmlinclude mainpage_chs.html +/// \~english +/// \htmlinclude mainpage_eng.html + +#ifndef __IMV_API_H__ +#define __IMV_API_H__ + +#include "IMVDefines.h" + +/// \~chinese +/// \brief 动态库导入导出定义 +/// \~english +/// \brief Dynamic library import and export definition +#if (defined (_WIN32) || defined(WIN64)) + #ifdef IMV_API_DLL_BUILD + #define IMV_API _declspec(dllexport) + #else + #define IMV_API _declspec(dllimport) + #endif + + #define IMV_CALL __stdcall +#else + #define IMV_API + #define IMV_CALL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/// \~chinese +/// \brief 获取版本信息 +/// \return 成功时返回版本信息,失败时返回NULL +/// \~english +/// \brief get version information +/// \return Success, return version info. Failure, return NULL +IMV_API const char* IMV_CALL IMV_GetVersion(void); + +/// \~chinese +/// \brief 枚举设备 +/// \param pDeviceList [OUT] 设备列表 +/// \param interfaceType [IN] 待枚举的接口类型, 类型可任意组合,如 interfaceTypeGige | interfaceTypeUsb3 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 1、当interfaceType = interfaceTypeAll 时,枚举所有接口下的在线设备\n +/// 2、当interfaceType = interfaceTypeGige 时,枚举所有GigE网口下的在线设备\n +/// 3、当interfaceType = interfaceTypeUsb3 时,枚举所有USB接口下的在线设备\n +/// 4、当interfaceType = interfaceTypeCL 时,枚举所有CameraLink接口下的在线设备\n +/// 5、该接口下的interfaceType支持任意接口类型的组合,如,若枚举所有GigE网口和USB3接口下的在线设备时, +/// 可将interfaceType设置为 interfaceType = interfaceTypeGige | interfaceTypeUsb3,其它接口类型组合以此类推 +/// \~english +/// \brief Enumerate Device +/// \param pDeviceList [OUT] Device list +/// \param interfaceType [IN] The interface type you want to find, support any interface type combination, sucn as interfaceTypeGige | interfaceTypeUsb3 +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// 1、when interfaceType = interfaceTypeAll, enumerate devices in all interface types\n +/// 2、when interfaceType = interfaceTypeGige, enumerate devices in GigE interface \n +/// 3、when interfaceType = interfaceTypeUsb3, enumerate devices in USB interface\n +/// 4、when interfaceType = interfaceTypeCL, enumerate devices in CameraLink interface\n +/// 5、interfaceType supports any interface type combination. For example, if you want to find all GigE and USB3 devices, +/// you can set interfaceType as interfaceType = interfaceTypeGige | interfaceTypeUsb3. +IMV_API int IMV_CALL IMV_EnumDevices(OUT IMV_DeviceList *pDeviceList, IN unsigned int interfaceType); + +/// \~chinese +/// \brief 以单播形式枚举设备, 仅限Gige设备使用 +/// \param pDeviceList [OUT] 设备列表 +/// \param pIpAddress [IN] 设备的IP地址 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Enumerate device by unicast mode. Only for Gige device. +/// \param pDeviceList [OUT] Device list +/// \param pIpAddress [IN] IP address of the device +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_EnumDevicesByUnicast(OUT IMV_DeviceList *pDeviceList, IN const char* pIpAddress); + +/// \~chinese +/// \brief 通过指定标示符创建设备句柄,如指定索引、设备键、设备自定义名、IP地址 +/// \param handle [OUT] 设备句柄 +/// \param mode [IN] 创建设备方式 +/// \param pIdentifier [IN] 指定标示符(设备键、设备自定义名、IP地址为char类型指针强转void类型指针,索引为unsigned int类型指针强转void类型指针) +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Create device handle by specifying identifiers, such as specifying index, device key, device userID, and IP address +/// \param handle [OUT] Device handle +/// \param mode [IN] Create handle mode +/// \param pIdentifier [IN] Specifying identifiers(device key, device userID, and IP address is char* forced to void*, index is unsigned int* forced to void*) +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_CreateHandle(OUT IMV_HANDLE* handle, IN IMV_ECreateHandleMode mode, IN void* pIdentifier); + +/// \~chinese +/// \brief 销毁设备句柄 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Destroy device handle +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_DestroyHandle(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 获取设备信息 +/// \param handle [IN] 设备句柄 +/// \param pDevInfo [OUT] 设备信息 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get device information +/// \param handle [IN] Device handle +/// \param pDevInfo [OUT] Device information +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetDeviceInfo(IN IMV_HANDLE handle, OUT IMV_DeviceInfo *pDevInfo); + +/// \~chinese +/// \brief 打开设备 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Open Device +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_Open(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 打开设备 +/// \param handle [IN] 设备句柄 +/// \param accessPermission [IN] 控制通道权限(IMV_Open默认使用accessPermissionControl权限) +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Open Device +/// \param handle [IN] Device handle +/// \param accessPermission [IN] Control access permission(Default used accessPermissionControl in IMV_Open) +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_OpenEx(IN IMV_HANDLE handle, IN IMV_ECameraAccessPermission accessPermission); + +/// \~chinese +/// \brief 判断设备是否已打开 +/// \param handle [IN] 设备句柄 +/// \return 打开状态,返回true;关闭状态或者掉线状态,返回false +/// \~english +/// \brief Check whether device is opened or not +/// \param handle [IN] Device handle +/// \return Opened, return true. Closed or Offline, return false +IMV_API bool IMV_CALL IMV_IsOpen(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 关闭设备 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Close Device +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_Close(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 修改设备IP, 仅限Gige设备使用 +/// \param handle [IN] 设备句柄 +/// \param pIpAddress [IN] IP地址 +/// \param pSubnetMask [IN] 子网掩码 +/// \param pGateway [IN] 默认网关 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 1、调用该函数时如果pSubnetMask和pGateway都设置了有效值,则以此有效值为准;\n +/// 2、调用该函数时如果pSubnetMask和pGateway都设置了NULL,则内部实现时用它所连接网卡的子网掩码和网关代替\n +/// 3、调用该函数时如果pSubnetMask和pGateway两者中其中一个为NULL,另一个非NULL,则返回错误 +/// \~english +/// \brief Modify device IP. Only for Gige device. +/// \param handle [IN] Device handle +/// \param pIpAddress [IN] IP address +/// \param pSubnetMask [IN] SubnetMask +/// \param pGateway [IN] Gateway +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// 1、When callback this function, if the values of pSubnetMask and pGateway are both valid then we consider the value is correct\n +/// 2、When callback this function, if the values of pSubnetMask and pGateway are both NULL, +/// then these values will be replaced by the subnetmask and gateway of NIC which this device connect to.\n +/// 3、When callback this function, if there is one value of pSubnetMask or pGateway is NULL and the other one is not NULL, then return error +IMV_API int IMV_CALL IMV_GIGE_ForceIpAddress(IN IMV_HANDLE handle, IN const char* pIpAddress, IN const char* pSubnetMask, IN const char* pGateway); + +/// \~chinese +/// \brief 获取设备的当前访问权限, 仅限Gige设备使用 +/// \param handle [IN] 设备句柄 +/// \param pAccessPermission [OUT] 设备的当前访问权限 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get current access permission of device. Only for Gige device. +/// \param handle [IN] Device handle +/// \param pAccessPermission [OUT] Current access permission of device +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GIGE_GetAccessPermission(IN IMV_HANDLE handle, OUT IMV_ECameraAccessPermission* pAccessPermission); + +/// \~chinese +/// \brief 设置设备对sdk命令的响应超时时间,仅限Gige设备使用 +/// \param handle [IN] 设备句柄 +/// \param timeout [IN] 超时时间,单位ms +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set the response timeout interval of device sends command to the API. Only for Gige device. +/// \param handle [IN] Device handle +/// \param timeout [IN] time out, unit:ms +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GIGE_SetAnswerTimeout(IN IMV_HANDLE handle, IN unsigned int timeout); + +/// \~chinese +/// \brief 下载设备描述XML文件,并保存到指定路径,如:D:\\xml.zip +/// \param handle [IN] 设备句柄 +/// \param pFullFileName [IN] 文件要保存的路径 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Download device description XML file, and save the files to specified path. e.g. D:\\xml.zip +/// \param handle [IN] Device handle +/// \param pFullFileName [IN] The full paths where the downloaded XMl files would be saved to +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_DownLoadGenICamXML(IN IMV_HANDLE handle, IN const char* pFullFileName); + +/// \~chinese +/// \brief 保存设备配置到指定的位置。同名文件已存在时,覆盖。 +/// \param handle [IN] 设备句柄 +/// \param pFullFileName [IN] 导出的设备配置文件全名(含路径),如:D:\\config.xml 或 D:\\config.mvcfg +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Save the configuration of the device. Overwrite the file if exists. +/// \param handle [IN] Device handle +/// \param pFullFileName [IN] The full path name of the property file(xml). e.g. D:\\config.xml or D:\\config.mvcfg +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SaveDeviceCfg(IN IMV_HANDLE handle, IN const char* pFullFileName); + +/// \~chinese +/// \brief 从文件加载设备xml配置 +/// \param handle [IN] 设备句柄 +/// \param pFullFileName [IN] 设备配置(xml)文件全名(含路径),如:D:\\config.xml 或 D:\\config.mvcfg +/// \param pErrorList [OUT] 加载失败的属性名列表。存放加载失败的属性上限为IMV_MAX_ERROR_LIST_NUM。 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief load the configuration of the device +/// \param handle [IN] Device handle +/// \param pFullFileName [IN] The full path name of the property file(xml). e.g. D:\\config.xml or D:\\config.mvcfg +/// \param pErrorList [OUT] The list of load failed properties. The failed to load properties list up to IMV_MAX_ERROR_LIST_NUM. +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_LoadDeviceCfg(IN IMV_HANDLE handle, IN const char* pFullFileName, OUT IMV_ErrorList* pErrorList); + +/// \~chinese +/// \brief 写用户自定义数据。相机内部保留32768字节用于用户存储自定义数据(此功能针对本品牌相机,其它品牌相机无此功能) +/// \param handle [IN] 设备句柄 +/// \param pBuffer [IN] 数据缓冲的指针 +/// \param pLength [IN] 期望写入的字节数 [OUT] 实际写入的字节数 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Write user-defined data; Inside the camera, there are 32768 bytes reserved for user to store private data (Only for our own camera has this function) +/// \param handle [IN] Device handle +/// \param pBuffer [IN] Pointer of the data buffer +/// \param pLength [IN] Byte count written expected [OUT] Byte count written in fact +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_WriteUserPrivateData(IN IMV_HANDLE handle, IN void* pBuffer, IN_OUT unsigned int* pLength); + +/// \~chinese +/// \brief 读用户自定义数据。相机内部保留32768字节用于用户存储自定义数据(此功能针对本品牌相机,其它品牌相机无此功能) +/// \param handle [IN] 设备句柄 +/// \param pBuffer [OUT] 数据缓冲的指针 +/// \param pLength [IN] 期望读出的字节数 [OUT] 实际读出的字节数 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Read user-defined data; Inside the camera, there are 32768 bytes reserved for user to store private data (Only for our own camera has this function) +/// \param handle [IN] Device handle +/// \param pBuffer [OUT] Pointer of the data buffer +/// \param pLength [IN] Byte count read expected [OUT] Byte count read in fact +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_ReadUserPrivateData(IN IMV_HANDLE handle, OUT void* pBuffer, IN_OUT unsigned int* pLength); + +/// \~chinese +/// \brief 往相机串口寄存器写数据,每次写会清除掉上次的数据(此功能只支持包含串口功能的本品牌相机) +/// \param handle [IN] 设备句柄 +/// \param pBuffer [IN] 数据缓冲的指针 +/// \param pLength [IN] 期望写入的字节数 [OUT] 实际写入的字节数 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Write serial data to camera serial register, will erase the data writen before (Only for our own camera with serial port has this function) +/// \param handle [IN] Device handle +/// \param pBuffer [IN] Pointer of the data buffer +/// \param pLength [IN] Byte count written expected [OUT] Byte count written in fact +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_WriteUARTData(IN IMV_HANDLE handle, IN void* pBuffer, IN_OUT unsigned int* pLength); + +/// \~chinese +/// \brief 从相机串口寄存器读取串口数据(此功能只支持包含串口功能的本品牌相机 ) +/// \param handle [IN] 设备句柄 +/// \param pBuffer [OUT] 数据缓冲的指针 +/// \param pLength [IN] 期望读出的字节数 [OUT] 实际读出的字节数 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Read serial data from camera serial register (Only for our own camera with serial port has this function) +/// \param handle [IN] Device handle +/// \param pBuffer [OUT] Pointer of the data buffer +/// \param pLength [IN] Byte count read expected [OUT] Byte count read in fact +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_ReadUARTData(IN IMV_HANDLE handle, OUT void* pBuffer, IN_OUT unsigned int* pLength); + +/// \~chinese +/// \brief 设备连接状态事件回调注册 +/// \param handle [IN] 设备句柄 +/// \param proc [IN] 设备连接状态事件回调函数 +/// \param pUser [IN] 用户自定义数据, 可设为NULL +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持一个回调函数,且设备关闭后,注册会失效,打开设备后需重新注册 +/// \~english +/// \brief Register call back function of device connection status event. +/// \param handle [IN] Device handle +/// \param proc [IN] Call back function of device connection status event +/// \param pUser [IN] User defined data,It can be set to NULL +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only one call back function is supported.\n +/// Registration becomes invalid after the device is closed, , and need to re-register after the device is opened +IMV_API int IMV_CALL IMV_SubscribeConnectArg(IN IMV_HANDLE handle, IN IMV_ConnectCallBack proc, IN void* pUser); + +/// \~chinese +/// \brief 参数更新事件回调注册 +/// \param handle [IN] 设备句柄 +/// \param proc [IN] 参数更新注册的事件回调函数 +/// \param pUser [IN] 用户自定义数据, 可设为NULL +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持一个回调函数,且设备关闭后,注册会失效,打开设备后需重新注册 +/// \~english +/// \brief Register call back function of parameter update event. +/// \param handle [IN] Device handle +/// \param proc [IN] Call back function of parameter update event +/// \param pUser [IN] User defined data,It can be set to NULL +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only one call back function is supported.\n +/// Registration becomes invalid after the device is closed, , and need to re-register after the device is opened +IMV_API int IMV_CALL IMV_SubscribeParamUpdateArg(IN IMV_HANDLE handle, IN IMV_ParamUpdateCallBack proc, IN void* pUser); + +/// \~chinese +/// \brief 流通道事件回调注册 +/// \param handle [IN] 设备句柄 +/// \param proc [IN] 流通道事件回调注册函数 +/// \param pUser [IN] 用户自定义数据, 可设为NULL +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持一个回调函数,且设备关闭后,注册会失效,打开设备后需重新注册 +/// \~english +/// \brief Register call back function of stream channel event. +/// \param handle [IN] Device handle +/// \param proc [IN] Call back function of stream channel event +/// \param pUser [IN] User defined data,It can be set to NULL +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only one call back function is supported.\n +/// Registration becomes invalid after the device is closed, , and need to re-register after the device is opened +IMV_API int IMV_CALL IMV_SubscribeStreamArg(IN IMV_HANDLE handle, IN IMV_StreamCallBack proc, IN void* pUser); + +/// \~chinese +/// \brief 消息通道事件回调注册 +/// \param handle [IN] 设备句柄 +/// \param proc [IN] 消息通道事件回调注册函数 +/// \param pUser [IN] 用户自定义数据, 可设为NULL +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持一个回调函数,且设备关闭后,注册会失效,打开设备后需重新注册 +/// \~english +/// \brief Register call back function of message channel event. +/// \param handle [IN] Device handle +/// \param proc [IN] Call back function of message channel event +/// \param pUser [IN] User defined data,It can be set to NULL +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only one call back function is supported.\n +/// Registration becomes invalid after the device is closed, , and need to re-register after the device is opened +IMV_API int IMV_CALL IMV_SubscribeMsgChannelArg(IN IMV_HANDLE handle, IN IMV_MsgChannelCallBack proc, IN void* pUser); + +/// \~chinese +/// \brief 设置帧数据缓存个数 +/// \param handle [IN] 设备句柄 +/// \param nSize [IN] 缓存数量 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 不能在拉流过程中设置 +/// \~english +/// \brief Set frame buffer count +/// \param handle [IN] Device handle +/// \param nSize [IN] The buffer count +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// It can not be set during frame grabbing +IMV_API int IMV_CALL IMV_SetBufferCount(IN IMV_HANDLE handle, IN unsigned int nSize); + +/// \~chinese +/// \brief 清除帧数据缓存 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Clear frame buffer +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_ClearFrameBuffer(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 设置驱动包间隔时间(MS),仅对Gige设备有效 +/// \param handle [IN] 设备句柄 +/// \param nTimeout [IN] 包间隔时间,单位是毫秒 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 触发模式尾包丢失重传机制 +/// \~english +/// \brief Set packet timeout(MS), only for Gige device +/// \param handle [IN] Device handle +/// \param nTimeout [IN] Time out value, unit is MS +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// The resend mechanism of tail packet loss on trigger mode +IMV_API int IMV_CALL IMV_GIGE_SetInterPacketTimeout(IN IMV_HANDLE handle, IN unsigned int nTimeout); + +/// \~chinese +/// \brief 设置单次重传最大包个数, 仅对GigE设备有效 +/// \param handle [IN] 设备句柄 +/// \param maxPacketNum [IN] 单次重传最大包个数 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// maxPacketNum为0时,该功能无效 +/// \~english +/// \brief Set the single resend maximum packet number, only for Gige device +/// \param handle [IN] Device handle +/// \param maxPacketNum [IN] The value of single resend maximum packet number +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Disable the function when maxPacketNum is 0 +IMV_API int IMV_CALL IMV_GIGE_SetSingleResendMaxPacketNum(IN IMV_HANDLE handle, IN unsigned int maxPacketNum); + +/// \~chinese +/// \brief 设置同一帧最大丢包的数量,仅对GigE设备有效 +/// \param handle [IN] 设备句柄 +/// \param maxLostPacketNum [IN] 最大丢包的数量 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// maxLostPacketNum为0时,该功能无效 +/// \~english +/// \brief Set the maximum lost packet number, only for Gige device +/// \param handle [IN] Device handle +/// \param maxLostPacketNum [IN] The value of maximum lost packet number +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Disable the function when maxLostPacketNum is 0 +IMV_API int IMV_CALL IMV_GIGE_SetMaxLostPacketNum(IN IMV_HANDLE handle, IN unsigned int maxLostPacketNum); + +/// \~chinese +/// \brief 设置U3V设备的传输数据块的数量和大小,仅对USB设备有效 +/// \param handle [IN] 设备句柄 +/// \param nNum [IN] 传输数据块的数量(范围:5-256) +/// \param nSize [IN] 传输数据块的大小(范围:8-512, 单位:KByte) +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 1、该接口暂时只有在Linux平台且使用无驱的情况下设置才有效,其他情况下返回IMV_NOT_SUPPORT错误码\n +/// 2、传输数据块数量,范围5 - 256, 默认为64,高分辨率高帧率时可以适当增加该值;多台相机共同使用时,可以适当减小该值\n +/// 3、传输每个数据块大小,范围8 - 512, 默认为64,单位是KByte +/// \~english +/// \brief Set the number and size of urb transmitted, only for USB device +/// \param handle [IN] Device handle +/// \param nNum [IN] The number of urb transmitted(range:5-256) +/// \param nSize [IN] The size of urb transmitted(range:8-512, unit:KByte) +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// 1、The interface is only supported on the Linux platform without USB driver. In other cases, it returns IMV_NOT_SUPPORT error code.\n +/// 2、The number of urb transmitted, the range is 5 - 256, and the default is 64. when high pixel and high frame rate can be appropriately increased.; +/// when multiple cameras are used together, the value can be appropriately reduced.\n +/// 3、The size of each urb transmitted, the range is 8 - 512, the default is 64, the unit is KByte. +IMV_API int IMV_CALL IMV_USB_SetUrbTransfer(IN IMV_HANDLE handle, IN unsigned int nNum, IN unsigned int nSize); + +/// \~chinese +/// \brief 开始取流 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Start grabbing +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_StartGrabbing(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 开始取流 +/// \param handle [IN] 设备句柄 +/// \param maxImagesGrabbed [IN] 允许最多的取帧数,达到指定取帧数后停止取流,如果为0,表示忽略此参数连续取流(IMV_StartGrabbing默认0) +/// \param strategy [IN] 取流策略,(IMV_StartGrabbing默认使用grabStrartegySequential策略取流) +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Start grabbing +/// \param handle [IN] Device handle +/// \param maxImagesGrabbed [IN] Maximum images allowed to grab, once it reaches the limit then stop grabbing; +/// If it is 0, then ignore this parameter and start grabbing continuously(default 0 in IMV_StartGrabbing) +/// \param strategy [IN] Image grabbing strategy; (Default grabStrartegySequential in IMV_StartGrabbing) +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_StartGrabbingEx(IN IMV_HANDLE handle, IN uint64_t maxImagesGrabbed, IN IMV_EGrabStrategy strategy); + +/// \~chinese +/// \brief 判断设备是否正在取流 +/// \param handle [IN] 设备句柄 +/// \return 正在取流,返回true;不在取流,返回false +/// \~english +/// \brief Check whether device is grabbing or not +/// \param handle [IN] Device handle +/// \return Grabbing, return true. Not grabbing, return false +IMV_API bool IMV_CALL IMV_IsGrabbing(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 停止取流 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Stop grabbing +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_StopGrabbing(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 注册帧数据回调函数(异步获取帧数据机制) +/// \param handle [IN] 设备句柄 +/// \param proc [IN] 帧数据信息回调函数,建议不要在该函数中处理耗时的操作,否则会阻塞后续帧数据的实时性 +/// \param pUser [IN] 用户自定义数据, 可设为NULL +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 该异步获取帧数据机制和同步获取帧数据机制(IMV_GetFrame)互斥,对于同一设备,系统中两者只能选其一\n +/// 只支持一个回调函数, 且设备关闭后,注册会失效,打开设备后需重新注册 +/// \~english +/// \brief Register frame data callback function( asynchronous getting frame data mechanism); +/// \param handle [IN] Device handle +/// \param proc [IN] Frame data information callback function; It is advised to not put time-cosuming operation in this function, +/// otherwise it will block follow-up data frames and affect real time performance +/// \param pUser [IN] User defined data,It can be set to NULL +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// This asynchronous getting frame data mechanism and synchronous getting frame data mechanism(IMV_GetFrame) are mutually exclusive,\n +/// only one method can be choosed between these two in system for the same device.\n +/// Only one call back function is supported.\n +/// Registration becomes invalid after the device is closed, , and need to re-register after the device is opened +IMV_API int IMV_CALL IMV_AttachGrabbing(IN IMV_HANDLE handle, IN IMV_FrameCallBack proc, IN void* pUser); + +/// \~chinese +/// \brief 获取一帧图像(同步获取帧数据机制) +/// \param handle [IN] 设备句柄 +/// \param pFrame [OUT] 帧数据信息 +/// \param timeoutMS [IN] 获取一帧图像的超时时间,INFINITE时表示无限等待,直到收到一帧数据或者停止取流。单位是毫秒 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 该接口不支持多线程调用。\n +/// 该同步获取帧机制和异步获取帧机制(IMV_AttachGrabbing)互斥,对于同一设备,系统中两者只能选其一。\n +/// 使用内部缓存获取图像,需要IMV_ReleaseFrame进行释放图像缓存。 +/// \~english +/// \brief Get a frame image(synchronous getting frame data mechanism) +/// \param handle [IN] Device handle +/// \param pFrame [OUT] Frame data information +/// \param timeoutMS [IN] The time out of getting one image, INFINITE means infinite wait until the one frame data is returned or stop grabbing.unit is MS +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// This interface does not support multi-threading.\n +/// This synchronous getting frame data mechanism and asynchronous getting frame data mechanism(IMV_AttachGrabbing) are mutually exclusive,\n +/// only one method can be chose between these two in system for the same device.\n +/// Use internal cache to get image, need to release image buffer by IMV_ReleaseFrame +IMV_API int IMV_CALL IMV_GetFrame(IN IMV_HANDLE handle, OUT IMV_Frame* pFrame, IN unsigned int timeoutMS); + +/// \~chinese +/// \brief 释放图像缓存 +/// \param handle [IN] 设备句柄 +/// \param pFrame [IN] 帧数据信息 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Free image buffer +/// \param handle [IN] Device handle +/// \param pFrame [IN] Frame image data information +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_ReleaseFrame(IN IMV_HANDLE handle, IN IMV_Frame* pFrame); + +/// \~chinese +/// \brief 帧数据深拷贝克隆 +/// \param handle [IN] 设备句柄 +/// \param pFrame [IN] 克隆源帧数据信息 +/// \param pCloneFrame [OUT] 新的帧数据信息 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 使用IMV_ReleaseFrame进行释放图像缓存。 +/// \~english +/// \brief Frame data deep clone +/// \param handle [IN] Device handle +/// \param pFrame [IN] Frame data information of clone source +/// \param pCloneFrame [OUT] New frame data information +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Use IMV_ReleaseFrame to free image buffer + +IMV_API int IMV_CALL IMV_CloneFrame(IN IMV_HANDLE handle, IN IMV_Frame* pFrame, OUT IMV_Frame* pCloneFrame); + +/// \~chinese +/// \brief 获取Chunk数据(仅对GigE/Usb相机有效) +/// \param handle [IN] 设备句柄 +/// \param pFrame [IN] 帧数据信息 +/// \param index [IN] 索引ID +/// \param pChunkDataInfo [OUT] Chunk数据信息 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get chunk data(Only GigE/Usb Camera) +/// \param handle [IN] Device handle +/// \param pFrame [IN] Frame data information +/// \param index [IN] index ID +/// \param pChunkDataInfo [OUT] Chunk data infomation +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetChunkDataByIndex(IN IMV_HANDLE handle, IN IMV_Frame* pFrame, IN unsigned int index, OUT IMV_ChunkDataInfo *pChunkDataInfo); + +/// \~chinese +/// \brief 获取流统计信息(IMV_StartGrabbing / IMV_StartGrabbing执行后调用) +/// \param handle [IN] 设备句柄 +/// \param pStreamStatsInfo [OUT] 流统计信息数据 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get stream statistics infomation(Used after excuting IMV_StartGrabbing / IMV_StartGrabbing) +/// \param handle [IN] Device handle +/// \param pStreamStatsInfo [OUT] Stream statistics infomation +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetStatisticsInfo(IN IMV_HANDLE handle, OUT IMV_StreamStatisticsInfo* pStreamStatsInfo); + +/// \~chinese +/// \brief 重置流统计信息(IMV_StartGrabbing / IMV_StartGrabbing执行后调用) +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Reset stream statistics infomation(Used after excuting IMV_StartGrabbing / IMV_StartGrabbing) +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_ResetStatisticsInfo(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 判断属性是否可用 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \return 可用,返回true;不可用,返回false +/// \~english +/// \brief Check the property is available or not +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \return Available, return true. Not available, return false +IMV_API bool IMV_CALL IMV_FeatureIsAvailable(IN IMV_HANDLE handle, IN const char* pFeatureName); + +/// \~chinese +/// \brief 判断属性是否可读 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \return 可读,返回true;不可读,返回false +/// \~english +/// \brief Check the property is readable or not +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \return Readable, return true. Not readable, return false +IMV_API bool IMV_CALL IMV_FeatureIsReadable(IN IMV_HANDLE handle, IN const char* pFeatureName); + +/// \~chinese +/// \brief 判断属性是否可写 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \return 可写,返回true;不可写,返回false +/// \~english +/// \brief Check the property is writeable or not +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \return Writeable, return true. Not writeable, return false +IMV_API bool IMV_CALL IMV_FeatureIsWriteable(IN IMV_HANDLE handle, IN const char* pFeatureName); + +/// \~chinese +/// \brief 判断属性是否可流 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \return 可流,返回true;不可流,返回false +/// \~english +/// \brief Check the property is streamable or not +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \return Streamable, return true. Not streamable, return false +IMV_API bool IMV_CALL IMV_FeatureIsStreamable(IN IMV_HANDLE handle, IN const char* pFeatureName); + +/// \~chinese +/// \brief 判断属性是否有效 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \return 有效,返回true;无效,返回false +/// \~english +/// \brief Check the property is valid or not +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \return Valid, return true. Invalid, return false +IMV_API bool IMV_CALL IMV_FeatureIsValid(IN IMV_HANDLE handle, IN const char* pFeatureName); + +/// \~chinese +/// \brief 获取整型属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pIntValue [OUT] 整型属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get integer property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pIntValue [OUT] Integer property value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetIntFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); + +/// \~chinese +/// \brief 获取整型属性可设的最小值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pIntValue [OUT] 整型属性可设的最小值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get the integer property settable minimum value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pIntValue [OUT] Integer property settable minimum value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetIntFeatureMin(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); + +/// \~chinese +/// \brief 获取整型属性可设的最大值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pIntValue [OUT] 整型属性可设的最大值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get the integer property settable maximum value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pIntValue [OUT] Integer property settable maximum value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetIntFeatureMax(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); + +/// \~chinese +/// \brief 获取整型属性步长 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pIntValue [OUT] 整型属性步长 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get integer property increment +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pIntValue [OUT] Integer property increment +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetIntFeatureInc(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT int64_t* pIntValue); + +/// \~chinese +/// \brief 设置整型属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param intValue [IN] 待设置的整型属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set integer property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param intValue [IN] Integer property value to be set +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SetIntFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, IN int64_t intValue); + +/// \~chinese +/// \brief 获取浮点属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pDoubleValue [OUT] 浮点属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get double property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pDoubleValue [OUT] Double property value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetDoubleFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); + +/// \~chinese +/// \brief 获取浮点属性可设的最小值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pDoubleValue [OUT] 浮点属性可设的最小值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get the double property settable minimum value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pDoubleValue [OUT] Double property settable minimum value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetDoubleFeatureMin(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); + +/// \~chinese +/// \brief 获取浮点属性可设的最大值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pDoubleValue [OUT] 浮点属性可设的最大值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get the double property settable maximum value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pDoubleValue [OUT] Double property settable maximum value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetDoubleFeatureMax(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT double* pDoubleValue); + +/// \~chinese +/// \brief 设置浮点属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param doubleValue [IN] 待设置的浮点属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set double property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param doubleValue [IN] Double property value to be set +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SetDoubleFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, IN double doubleValue); + +/// \~chinese +/// \brief 获取布尔属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pBoolValue [OUT] 布尔属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get boolean property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pBoolValue [OUT] Boolean property value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetBoolFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT bool* pBoolValue); + +/// \~chinese +/// \brief 设置布尔属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param boolValue [IN] 待设置的布尔属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set boolean property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param boolValue [IN] Boolean property value to be set +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SetBoolFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, IN bool boolValue); + +/// \~chinese +/// \brief 获取枚举属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pEnumValue [OUT] 枚举属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get enumeration property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pEnumValue [OUT] Enumeration property value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetEnumFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT uint64_t* pEnumValue); + +/// \~chinese +/// \brief 设置枚举属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param enumValue [IN] 待设置的枚举属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set enumeration property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param enumValue [IN] Enumeration property value to be set +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SetEnumFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, IN uint64_t enumValue); + +/// \~chinese +/// \brief 获取枚举属性symbol值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pEnumSymbol [OUT] 枚举属性symbol值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get enumeration property symbol value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pEnumSymbol [OUT] Enumeration property symbol value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetEnumFeatureSymbol(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_String* pEnumSymbol); + +/// \~chinese +/// \brief 设置枚举属性symbol值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pEnumSymbol [IN] 待设置的枚举属性symbol值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set enumeration property symbol value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pEnumSymbol [IN] Enumeration property symbol value to be set +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SetEnumFeatureSymbol(IN IMV_HANDLE handle, IN const char* pFeatureName, IN const char* pEnumSymbol); + +/// \~chinese +/// \brief 获取枚举属性的可设枚举值的个数 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pEntryNum [OUT] 枚举属性的可设枚举值的个数 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get the number of enumeration property settable enumeration +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pEntryNum [OUT] The number of enumeration property settable enumeration value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetEnumFeatureEntryNum(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT unsigned int* pEntryNum); + +/// \~chinese +/// \brief 获取枚举属性的可设枚举值列表 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pEnumEntryList [OUT] 枚举属性的可设枚举值列表 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get settable enumeration value list of enumeration property +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pEnumEntryList [OUT] Settable enumeration value list of enumeration property +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetEnumFeatureEntrys(IN IMV_HANDLE handle, IN const char* pFeatureName, IN_OUT IMV_EnumEntryList* pEnumEntryList); + +/// \~chinese +/// \brief 获取字符串属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pStringValue [OUT] 字符串属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Get string property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pStringValue [OUT] String property value +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_GetStringFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, OUT IMV_String* pStringValue); + +/// \~chinese +/// \brief 设置字符串属性值 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \param pStringValue [IN] 待设置的字符串属性值 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Set string property value +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \param pStringValue [IN] String property value to be set +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_SetStringFeatureValue(IN IMV_HANDLE handle, IN const char* pFeatureName, IN const char* pStringValue); + +/// \~chinese +/// \brief 执行命令属性 +/// \param handle [IN] 设备句柄 +/// \param pFeatureName [IN] 属性名 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Execute command property +/// \param handle [IN] Device handle +/// \param pFeatureName [IN] Feature name +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_ExecuteCommandFeature(IN IMV_HANDLE handle, IN const char* pFeatureName); + +/// \~chinese +/// \brief 像素格式转换 +/// \param handle [IN] 设备句柄 +/// \param pstPixelConvertParam [IN][OUT] 像素格式转换参数结构体 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持转化成目标像素格式gvspPixelRGB8 / gvspPixelBGR8 / gvspPixelMono8 / gvspPixelBGRA8\n +/// 通过该接口将原始图像数据转换成用户所需的像素格式并存放在调用者指定内存中。\n +/// 像素格式为YUV411Packed的时,图像宽须能被4整除\n +/// 像素格式为YUV422Packed的时,图像宽须能被2整除\n +/// 像素格式为YUYVPacked的时,图像宽须能被2整除\n +/// 转换后的图像:数据存储是从最上面第一行开始的,这个是相机数据的默认存储方向 +/// \~english +/// \brief Pixel format conversion +/// \param handle [IN] Device handle +/// \param pstPixelConvertParam [IN][OUT] Convert Pixel Type parameter structure +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only support converting to destination pixel format of gvspPixelRGB8 / gvspPixelBGR8 / gvspPixelMono8 / gvspPixelBGRA8\n +/// This API is used to transform the collected original data to pixel format and save to specified memory by caller.\n +/// pixelFormat:YUV411Packed, the image width is divisible by 4\n +/// pixelFormat : YUV422Packed, the image width is divisible by 2\n +/// pixelFormat : YUYVPacked,the image width is divisible by 2\n +/// converted image:The first row of the image is located at the start of the image buffer.This is the default for image taken by a camera. +IMV_API int IMV_CALL IMV_PixelConvert(IN IMV_HANDLE handle, IN_OUT IMV_PixelConvertParam* pstPixelConvertParam); + +/// \~chinese +/// \brief 打开录像 +/// \param handle [IN] 设备句柄 +/// \param pstRecordParam [IN] 录像参数结构体 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Open record +/// \param handle [IN] Device handle +/// \param pstRecordParam [IN] Record param structure +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_OpenRecord(IN IMV_HANDLE handle, IN IMV_RecordParam *pstRecordParam); + +/// \~chinese +/// \brief 录制一帧图像 +/// \param handle [IN] 设备句柄 +/// \param pstRecordFrameInfoParam [IN] 录像用帧信息结构体 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Record one frame +/// \param handle [IN] Device handle +/// \param pstRecordFrameInfoParam [IN] Frame information for recording structure +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_InputOneFrame(IN IMV_HANDLE handle, IN IMV_RecordFrameInfoParam *pstRecordFrameInfoParam); + +/// \~chinese +/// \brief 关闭录像 +/// \param handle [IN] 设备句柄 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \~english +/// \brief Close record +/// \param handle [IN] Device handle +/// \return Success, return IMV_OK. Failure, return error code +IMV_API int IMV_CALL IMV_CloseRecord(IN IMV_HANDLE handle); + +/// \~chinese +/// \brief 图像翻转 +/// \param handle [IN] 设备句柄 +/// \param pstFlipImageParam [IN][OUT] 图像翻转参数结构体 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持像素格式gvspPixelRGB8 / gvspPixelBGR8 / gvspPixelMono8的图像的垂直和水平翻转。\n +/// 通过该接口将原始图像数据翻转后并存放在调用者指定内存中。 +/// \~english +/// \brief Flip image +/// \param handle [IN] Device handle +/// \param pstFlipImageParam [IN][OUT] Flip image parameter structure +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only support vertical and horizontal flip of image data with gvspPixelRGB8 / gvspPixelBGR8 / gvspPixelMono8 pixel format.\n +/// This API is used to flip original data and save to specified memory by caller. +IMV_API int IMV_CALL IMV_FlipImage(IN IMV_HANDLE handle, IN_OUT IMV_FlipImageParam* pstFlipImageParam); + +/// \~chinese +/// \brief 图像顺时针旋转 +/// \param handle [IN] 设备句柄 +/// \param pstRotateImageParam [IN][OUT] 图像旋转参数结构体 +/// \return 成功,返回IMV_OK;错误,返回错误码 +/// \remarks +/// 只支持gvspPixelRGB8 / gvspPixelBGR8 / gvspPixelMono8格式数据的90/180/270度顺时针旋转。\n +/// 通过该接口将原始图像数据旋转后并存放在调用者指定内存中。 +/// \~english +/// \brief Rotate image clockwise +/// \param handle [IN] Device handle +/// \param pstRotateImageParam [IN][OUT] Rotate image parameter structure +/// \return Success, return IMV_OK. Failure, return error code +/// \remarks +/// Only support 90/180/270 clockwise rotation of data in the gvspPixelRGB8 / gvspPixelBGR8 / gvspPixelMono8 format.\n +/// This API is used to rotation original data and save to specified memory by caller. +IMV_API int IMV_CALL IMV_RotateImage(IN IMV_HANDLE handle, IN_OUT IMV_RotateImageParam* pstRotateImageParam); + +#ifdef __cplusplus +} +#endif + +#endif // __IMV_API_H__ \ No newline at end of file diff --git a/IMVDefines.h b/IMVDefines.h new file mode 100644 index 0000000..8cb5082 --- /dev/null +++ b/IMVDefines.h @@ -0,0 +1,811 @@ +#ifndef __IMV_DEFINES_H__ +#define __IMV_DEFINES_H__ + +#ifdef WIN32 +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#ifndef IN +#define IN ///< \~chinese 输入型参数 \~english Input param +#endif + +#ifndef OUT +#define OUT ///< \~chinese 输出型参数 \~english Output param +#endif + +#ifndef IN_OUT +#define IN_OUT ///< \~chinese 输入/输出型参数 \~english Input/Output param +#endif + +#ifndef __cplusplus +typedef char bool; +#define true 1 +#define false 0 +#endif + +/// \~chinese +/// \brief 错误码 +/// \~english +/// \brief Error code +#define IMV_OK 0 ///< \~chinese 成功,无错误 \~english Successed, no error +#define IMV_ERROR -101 ///< \~chinese 通用的错误 \~english Generic error +#define IMV_INVALID_HANDLE -102 ///< \~chinese 错误或无效的句柄 \~english Error or invalid handle +#define IMV_INVALID_PARAM -103 ///< \~chinese 错误的参数 \~english Incorrect parameter +#define IMV_INVALID_FRAME_HANDLE -104 ///< \~chinese 错误或无效的帧句柄 \~english Error or invalid frame handle +#define IMV_INVALID_FRAME -105 ///< \~chinese 无效的帧 \~english Invalid frame +#define IMV_INVALID_RESOURCE -106 ///< \~chinese 相机/事件/流等资源无效 \~english Camera/Event/Stream and so on resource invalid +#define IMV_INVALID_IP -107 ///< \~chinese 设备与主机的IP网段不匹配 \~english Device's and PC's subnet is mismatch +#define IMV_NO_MEMORY -108 ///< \~chinese 内存不足 \~english Malloc memery failed +#define IMV_INSUFFICIENT_MEMORY -109 ///< \~chinese 传入的内存空间不足 \~english Insufficient memory +#define IMV_ERROR_PROPERTY_TYPE -110 ///< \~chinese 属性类型错误 \~english Property type error +#define IMV_INVALID_ACCESS -111 ///< \~chinese 属性不可访问、或不能读/写、或读/写失败 \~english Property not accessible, or not be read/written, or read/written failed +#define IMV_INVALID_RANGE -112 ///< \~chinese 属性值超出范围、或者不是步长整数倍 \~english The property's value is out of range, or is not integer multiple of the step +#define IMV_NOT_SUPPORT -113 ///< \~chinese 设备不支持的功能 \~english Device not supported function + +#define IMV_MAX_DEVICE_ENUM_NUM 100 ///< \~chinese 支持设备最大个数 \~english The maximum number of supported devices +#define IMV_MAX_STRING_LENTH 256 ///< \~chinese 字符串最大长度 \~english The maximum length of string +#define IMV_MAX_ERROR_LIST_NUM 128 ///< \~chinese 失败属性列表最大长度 \~english The maximum size of failed properties list + +typedef void* IMV_HANDLE; ///< \~chinese 设备句柄 \~english Device handle +typedef void* IMV_FRAME_HANDLE; ///< \~chinese 帧句柄 \~english Frame handle + +/// \~chinese +///枚举:接口类型 +/// \~english +///Enumeration: interface type +typedef enum _IMV_EInterfaceType +{ + interfaceTypeGige = 0x00000001, ///< \~chinese 网卡接口类型 \~english NIC type + interfaceTypeUsb3 = 0x00000002, ///< \~chinese USB3.0接口类型 \~english USB3.0 interface type + interfaceTypeCL = 0x00000004, ///< \~chinese CAMERALINK接口类型 \~english Cameralink interface type + interfaceTypePCIe = 0x00000008, ///< \~chinese PCIe接口类型 \~english PCIe interface type + interfaceTypeAll = 0x00000000, ///< \~chinese 忽略接口类型 \~english All types interface type + interfaceInvalidType = 0xFFFFFFFF ///< \~chinese 无效接口类型 \~english Invalid interface type +}IMV_EInterfaceType; + +/// \~chinese +///枚举:设备类型 +/// \~english +///Enumeration: device type +typedef enum _IMV_ECameraType +{ + typeGigeCamera = 0, ///< \~chinese GIGE相机 \~english GigE Vision Camera + typeU3vCamera = 1, ///< \~chinese USB3.0相机 \~english USB3.0 Vision Camera + typeCLCamera = 2, ///< \~chinese CAMERALINK 相机 \~english Cameralink camera + typePCIeCamera = 3, ///< \~chinese PCIe相机 \~english PCIe Camera + typeUndefinedCamera = 255 ///< \~chinese 未知类型 \~english Undefined Camera +}IMV_ECameraType; + +/// \~chinese +///枚举:创建句柄方式 +/// \~english +///Enumeration: Create handle mode +typedef enum _IMV_ECreateHandleMode +{ + modeByIndex = 0, ///< \~chinese 通过已枚举设备的索引(从0开始,比如 0, 1, 2...) \~english By index of enumerated devices (Start from 0, such as 0, 1, 2...) + modeByCameraKey, ///< \~chinese 通过设备键"厂商:序列号" \~english By device's key "vendor:serial number" + modeByDeviceUserID, ///< \~chinese 通过设备自定义名 \~english By device userID + modeByIPAddress, ///< \~chinese 通过设备IP地址 \~english By device IP address. +}IMV_ECreateHandleMode; + +/// \~chinese +///枚举:访问权限 +/// \~english +///Enumeration: access permission +typedef enum _IMV_ECameraAccessPermission +{ + accessPermissionOpen = 0, ///< \~chinese GigE相机没有被连接 \~english The GigE vision device isn't connected to any application. + accessPermissionExclusive, ///< \~chinese 独占访问权限 \~english Exclusive Access Permission + accessPermissionControl, ///< \~chinese 非独占可读访问权限 \~english Non-Exclusive Readbale Access Permission + accessPermissionControlWithSwitchover, ///< \~chinese 切换控制访问权限 \~english Control access with switchover enabled. + accessPermissionUnknown = 254, ///< \~chinese 无法确定 \~english Value not known; indeterminate. + accessPermissionUndefined ///< \~chinese 未定义访问权限 \~english Undefined Access Permission +}IMV_ECameraAccessPermission; + +/// \~chinese +///枚举:抓图策略 +/// \~english +///Enumeration: grab strartegy +typedef enum _IMV_EGrabStrategy +{ + grabStrartegySequential = 0, ///< \~chinese 按到达顺序处理图片 \~english The images are processed in the order of their arrival + grabStrartegyLatestImage = 1, ///< \~chinese 获取最新的图片 \~english Get latest image + grabStrartegyUpcomingImage = 2, ///< \~chinese 等待获取下一张图片(只针对GigE相机) \~english Waiting for next image(GigE only) + grabStrartegyUndefined ///< \~chinese 未定义 \~english Undefined +}IMV_EGrabStrategy; + +/// \~chinese +///枚举:流事件状态 +/// \~english +/// Enumeration:stream event status +typedef enum _IMV_EEventStatus +{ + streamEventNormal = 1, ///< \~chinese 正常流事件 \~english Normal stream event + streamEventLostFrame = 2, ///< \~chinese 丢帧事件 \~english Lost frame event + streamEventLostPacket = 3, ///< \~chinese 丢包事件 \~english Lost packet event + streamEventImageError = 4, ///< \~chinese 图像错误事件 \~english Error image event + streamEventStreamChannelError = 5, ///< \~chinese 取流错误事件 \~english Stream channel error event + streamEventTooManyConsecutiveResends = 6, ///< \~chinese 太多连续重传 \~english Too many consecutive resends event + streamEventTooManyLostPacket = 7 ///< \~chinese 太多丢包 \~english Too many lost packet event +}IMV_EEventStatus; + +/// \~chinese +///枚举:图像转换Bayer格式所用的算法 +/// \~english +/// Enumeration:alorithm used for Bayer demosaic +typedef enum _IMV_EBayerDemosaic +{ + demosaicNearestNeighbor, ///< \~chinese 最近邻 \~english Nearest neighbor + demosaicBilinear, ///< \~chinese 双线性 \~english Bilinear + demosaicEdgeSensing, ///< \~chinese 边缘检测 \~english Edge sensing + demosaicNotSupport = 255, ///< \~chinese 不支持 \~english Not support +}IMV_EBayerDemosaic; + +/// \~chinese +///枚举:事件类型 +/// \~english +/// Enumeration:event type +typedef enum _IMV_EVType +{ + offLine, ///< \~chinese 设备离线通知 \~english device offline notification + onLine ///< \~chinese 设备在线通知 \~english device online notification +}IMV_EVType; + +/// \~chinese +///枚举:视频格式 +/// \~english +/// Enumeration:Video format +typedef enum _IMV_EVideoType +{ + typeVideoFormatAVI = 0, ///< \~chinese AVI格式 \~english AVI format + typeVideoFormatNotSupport = 255 ///< \~chinese 不支持 \~english Not support +}IMV_EVideoType; + +/// \~chinese +///枚举:图像翻转类型 +/// \~english +/// Enumeration:Image flip type +typedef enum _IMV_EFlipType +{ + typeFlipVertical, ///< \~chinese 垂直(Y轴)翻转 \~english Vertical(Y-axis) flip + typeFlipHorizontal ///< \~chinese 水平(X轴)翻转 \~english Horizontal(X-axis) flip +}IMV_EFlipType; + +/// \~chinese +///枚举:顺时针旋转角度 +/// \~english +/// Enumeration:Rotation angle clockwise +typedef enum _IMV_ERotationAngle +{ + rotationAngle90, ///< \~chinese 顺时针旋转90度 \~english Rotate 90 degree clockwise + rotationAngle180, ///< \~chinese 顺时针旋转180度 \~english Rotate 180 degree clockwise + rotationAngle270, ///< \~chinese 顺时针旋转270度 \~english Rotate 270 degree clockwise +}IMV_ERotationAngle; + +#define IMV_GVSP_PIX_MONO 0x01000000 +#define IMV_GVSP_PIX_RGB 0x02000000 +#define IMV_GVSP_PIX_COLOR 0x02000000 +#define IMV_GVSP_PIX_CUSTOM 0x80000000 +#define IMV_GVSP_PIX_COLOR_MASK 0xFF000000 + +// Indicate effective number of bits occupied by the pixel (including padding). +// This can be used to compute amount of memory required to store an image. +#define IMV_GVSP_PIX_OCCUPY1BIT 0x00010000 +#define IMV_GVSP_PIX_OCCUPY2BIT 0x00020000 +#define IMV_GVSP_PIX_OCCUPY4BIT 0x00040000 +#define IMV_GVSP_PIX_OCCUPY8BIT 0x00080000 +#define IMV_GVSP_PIX_OCCUPY12BIT 0x000C0000 +#define IMV_GVSP_PIX_OCCUPY16BIT 0x00100000 +#define IMV_GVSP_PIX_OCCUPY24BIT 0x00180000 +#define IMV_GVSP_PIX_OCCUPY32BIT 0x00200000 +#define IMV_GVSP_PIX_OCCUPY36BIT 0x00240000 +#define IMV_GVSP_PIX_OCCUPY48BIT 0x00300000 + +/// \~chinese +///枚举:图像格式 +/// \~english +/// Enumeration:image format +typedef enum _IMV_EPixelType +{ + // Undefined pixel type + gvspPixelTypeUndefined = -1, + + // Mono Format + gvspPixelMono1p = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY1BIT | 0x0037), + gvspPixelMono2p = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY2BIT | 0x0038), + gvspPixelMono4p = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY4BIT | 0x0039), + gvspPixelMono8 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY8BIT | 0x0001), + gvspPixelMono8S = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY8BIT | 0x0002), + gvspPixelMono10 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0003), + gvspPixelMono10Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x0004), + gvspPixelMono12 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0005), + gvspPixelMono12Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x0006), + gvspPixelMono14 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0025), + gvspPixelMono16 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0007), + + // Bayer Format + gvspPixelBayGR8 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY8BIT | 0x0008), + gvspPixelBayRG8 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY8BIT | 0x0009), + gvspPixelBayGB8 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY8BIT | 0x000A), + gvspPixelBayBG8 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY8BIT | 0x000B), + gvspPixelBayGR10 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x000C), + gvspPixelBayRG10 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x000D), + gvspPixelBayGB10 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x000E), + gvspPixelBayBG10 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x000F), + gvspPixelBayGR12 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0010), + gvspPixelBayRG12 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0011), + gvspPixelBayGB12 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0012), + gvspPixelBayBG12 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0013), + gvspPixelBayGR10Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x0026), + gvspPixelBayRG10Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x0027), + gvspPixelBayGB10Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x0028), + gvspPixelBayBG10Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x0029), + gvspPixelBayGR12Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x002A), + gvspPixelBayRG12Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x002B), + gvspPixelBayGB12Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x002C), + gvspPixelBayBG12Packed = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY12BIT | 0x002D), + gvspPixelBayGR16 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x002E), + gvspPixelBayRG16 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x002F), + gvspPixelBayGB16 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0030), + gvspPixelBayBG16 = (IMV_GVSP_PIX_MONO | IMV_GVSP_PIX_OCCUPY16BIT | 0x0031), + + // RGB Format + gvspPixelRGB8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x0014), + gvspPixelBGR8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x0015), + gvspPixelRGBA8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY32BIT | 0x0016), + gvspPixelBGRA8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY32BIT | 0x0017), + gvspPixelRGB10 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x0018), + gvspPixelBGR10 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x0019), + gvspPixelRGB12 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x001A), + gvspPixelBGR12 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x001B), + gvspPixelRGB16 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x0033), + gvspPixelRGB10V1Packed = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY32BIT | 0x001C), + gvspPixelRGB10P32 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY32BIT | 0x001D), + gvspPixelRGB12V1Packed = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY36BIT | 0X0034), + gvspPixelRGB565P = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x0035), + gvspPixelBGR565P = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0X0036), + + // YVR Format + gvspPixelYUV411_8_UYYVYY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY12BIT | 0x001E), + gvspPixelYUV422_8_UYVY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x001F), + gvspPixelYUV422_8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x0032), + gvspPixelYUV8_UYV = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x0020), + gvspPixelYCbCr8CbYCr = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x003A), + gvspPixelYCbCr422_8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x003B), + gvspPixelYCbCr422_8_CbYCrY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x0043), + gvspPixelYCbCr411_8_CbYYCrYY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY12BIT | 0x003C), + gvspPixelYCbCr601_8_CbYCr = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x003D), + gvspPixelYCbCr601_422_8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x003E), + gvspPixelYCbCr601_422_8_CbYCrY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x0044), + gvspPixelYCbCr601_411_8_CbYYCrYY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY12BIT | 0x003F), + gvspPixelYCbCr709_8_CbYCr = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x0040), + gvspPixelYCbCr709_422_8 = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x0041), + gvspPixelYCbCr709_422_8_CbYCrY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY16BIT | 0x0045), + gvspPixelYCbCr709_411_8_CbYYCrYY = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY12BIT | 0x0042), + + // RGB Planar + gvspPixelRGB8Planar = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY24BIT | 0x0021), + gvspPixelRGB10Planar = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x0022), + gvspPixelRGB12Planar = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x0023), + gvspPixelRGB16Planar = (IMV_GVSP_PIX_COLOR | IMV_GVSP_PIX_OCCUPY48BIT | 0x0024), + + //BayerRG10p和BayerRG12p格式,针对特定项目临时添加,请不要使用 + //BayerRG10p and BayerRG12p, currently used for specific project, please do not use them + gvspPixelBayRG10p = 0x010A0058, + gvspPixelBayRG12p = 0x010c0059, + + //mono1c格式,自定义格式 + //mono1c, customized image format, used for binary output + gvspPixelMono1c = 0x012000FF, + + //mono1e格式,自定义格式,用来显示连通域 + //mono1e, customized image format, used for displaying connected domain + gvspPixelMono1e = 0x01080FFF +}IMV_EPixelType; + +/// \~chinese +/// \brief 字符串信息 +/// \~english +/// \brief String information +typedef struct _IMV_String +{ + char str[IMV_MAX_STRING_LENTH]; ///< \~chinese 字符串.长度不超过256 \~english Strings and the maximum length of strings is 255. +}IMV_String; + +/// \~chinese +/// \brief GigE网卡信息 +/// \~english +/// \brief GigE interface information +typedef struct _IMV_GigEInterfaceInfo +{ + char description[IMV_MAX_STRING_LENTH]; ///< \~chinese 网卡描述信息 \~english Network card description + char macAddress[IMV_MAX_STRING_LENTH]; ///< \~chinese 网卡Mac地址 \~english Network card MAC Address + char ipAddress[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备Ip地址 \~english Device ip Address + char subnetMask[IMV_MAX_STRING_LENTH]; ///< \~chinese 子网掩码 \~english SubnetMask + char defaultGateWay[IMV_MAX_STRING_LENTH]; ///< \~chinese 默认网关 \~english Default GateWay + char chReserved[5][IMV_MAX_STRING_LENTH]; ///< 保留 \~english Reserved field +}IMV_GigEInterfaceInfo; + +/// \~chinese +/// \brief USB接口信息 +/// \~english +/// \brief USB interface information +typedef struct _IMV_UsbInterfaceInfo +{ + char description[IMV_MAX_STRING_LENTH]; ///< \~chinese USB接口描述信息 \~english USB interface description + char vendorID[IMV_MAX_STRING_LENTH]; ///< \~chinese USB接口Vendor ID \~english USB interface Vendor ID + char deviceID[IMV_MAX_STRING_LENTH]; ///< \~chinese USB接口设备ID \~english USB interface Device ID + char subsystemID[IMV_MAX_STRING_LENTH]; ///< \~chinese USB接口Subsystem ID \~english USB interface Subsystem ID + char revision[IMV_MAX_STRING_LENTH]; ///< \~chinese USB接口Revision \~english USB interface Revision + char speed[IMV_MAX_STRING_LENTH]; ///< \~chinese USB接口speed \~english USB interface speed + char chReserved[4][IMV_MAX_STRING_LENTH]; ///< 保留 \~english Reserved field +}IMV_UsbInterfaceInfo; + +/// \~chinese +/// \brief GigE设备信息 +/// \~english +/// \brief GigE device information +typedef struct _IMV_GigEDeviceInfo +{ + /// \~chinese + /// 设备支持的IP配置选项\n + /// value:4 相机只支持LLA\n + /// value:5 相机支持LLA和Persistent IP\n + /// value:6 相机支持LLA和DHCP\n + /// value:7 相机支持LLA、DHCP和Persistent IP\n + /// value:0 获取失败 + /// \~english + /// Supported IP configuration options of device\n + /// value:4 Device supports LLA \n + /// value:5 Device supports LLA and Persistent IP\n + /// value:6 Device supports LLA and DHCP\n + /// value:7 Device supports LLA, DHCP and Persistent IP\n + /// value:0 Get fail + unsigned int nIpConfigOptions; + /// \~chinese + /// 设备当前的IP配置选项\n + /// value:4 LLA处于活动状态\n + /// value:5 LLA和Persistent IP处于活动状态\n + /// value:6 LLA和DHCP处于活动状态\n + /// value:7 LLA、DHCP和Persistent IP处于活动状态\n + /// value:0 获取失败 + /// \~english + /// Current IP Configuration options of device\n + /// value:4 LLA is active\n + /// value:5 LLA and Persistent IP are active\n + /// value:6 LLA and DHCP are active\n + /// value:7 LLA, DHCP and Persistent IP are active\n + /// value:0 Get fail + unsigned int nIpConfigCurrent; + unsigned int nReserved[3]; ///< \~chinese 保留 \~english Reserved field + + char macAddress[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备Mac地址 \~english Device MAC Address + char ipAddress[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备Ip地址 \~english Device ip Address + char subnetMask[IMV_MAX_STRING_LENTH]; ///< \~chinese 子网掩码 \~english SubnetMask + char defaultGateWay[IMV_MAX_STRING_LENTH]; ///< \~chinese 默认网关 \~english Default GateWay + char protocolVersion[IMV_MAX_STRING_LENTH]; ///< \~chinese 网络协议版本 \~english Net protocol version + /// \~chinese + /// Ip配置有效性\n + /// Ip配置有效时字符串值"Valid"\n + /// Ip配置无效时字符串值"Invalid On This Interface" + /// \~english + /// IP configuration valid\n + /// String value is "Valid" when ip configuration valid\n + /// String value is "Invalid On This Interface" when ip configuration invalid + char ipConfiguration[IMV_MAX_STRING_LENTH]; + char chReserved[6][IMV_MAX_STRING_LENTH]; ///< \~chinese 保留 \~english Reserved field + +}IMV_GigEDeviceInfo; + +/// \~chinese +/// \brief Usb设备信息 +/// \~english +/// \brief Usb device information +typedef struct _IMV_UsbDeviceInfo +{ + bool bLowSpeedSupported; ///< \~chinese true支持,false不支持,其他值 非法。 \~english true support,false not supported,other invalid + bool bFullSpeedSupported; ///< \~chinese true支持,false不支持,其他值 非法。 \~english true support,false not supported,other invalid + bool bHighSpeedSupported; ///< \~chinese true支持,false不支持,其他值 非法。 \~english true support,false not supported,other invalid + bool bSuperSpeedSupported; ///< \~chinese true支持,false不支持,其他值 非法。 \~english true support,false not supported,other invalid + bool bDriverInstalled; ///< \~chinese true安装,false未安装,其他值 非法。 \~english true support,false not supported,other invalid + bool boolReserved[3]; ///< \~chinese 保留 + unsigned int Reserved[4]; ///< \~chinese 保留 \~english Reserved field + + char configurationValid[IMV_MAX_STRING_LENTH]; ///< \~chinese 配置有效性 \~english Configuration Valid + char genCPVersion[IMV_MAX_STRING_LENTH]; ///< \~chinese GenCP 版本 \~english GenCP Version + char u3vVersion[IMV_MAX_STRING_LENTH]; ///< \~chinese U3V 版本号 \~english U3v Version + char deviceGUID[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备引导号 \~english Device guid number + char familyName[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备系列号 \~english Device serial number + char u3vSerialNumber[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备序列号 \~english Device SerialNumber + char speed[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备传输速度 \~english Device transmission speed + char maxPower[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备最大供电量 \~english Maximum power supply of device + char chReserved[4][IMV_MAX_STRING_LENTH]; ///< \~chinese 保留 \~english Reserved field + +}IMV_UsbDeviceInfo; + +/// \~chinese +/// \brief 设备通用信息 +/// \~english +/// \brief Device general information +typedef struct _IMV_DeviceInfo +{ + IMV_ECameraType nCameraType; ///< \~chinese 设备类别 \~english Camera type + int nCameraReserved[5]; ///< \~chinese 保留 \~english Reserved field + + char cameraKey[IMV_MAX_STRING_LENTH]; ///< \~chinese 厂商:序列号 \~english Camera key + char cameraName[IMV_MAX_STRING_LENTH]; ///< \~chinese 用户自定义名 \~english UserDefinedName + char serialNumber[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备序列号 \~english Device SerialNumber + char vendorName[IMV_MAX_STRING_LENTH]; ///< \~chinese 厂商 \~english Camera Vendor + char modelName[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备型号 \~english Device model + char manufactureInfo[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备制造信息 \~english Device ManufactureInfo + char deviceVersion[IMV_MAX_STRING_LENTH]; ///< \~chinese 设备版本 \~english Device Version + char cameraReserved[5][IMV_MAX_STRING_LENTH]; ///< \~chinese 保留 \~english Reserved field + union + { + IMV_GigEDeviceInfo gigeDeviceInfo; ///< \~chinese Gige设备信息 \~english Gige Device Information + IMV_UsbDeviceInfo usbDeviceInfo; ///< \~chinese Usb设备信息 \~english Usb Device Information + }DeviceSpecificInfo; + + IMV_EInterfaceType nInterfaceType; ///< \~chinese 接口类别 \~english Interface type + int nInterfaceReserved[5]; ///< \~chinese 保留 \~english Reserved field + char interfaceName[IMV_MAX_STRING_LENTH]; ///< \~chinese 接口名 \~english Interface Name + char interfaceReserved[5][IMV_MAX_STRING_LENTH]; ///< \~chinese 保留 \~english Reserved field + union + { + IMV_GigEInterfaceInfo gigeInterfaceInfo; ///< \~chinese GigE网卡信息 \~english Gige interface Information + IMV_UsbInterfaceInfo usbInterfaceInfo; ///< \~chinese Usb接口信息 \~english Usb interface Information + }InterfaceInfo; +}IMV_DeviceInfo; + +/// \~chinese +/// \brief 加载失败的属性信息 +/// \~english +/// \brief Load failed properties information +typedef struct _IMV_ErrorList +{ + unsigned int nParamCnt; ///< \~chinese 加载失败的属性个数 \~english The count of load failed properties + IMV_String paramNameList[IMV_MAX_ERROR_LIST_NUM]; ///< \~chinese 加载失败的属性集合,上限128 \~english Array of load failed properties, up to 128 +}IMV_ErrorList; + +/// \~chinese +/// \brief 设备信息列表 +/// \~english +/// \brief Device information list +typedef struct _IMV_DeviceList +{ + unsigned int nDevNum; ///< \~chinese 设备数量 \~english Device Number + IMV_DeviceInfo* pDevInfo; ///< \~chinese 设备息列表(SDK内部缓存),最多100设备 \~english Device information list(cached within the SDK), up to 100 +}IMV_DeviceList; + +/// \~chinese +/// \brief 连接事件信息 +/// \~english +/// \brief connection event information +typedef struct _IMV_SConnectArg +{ + IMV_EVType event; ///< \~chinese 事件类型 \~english event type + unsigned int nReserve[10]; ///< \~chinese 预留字段 \~english Reserved field +}IMV_SConnectArg; + +/// \~chinese +/// \brief 参数更新事件信息 +/// \~english +/// \brief Updating parameters event information +typedef struct _IMV_SParamUpdateArg +{ + bool isPoll; ///< \~chinese 是否是定时更新,true:表示是定时更新,false:表示非定时更新 \~english Update periodically or not. true:update periodically, true:not update periodically + unsigned int nReserve[10]; ///< \~chinese 预留字段 \~english Reserved field + unsigned int nParamCnt; ///< \~chinese 更新的参数个数 \~english The number of parameters which need update + IMV_String* pParamNameList; ///< \~chinese 更新的参数名称集合(SDK内部缓存) \~english Array of parameter's name which need to be updated(cached within the SDK) +}IMV_SParamUpdateArg; + +/// \~chinese +/// \brief 流事件信息 +/// \~english +/// \brief Stream event information +typedef struct _IMV_SStreamArg +{ + unsigned int channel; ///< \~chinese 流通道号 \~english Channel no. + uint64_t blockId; ///< \~chinese 流数据BlockID \~english Block ID of stream data + uint64_t timeStamp; ///< \~chinese 时间戳 \~english Event time stamp + IMV_EEventStatus eStreamEventStatus; ///< \~chinese 流事件状态码 \~english Stream event status code + unsigned int status; ///< \~chinese 事件状态错误码 \~english Status error code + unsigned int nReserve[9]; ///< \~chinese 预留字段 \~english Reserved field +}IMV_SStreamArg; + +/// \~chinese +/// 消息通道事件ID列表 +/// \~english +/// message channel event id list +#define IMV_MSG_EVENT_ID_EXPOSURE_END 0x9001 +#define IMV_MSG_EVENT_ID_FRAME_TRIGGER 0x9002 +#define IMV_MSG_EVENT_ID_FRAME_START 0x9003 +#define IMV_MSG_EVENT_ID_ACQ_START 0x9004 +#define IMV_MSG_EVENT_ID_ACQ_TRIGGER 0x9005 +#define IMV_MSG_EVENT_ID_DATA_READ_OUT 0x9006 + +/// \~chinese +/// \brief 消息通道事件信息 +/// \~english +/// \brief Message channel event information +typedef struct _IMV_SMsgChannelArg +{ + unsigned short eventId; ///< \~chinese 事件Id \~english Event id + unsigned short channelId; ///< \~chinese 消息通道号 \~english Channel id + uint64_t blockId; ///< \~chinese 流数据BlockID \~english Block ID of stream data + uint64_t timeStamp; ///< \~chinese 时间戳 \~english Event timestamp + unsigned int nReserve[8]; ///< \~chinese 预留字段 \~english Reserved field + unsigned int nParamCnt; ///< \~chinese 参数个数 \~english The number of parameters which need update + IMV_String* pParamNameList; ///< \~chinese 事件相关的属性名列集合(SDK内部缓存) \~english Array of parameter's name which is related(cached within the SDK) +}IMV_SMsgChannelArg; + +/// \~chinese +/// \brief Chunk数据信息 +/// \~english +/// \brief Chunk data information +typedef struct _IMV_ChunkDataInfo +{ + unsigned int chunkID; ///< \~chinese ChunkID \~english ChunkID + unsigned int nParamCnt; ///< \~chinese 属性名个数 \~english The number of paramNames + IMV_String* pParamNameList; ///< \~chinese Chunk数据对应的属性名集合(SDK内部缓存) \~english ParamNames Corresponding property name of chunk data(cached within the SDK) +}IMV_ChunkDataInfo; + +/// \~chinese +/// \brief 帧图像信息 +/// \~english +/// \brief The frame image information +typedef struct _IMV_FrameInfo +{ + uint64_t blockId; ///< \~chinese 帧Id(仅对GigE/Usb/PCIe相机有效) \~english The block ID(GigE/Usb/PCIe camera only) + unsigned int status; ///< \~chinese 数据帧状态(0是正常状态) \~english The status of frame(0 is normal status) + unsigned int width; ///< \~chinese 图像宽度 \~english The width of image + unsigned int height; ///< \~chinese 图像高度 \~english The height of image + unsigned int size; ///< \~chinese 图像大小 \~english The size of image + IMV_EPixelType pixelFormat; ///< \~chinese 图像像素格式 \~english The pixel format of image + uint64_t timeStamp; ///< \~chinese 图像时间戳(仅对GigE/Usb/PCIe相机有效) \~english The timestamp of image(GigE/Usb/PCIe camera only) + unsigned int chunkCount; ///< \~chinese 帧数据中包含的Chunk个数(仅对GigE/Usb相机有效) \~english The number of chunk in frame data(GigE/Usb Camera Only) + unsigned int paddingX; ///< \~chinese 图像paddingX(仅对GigE/Usb/PCIe相机有效) \~english The paddingX of image(GigE/Usb/PCIe camera only) + unsigned int paddingY; ///< \~chinese 图像paddingY(仅对GigE/Usb/PCIe相机有效) \~english The paddingY of image(GigE/Usb/PCIe camera only) + unsigned int recvFrameTime; ///< \~chinese 图像在网络传输所用的时间(单位:微秒,非GigE相机该值为0) \~english The time taken for the image to be transmitted over the network(unit:us, The value is 0 for non-GigE camera) + unsigned int nReserved[19]; ///< \~chinese 预留字段 \~english Reserved field +}IMV_FrameInfo; + +/// \~chinese +/// \brief 帧图像数据信息 +/// \~english +/// \brief Frame image data information +typedef struct _IMV_Frame +{ + IMV_FRAME_HANDLE frameHandle; ///< \~chinese 帧图像句柄(SDK内部帧管理用) \~english Frame image handle(used for managing frame within the SDK) + unsigned char* pData; ///< \~chinese 帧图像数据的内存首地址 \~english The starting address of memory of image data + IMV_FrameInfo frameInfo; ///< \~chinese 帧信息 \~english Frame information + unsigned int nReserved[10]; ///< \~chinese 预留字段 \~english Reserved field +}IMV_Frame; + +/// \~chinese +/// \brief PCIE设备统计流信息 +/// \~english +/// \brief PCIE device stream statistics information +typedef struct _IMV_PCIEStreamStatsInfo +{ + unsigned int imageError; ///< \~chinese 图像错误的帧数 \~english Number of images error frames + unsigned int lostPacketBlock; ///< \~chinese 丢包的帧数 \~english Number of frames lost + unsigned int nReserved0[10]; ///< \~chinese 预留 \~english Reserved field + + unsigned int imageReceived; ///< \~chinese 正常获取的帧数 \~english Number of frames acquired + double fps; ///< \~chinese 帧率 \~english Frame rate + double bandwidth; ///< \~chinese 带宽(Mbps) \~english Bandwidth(Mbps) + unsigned int nReserved[8]; ///< \~chinese 预留 \~english Reserved field +}IMV_PCIEStreamStatsInfo; + +/// \~chinese +/// \brief U3V设备统计流信息 +/// \~english +/// \brief U3V device stream statistics information +typedef struct _IMV_U3VStreamStatsInfo +{ + unsigned int imageError; ///< \~chinese 图像错误的帧数 \~english Number of images error frames + unsigned int lostPacketBlock; ///< \~chinese 丢包的帧数 \~english Number of frames lost + unsigned int nReserved0[10]; ///< \~chinese 预留 \~english Reserved field + + unsigned int imageReceived; ///< \~chinese 正常获取的帧数 \~english Number of images error frames + double fps; ///< \~chinese 帧率 \~english Frame rate + double bandwidth; ///< \~chinese 带宽(Mbps) \~english Bandwidth(Mbps) + unsigned int nReserved[8]; ///< \~chinese 预留 \~english Reserved field +}IMV_U3VStreamStatsInfo; + +/// \~chinese +/// \brief Gige设备统计流信息 +/// \~english +/// \brief Gige device stream statistics information +typedef struct _IMV_GigEStreamStatsInfo +{ + unsigned int nReserved0[10]; ///< \~chinese 预留 \~english Reserved field + + unsigned int imageError; ///< \~chinese 图像错误的帧数 \~english Number of image error frames + unsigned int lostPacketBlock; ///< \~chinese 丢包的帧数 \~english Number of frames lost + unsigned int nReserved1[4]; ///< \~chinese 预留 \~english Reserved field + unsigned int nReserved2[5]; ///< \~chinese 预留 \~english Reserved field + + unsigned int imageReceived; ///< \~chinese 正常获取的帧数 \~english Number of frames acquired + double fps; ///< \~chinese 帧率 \~english Frame rate + double bandwidth; ///< \~chinese 带宽(Mbps) \~english Bandwidth(Mbps) + unsigned int nReserved[4]; ///< \~chinese 预留 \~english Reserved field +}IMV_GigEStreamStatsInfo; + +/// \~chinese +/// \brief 统计流信息 +/// \~english +/// \brief Stream statistics information +typedef struct _IMV_StreamStatisticsInfo +{ + IMV_ECameraType nCameraType; ///< \~chinese 设备类型 \~english Device type + + union + { + IMV_PCIEStreamStatsInfo pcieStatisticsInfo; ///< \~chinese PCIE设备统计信息 \~english PCIE device statistics information + IMV_U3VStreamStatsInfo u3vStatisticsInfo; ///< \~chinese U3V设备统计信息 \~english U3V device statistics information + IMV_GigEStreamStatsInfo gigeStatisticsInfo; ///< \~chinese Gige设备统计信息 \~english GIGE device statistics information + }; +}IMV_StreamStatisticsInfo; + +/// \~chinese +/// \brief 枚举属性的枚举值信息 +/// \~english +/// \brief Enumeration property 's enumeration value information +typedef struct _IMV_EnumEntryInfo +{ + uint64_t value; ///< \~chinese 枚举值 \~english Enumeration value + char name[IMV_MAX_STRING_LENTH]; ///< \~chinese symbol名 \~english Symbol name +}IMV_EnumEntryInfo; + +/// \~chinese +/// \brief 枚举属性的可设枚举值列表信息 +/// \~english +/// \brief Enumeration property 's settable enumeration value list information +typedef struct _IMV_EnumEntryList +{ + unsigned int nEnumEntryBufferSize; ///< \~chinese 存放枚举值内存大小 \~english The size of saving enumeration value + IMV_EnumEntryInfo* pEnumEntryInfo; ///< \~chinese 存放可设枚举值列表(调用者分配缓存) \~english Save the list of settable enumeration value(allocated cache by the caller) +}IMV_EnumEntryList; + +/// \~chinese +/// \brief 像素转换结构体 +/// \~english +/// \brief Pixel convert structure +typedef struct _IMV_PixelConvertParam +{ + unsigned int nWidth; ///< [IN] \~chinese 图像宽 \~english Width + unsigned int nHeight; ///< [IN] \~chinese 图像高 \~english Height + IMV_EPixelType ePixelFormat; ///< [IN] \~chinese 像素格式 \~english Pixel format + unsigned char* pSrcData; ///< [IN] \~chinese 输入图像数据 \~english Input image data + unsigned int nSrcDataLen; ///< [IN] \~chinese 输入图像长度 \~english Input image length + unsigned int nPaddingX; ///< [IN] \~chinese 图像宽填充 \~english Padding X + unsigned int nPaddingY; ///< [IN] \~chinese 图像高填充 \~english Padding Y + IMV_EBayerDemosaic eBayerDemosaic; ///< [IN] \~chinese 转换Bayer格式算法 \~english Alorithm used for Bayer demosaic + IMV_EPixelType eDstPixelFormat; ///< [IN] \~chinese 目标像素格式 \~english Destination pixel format + unsigned char* pDstBuf; ///< [OUT] \~chinese 输出数据缓存(调用者分配缓存) \~english Output data buffer(allocated cache by the caller) + unsigned int nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size + unsigned int nDstDataLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length + unsigned int nReserved[8]; ///< \~chinese 预留 \~english Reserved field +}IMV_PixelConvertParam; + +/// \~chinese +/// \brief 录像结构体 +/// \~english +/// \brief Record structure +typedef struct _IMV_RecordParam +{ + unsigned int nWidth; ///< [IN] \~chinese 图像宽 \~english Width + unsigned int nHeight; ///< [IN] \~chinese 图像高 \~english Height + float fFameRate; ///< [IN] \~chinese 帧率(大于0) \~english Frame rate(greater than 0) + unsigned int nQuality; ///< [IN] \~chinese 视频质量(1-100) \~english Video quality(1-100) + IMV_EVideoType recordFormat; ///< [IN] \~chinese 视频格式 \~english Video format + const char* pRecordFilePath; ///< [IN] \~chinese 保存视频路径 \~english Save video path + unsigned int nReserved[5]; ///< \~chinese 预留 \~english Reserved +}IMV_RecordParam; + +/// \~chinese +/// \brief 录像用帧信息结构体 +/// \~english +/// \brief Frame information for recording structure +typedef struct _IMV_RecordFrameInfoParam +{ + unsigned char* pData; ///< [IN] \~chinese 图像数据 \~english Image data + unsigned int nDataLen; ///< [IN] \~chinese 图像数据长度 \~english Image data length + unsigned int nPaddingX; ///< [IN] \~chinese 图像宽填充 \~english Padding X + unsigned int nPaddingY; ///< [IN] \~chinese 图像高填充 \~english Padding Y + IMV_EPixelType ePixelFormat; ///< [IN] \~chinese 像素格式 \~english Pixel format + unsigned int nReserved[5]; ///< \~chinese 预留 \~english Reserved +}IMV_RecordFrameInfoParam; + +/// \~chinese +/// \brief 图像翻转结构体 +/// \~english +/// \brief Flip image structure +typedef struct _IMV_FlipImageParam +{ + unsigned int nWidth; ///< [IN] \~chinese 图像宽 \~english Width + unsigned int nHeight; ///< [IN] \~chinese 图像高 \~english Height + IMV_EPixelType ePixelFormat; ///< [IN] \~chinese 像素格式 \~english Pixel format + IMV_EFlipType eFlipType; ///< [IN] \~chinese 翻转类型 \~english Flip type + unsigned char* pSrcData; ///< [IN] \~chinese 输入图像数据 \~english Input image data + unsigned int nSrcDataLen; ///< [IN] \~chinese 输入图像长度 \~english Input image length + unsigned char* pDstBuf; ///< [OUT] \~chinese 输出数据缓存(调用者分配缓存) \~english Output data buffer(allocated cache by the caller) + unsigned int nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size + unsigned int nDstDataLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length + unsigned int nReserved[8]; ///< \~chinese 预留 \~english Reserved +}IMV_FlipImageParam; + +/// \~chinese +/// \brief 图像旋转结构体 +/// \~english +/// \brief Rotate image structure +typedef struct _IMV_RotateImageParam +{ + unsigned int nWidth; ///< [IN][OUT] \~chinese 图像宽 \~english Width + unsigned int nHeight; ///< [IN][OUT] \~chinese 图像高 \~english Height + IMV_EPixelType ePixelFormat; ///< [IN] \~chinese 像素格式 \~english Pixel format + IMV_ERotationAngle eRotationAngle; ///< [IN] \~chinese 旋转角度 \~english Rotation angle + unsigned char* pSrcData; ///< [IN] \~chinese 输入图像数据 \~english Input image data + unsigned int nSrcDataLen; ///< [IN] \~chinese 输入图像长度 \~english Input image length + unsigned char* pDstBuf; ///< [OUT] \~chinese 输出数据缓存(调用者分配缓存) \~english Output data buffer(allocated cache by the caller) + unsigned int nDstBufSize; ///< [IN] \~chinese 提供的输出缓冲区大小 \~english Provided output buffer size + unsigned int nDstDataLen; ///< [OUT] \~chinese 输出数据长度 \~english Output data length + unsigned int nReserved[8]; ///< \~chinese 预留 \~english Reserved +}IMV_RotateImageParam; + +/// \~chinese +/// \brief 设备连接状态事件回调函数声明 +/// \param pParamUpdateArg [in] 回调时主动推送的设备连接状态事件信息 +/// \param pUser [in] 用户自定义数据 +/// \~english +/// \brief Call back function declaration of device connection status event +/// \param pStreamArg [in] The device connection status event which will be active pushed out during the callback +/// \param pUser [in] User defined data +typedef void(*IMV_ConnectCallBack)(const IMV_SConnectArg* pConnectArg, void* pUser); + +/// \~chinese +/// \brief 参数更新事件回调函数声明 +/// \param pParamUpdateArg [in] 回调时主动推送的参数更新事件信息 +/// \param pUser [in] 用户自定义数据 +/// \~english +/// \brief Call back function declaration of parameter update event +/// \param pStreamArg [in] The parameter update event which will be active pushed out during the callback +/// \param pUser [in] User defined data +typedef void(*IMV_ParamUpdateCallBack)(const IMV_SParamUpdateArg* pParamUpdateArg, void* pUser); + +/// \~chinese +/// \brief 流事件回调函数声明 +/// \param pStreamArg [in] 回调时主动推送的流事件信息 +/// \param pUser [in] 用户自定义数据 +/// \~english +/// \brief Call back function declaration of stream event +/// \param pStreamArg [in] The stream event which will be active pushed out during the callback +/// \param pUser [in] User defined data +typedef void(*IMV_StreamCallBack)(const IMV_SStreamArg* pStreamArg, void* pUser); + +/// \~chinese +/// \brief 消息通道事件回调函数声明 +/// \param pMsgChannelArg [in] 回调时主动推送的消息通道事件信息 +/// \param pUser [in] 用户自定义数据 +/// \~english +/// \brief Call back function declaration of message channel event +/// \param pMsgChannelArg [in] The message channel event which will be active pushed out during the callback +/// \param pUser [in] User defined data +typedef void(*IMV_MsgChannelCallBack)(const IMV_SMsgChannelArg* pMsgChannelArg, void* pUser); + +/// \~chinese +/// \brief 帧数据信息回调函数声明 +/// \param pFrame [in] 回调时主动推送的帧信息 +/// \param pUser [in] 用户自定义数据 +/// \~english +/// \brief Call back function declaration of frame data information +/// \param pFrame [in] The frame information which will be active pushed out during the callback +/// \param pUser [in] User defined data +typedef void(*IMV_FrameCallBack)(IMV_Frame* pFrame, void* pUser); + +#endif // __IMV_DEFINES_H__ \ No newline at end of file diff --git a/LidarPublisher.cpp b/LidarPublisher.cpp new file mode 100644 index 0000000..e69de29 diff --git a/ScreenCamera_2024-11-21-20-52-13.json b/ScreenCamera_2024-11-21-20-52-13.json new file mode 100644 index 0000000..16d13bd --- /dev/null +++ b/ScreenCamera_2024-11-21-20-52-13.json @@ -0,0 +1,41 @@ +{ + "class_name" : "PinholeCameraParameters", + "extrinsic" : + [ + 0.82349700295056028, + 0.51794784004159533, + 0.23147941836735964, + 0.0, + -0.55055775397237539, + 0.82806754878624445, + 0.10578418685245053, + 0.0, + -0.1368899034711418, + -0.21455574949972034, + 0.96707134415423301, + 0.0, + -2.9882837950628538, + -0.94906622954748698, + 10.63537376453692, + 1.0 + ], + "intrinsic" : + { + "height" : 1080, + "intrinsic_matrix" : + [ + 935.30743608719376, + 0.0, + 0.0, + 0.0, + 935.30743608719376, + 0.0, + 959.5, + 539.5, + 1.0 + ], + "width" : 1920 + }, + "version_major" : 1, + "version_minor" : 0 +} \ No newline at end of file diff --git a/ScreenCamera_2024-11-25-22-24-01.json b/ScreenCamera_2024-11-25-22-24-01.json new file mode 100644 index 0000000..c6a1c16 --- /dev/null +++ b/ScreenCamera_2024-11-25-22-24-01.json @@ -0,0 +1,41 @@ +{ + "class_name" : "PinholeCameraParameters", + "extrinsic" : + [ + 0.939223094717625, + 0.062346439634526594, + 0.33759872602535923, + 0.0, + 0.11366480802410098, + -0.98438229385923792, + -0.13443143588189957, + 0.0, + 0.32394488692660589, + 0.16463420361918521, + -0.93164118051575262, + 0.0, + -5.5072699140410242, + 0.46811610616831523, + 12.42305128653331, + 1.0 + ], + "intrinsic" : + { + "height" : 1080, + "intrinsic_matrix" : + [ + 935.30743608719376, + 0.0, + 0.0, + 0.0, + 935.30743608719376, + 0.0, + 959.5, + 539.5, + 1.0 + ], + "width" : 1920 + }, + "version_major" : 1, + "version_minor" : 0 +} \ No newline at end of file diff --git a/api_alg.py b/api_alg.py new file mode 100644 index 0000000..8a8d234 --- /dev/null +++ b/api_alg.py @@ -0,0 +1,209 @@ +#Import modules +import cv2 +import numpy as np +import math +import time +import sys +import json + +# 1、src 放标准图还是待检测图 +# 2、问题一:两张图的尺寸要一致 +# 3、问题二:相机的z轴 是手臂的y轴 +# 4、所有参数应该是 第二个参数到第一个参数的差值::标准图必须做目标图像 +# 5、if m.distance < 0.72*n.distance: 这个阈值是个关键参数,越小定位约精准 +# 6、assert(isRotationMatrix(R)) 报错是因为截图或者拉伸的原因,使得角度旋转无解 +# 7、截图比例会影响旋转矩阵,甚至会使得旋转矩阵无解。一定要4:3 +# 8、原图中目标图像的像素数量与目标图像的像素数量,【缩放比】越接近,M的值越准确 +# 9、缩放比需要打印 +# 10、会改变M的参数变量包括: +# img1 = cv2.resize +# interpolation=cv2.INTER_AREA +# cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) 1.0 +# if m.distance < 0.85 * n.distance: 0.85 +# 11、编写自动化选择参数脚本!!!!自动找到最优解 +# 12、可优化参数: +# cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) +# cv2.resize + +######################################################################## +#Import pictures +homo = "./image/2_origin_centor.jpg" +homo_train = "./image/10_bigorigin_rz_x.jpg" + +homo = "./scp_file//o.jpg" +homo_train = "./scp_file/6_-0.59803_0.264184_0.588617_-1.556_0.343_1.072.jpg" + +def cal_homo(homo_train, homo): + + start = time.time() + # interpolation=cv2.INTER_AREA 必须加 + img1 = cv2.imread(homo_train, cv2.IMREAD_GRAYSCALE) + img1 = cv2.resize(img1, (int(img1.shape[1] / 4), int(img1.shape[0] / 4)), interpolation=cv2.INTER_AREA) # 必须加 + img2 = cv2.imread(homo, cv2.IMREAD_GRAYSCALE) + img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]), interpolation=cv2.INTER_AREA) # 必须加,两张照片必须同样尺寸 + + #Feature Extraction + MIN_MATCH_COUNT = 20 ##修改 + sift = cv2.xfeatures2d.SIFT_create() + + kp1, des1 = sift.detectAndCompute(img1, None) + kp2, des2 = sift.detectAndCompute(img2, None) + + FLANN_INDEX_KDTREE = 0 + + index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) + search_params = dict(checks = 50) + + flann = cv2.FlannBasedMatcher(index_params, search_params) + + matches = flann.knnMatch(des1, des2, k=2) + + # store all the good matches as per Lowe's ratio test. + good = [] + for m,n in matches: + if m.distance < 0.85 * n.distance: + good.append(m) + + if len(good)>MIN_MATCH_COUNT: + src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) + dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) + + + #Finds homography + # M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) ## 修改 1.0 -> 5.0 + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 3, maxIters=2000, confidence=0.99) ## 修改 1.0 -> 5.0 + print("api_alg 单应性矩阵 M:\n", M) + + matchesMask = mask.ravel().tolist() + + h,w = img1.shape + pts = np.float32([ [0,0], [0,h-1], [w-1,h-1], [w-1,0] ]).reshape(-1, 1, 2) + dst = cv2.perspectiveTransform(pts, M) + + img2 = cv2.polylines(img2, [np.int32(dst)], True, 255, 3, cv2.LINE_AA) + + else: + # print ("api_alg : Not enough matches are found - %d/%d") % (len(good), MIN_MATCH_COUNT) + matchesMask = None + + # for draw + # draw_params = dict(matchColor = (0,255,0), # draw matches in green color + # singlePointColor = None, + # matchesMask = matchesMask, # draw only inliers + # flags = 2) + # img3 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params) + # plt.imshow(img3, 'gray'),plt.show() + + # camera pose from H whitout K + def cameraPoseFromHomography(H): + norm1 = np.linalg.norm(H[:, 0]) + norm2 = np.linalg.norm(H[:, 1]) + tnorm = (norm1 + norm2) / 2.0 + H1 = H[:, 0] / norm1 + H2 = H[:, 1] / norm2 + H3 = np.cross(H1, H2) + T = H[:, 2] / tnorm + return np.array([H1, H2, H3, T]).transpose() + + RT = cameraPoseFromHomography(M) + # print("api_alg RT whitout K", RT) + + focal_length = img1.shape[1] # 使用摄像头的宽度(像素)代表焦距 + center = (img1.shape[1] / 2, img1.shape[0] / 2) # 使用图像的中心代替光学中心 + K = np.array([[focal_length, 0, center[0]], + [0, focal_length, center[1]], + [0, 0, 1]]) + + # camera pose from H whit K + num, Rs, Ts, Ns = cv2.decomposeHomographyMat(M, K) + # print("api_alg Rs", Rs) + # print("api_alg Ts", Ts) + + # Checks if a matrix is a valid rotation matrix. + def isRotationMatrix(R) : + Rt = np.transpose(R) + shouldBeIdentity = np.dot(Rt, R) + I = np.identity(3, dtype = R.dtype) + n = np.linalg.norm(I - shouldBeIdentity) + return n < 1e-6 + + # Calculates rotation matrix to euler angles + # The result is the same as MATLAB except the order + # of the euler angles ( x and z are swapped ). + def rotationMatrixToEulerAngles(R) : + + # assert(isRotationMatrix(R)) + if not isRotationMatrix(R): + # print("api_alg : assert(isRotationMatrix(R)) !!!!") + return np.array([0, 0, 0]) + + sy = math.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0]) + + singular = sy < 1e-6 + + if not singular : + x = math.atan2(R[2,1] , R[2,2]) + y = math.atan2(-R[2,0], sy) + z = math.atan2(R[1,0], R[0,0]) + else : + x = math.atan2(-R[1,2], R[1,1]) + y = math.atan2(-R[2,0], sy) + z = 0 + + return np.array([x, y, z]) + + # Conver the 4 rotation matrix solutions into XYZ Euler angles + # 获取最后一组值 + i = 0 + for i in range(0, len(Rs)): + # 获取最后一组值 + angles = rotationMatrixToEulerAngles(Rs[i]) + x = np.degrees(angles[0]) + y = np.degrees(angles[1]) + z = np.degrees(angles[2]) + anglesDeg = np.array([x,y,z]) + # print("api_alg 角度: ", anglesDeg) + + R = Rs[num - 1] + T = Ts[num - 1] + + # print("api_alg : Rs矩阵") + # for i in range(len(Rs)): print(Rs[i]) + # print("api_alg : Ts矩阵\n", Ts) + + rand = [x / 180 * math.pi, y / 180 * math.pi, z / 180 * math.pi] + + print("api_alg 图像计算旋转矩阵 R: \n", R) + print("api_alg 图像计算角度偏移 a: ", anglesDeg) + print("api_alg 图像计算弧度偏移 r: ", rand) + print("api_alg 图像计算平移偏移 t: ", [T[0][0], T[1][0], T[2][0]]) + + end = time.time() + print("api_alg 程序的运行时间为:{}".format(end-start)) + print(rand[0], rand[1], rand[2]) + + return rand[0], rand[1], rand[2], M[0][0], M[1][1], M[0][2], M[1][2], R, T + +if __name__ == '__main__': + resp = {'code': 0, 'message': 'success'} + if len(sys.argv) != 3: + resp['code'] = -1 + resp['message'] = '参数错误!' + else: + img1 = sys.argv[1] + img2 = sys.argv[2] + result = cal_homo(img1, img2) + resp['result'] = { + 'drx': result[0], + 'dry': result[1], + 'drz': result[2], + 'hs': result[3], + 'ws': result[4], + 'xf': result[5], + 'yf': result[6], + 'dx': result[8][0][0], + 'dy': result[8][1][0], + 'dz': result[8][2][0], + } + + print(json.dumps(resp, indent = 0, ensure_ascii = False)) diff --git a/api_alg_pnp.py b/api_alg_pnp.py new file mode 100644 index 0000000..0632483 --- /dev/null +++ b/api_alg_pnp.py @@ -0,0 +1,332 @@ +#Import modules +import os +from unicodedata import mirrored +import cv2 +import numpy as np +import math +import time +import json +import sys +# import transforms3d as tfs + +# 1、src 放标准图还是待检测图 +# 2、问题一:两张图的尺寸要一致 +# 3、问题二:相机的z轴 是手臂的y轴 +# 4、所有参数应该是 第二个参数到第一个参数的差值::标准图必须做目标图像 +# 5、if m.distance < 0.72*n.distance: 这个阈值是个关键参数,越小定位约精准 +# 6、assert(isRotationMatrix(R)) 报错是因为截图或者拉伸的原因,使得角度旋转无解 +# 7、截图比例会影响旋转矩阵,甚至会使得旋转矩阵无解。一定要4:3 +# 8、原图中目标图像的像素数量与目标图像的像素数量,【缩放比】越接近,M的值越准确 +# 9、缩放比需要打印 +# 10、会改变M的参数变量包括: +# img1 = cv2.resize +# interpolation=cv2.INTER_AREA +# cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 1.0) 1.0 +# if m.distance < 0.85 * n.distance: 0.85 +# 11、编写自动化选择参数脚本!!!!自动找到最优解 +# 12、可优化参数: +# cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) +# cv2.resize + +######################################################################## +#Import pictures +homo = "./image/2_origin_centor.jpg" +homo_train = "./image/10_bigorigin_rz_x.jpg" + +homo = "./scp_file//o.jpg" +homo_train = "./scp_file/6_-0.59803_0.264184_0.588617_-1.556_0.343_1.072.jpg" + +homo = "./error1009/grayscale1.jpg" +homo_train = "./error1009/9983823d/GRAY_SCALE/WIDE/1/IMG_20221009_105934.jpg" + +# homo = "./error0926/c24.jpg" +# homo = "./error0928/1g.jpg" +# homo_train = "./error0926/IMG_20220926_165931.jpg" + +homo = "./error1010/sfrplus.jpg" +homo_train = "./error1010/IMG_20221010_162855.jpg" + +# homo_train = "./060701/IMG_20230604_130953.jpg" +# homo = "./error06042/C24.jpg" +# homo_train = "./060701/IMG_20230603_185437.jpg" +# homo_train = "./060701/IMG_20230603_185512.jpg" +# homo_train = "./060701/IMG_20230603_185518.jpg" +# homo_train = "./error0604/IMG_20230604_175620.jpg" +# homo_train = "./error0604/IMG_20230604_175620.jpg" +# homo_train = "./error06042/IMG_20230604_182406.jpg" + + +homo = "./error0605/grayscale.jpg" +homo_train = "./error0605/IMG_20230605_121151.jpg" + +# homo = "./error0605/sfrplus.jpg" +# homo_train = "./error0605/IMG_20230605_132952.jpg" + +# homo = "./error0605 near/sfrplus.jpg" +# homo_train = "./error0605 near/IMG_20230605_174504.jpg" + +homo = "./error0605gray/grayscale.jpg" +homo_train = "./error0605gray/IMG_20230605_194543.jpg" + + +def Pnp(objpos, imgpos, M, cameraMatrix, coff_dis): + + dst_imgpos = cv2.perspectiveTransform(imgpos, M) + # imgp.append(dst_imgpos) + # pnp 求解 + _, rvec, tvec = cv2.solvePnP(objpos, dst_imgpos, cameraMatrix, None, flags=cv2.SOLVEPNP_UPNP) + # print(cv2.Rodrigues(rvec)) + rotM = cv2.Rodrigues(rvec)[0] + # camera_postion = -np.mat(rotM).T * np.mat(tvec) + # Ca = camera_postion.T + + # 计算相机坐标系的三轴旋转欧拉角,旋转后可以转出世界坐标系。旋转顺序z,y,x + thetaZ = math.atan2(rotM[1, 0], rotM[0, 0]) * 180.0 / math.pi + thetaY = math.atan2(-1.0 * rotM[2, 0], math.sqrt(rotM[2, 1] ** 2 + rotM[2, 2] ** 2)) * 180.0 / math.pi + thetaX = math.atan2(rotM[2, 1], rotM[2, 2]) * 180.0 / math.pi + + # 相机坐标系下值 + x = tvec[0] + y = tvec[1] + z = tvec[2] + + # 进行三次旋转 + def RotateByZ(Cx, Cy, thetaZ): + rz = thetaZ * math.pi / 180.0 + outX = math.cos(rz) * Cx - math.sin(rz) * Cy + outY = math.sin(rz) * Cx + math.cos(rz) * Cy + return outX, outY + + def RotateByY(Cx, Cz, thetaY): + ry = thetaY * math.pi / 180.0 + outZ = math.cos(ry) * Cz - math.sin(ry) * Cx + outX = math.sin(ry) * Cz + math.cos(ry) * Cx + return outX, outZ + + def RotateByX(Cy, Cz, thetaX): + rx = thetaX * math.pi / 180.0 + outY = math.cos(rx) * Cy - math.sin(rx) * Cz + outZ = math.sin(rx) * Cy + math.cos(rx) * Cz + return outY, outZ + + (x, y) = RotateByZ(x, y, -1.0 * thetaZ) + (x, z) = RotateByY(x, z, -1.0 * thetaY) + (y, z) = RotateByX(y, z, -1.0 * thetaX) + Cx = x * -1 + Cy = y * -1 + Cz = z * -1 + + # 输出相机位置 + camera_Location = [Cx, Cy, Cz] + # print("相机位姿",camera_Location) + + # 输出相机旋转角 + # print("相机旋转角度:",'[', thetaX, thetaY, -thetaZ, ']') + + angles = [thetaX, thetaY, thetaZ] + #result = [camera_Location, "旋转角度", angles] + + return angles, camera_Location + + +# 欧拉角->旋转矩阵 +def eulerAnglesToRotationMatrix(theta) : + R_x = np.array([[1, 0, 0 ], + [0, math.cos(theta[0]), -math.sin(theta[0]) ], + [0, math.sin(theta[0]), math.cos(theta[0]) ] + ]) + R_y = np.array([[math.cos(theta[1]), 0, math.sin(theta[1]) ], + [0, 1, 0 ], + [-math.sin(theta[1]), 0, math.cos(theta[1]) ] + ]) + R_z = np.array([[math.cos(theta[2]), -math.sin(theta[2]), 0], + [math.sin(theta[2]), math.cos(theta[2]), 0], + [0, 0, 1] + ]) + R = np.dot(R_z, np.dot( R_y, R_x )) + return R + + +def _angel_zoom(rx, ry, rz, angel_zoom=1): + ax, angle = tfs.euler.euler2axangle(rx, ry, rz, "sxyz") + eulers = tfs.euler.axangle2euler(ax * angel_zoom, angle * angel_zoom, "sxyz") + return eulers[0], eulers[1], eulers[2] + + +# 固定 resolution = 1, sigma = 1.9 +def cal_homo(homo_train, homo, mirror = False, resolution = 1, angle_zoom=1, sigma = 1.6): + + # 默认初始化参数 + resolution = 1 + + angle_zoom = 1 + + # SIFT:该值越大,被选中的特征点越多,计算时间越长,推荐10 同时适用于广角和后置 + edgeThreshold = 10 + + # SIFT:该值越大,精度越高,计算时间越长 + sigma = 4.5 + # if os.path.basename(homo) == "grayscale.jpg": sigma = 1.9 + + ransacReprojThreshold = 3.0 # Homography: 该值越小,精度越高,对时间没有影像 + + # imgWidth、imgHeight 越大,精度越高,计算时间越长 + imgWidth = 1000 + imgHeight = 750 + # if os.path.basename(homo) == "grayscale.jpg": + # imgWidth = 1600 + # imgHeight = 1200 + + # 算法开始执行计时 + start = time.time() + + # 读取图像与标准图像进行对比 + img1 = cv2.imread(homo_train, cv2.IMREAD_GRAYSCALE) + if mirror: img1 = cv2.flip(img1, 1) + + img1 = cv2.resize(img1, (imgWidth, imgHeight), interpolation=cv2.INTER_AREA) # 使用INTER_AREA可以提升特征点识别率 + img2 = cv2.imread(homo, cv2.IMREAD_GRAYSCALE) + img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]), interpolation=cv2.INTER_AREA) # 使用INTER_AREA可以提升特征点识别率,两张照片必须同样尺寸 + + + # 1、使用 SIFT 进行特征提取 + MIN_MATCH_COUNT = 20 + MAX_MATCH_COUNT = 100 + + # 从优选择特征点,限定800个 + if resolution == 1: sift = cv2.xfeatures2d.SIFT_create(nfeatures=1500, nOctaveLayers=10, contrastThreshold=0.02, edgeThreshold=edgeThreshold, sigma=sigma) + else: sift = cv2.xfeatures2d.SIFT_create(nfeatures=1500) + + kp1, des1 = sift.detectAndCompute(img1, None) + kp2, des2 = sift.detectAndCompute(img2, None) + + + # 2、使用 flann 进行特征点匹配 + FLANN_INDEX_KDTREE = 1 + index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) + search_params = dict(checks = 50) + flann = cv2.FlannBasedMatcher(index_params, search_params) + matches = flann.knnMatch(des1, des2, k=2) + + + # 挑选匹配情况较好的特征点 + good = [] + for m,n in matches: + if m.distance < 0.85 * n.distance: + good.append(m) + # 从优选择特征点,限定MAX个特征 + # good = sorted(good, key=lambda x: x.distance) + # if len(good) >= MAX_MATCH_COUNT: good = good[:100] + + + # 如果特征匹配点的数量不低于 MIN_MATCH_COUNT 设置的数量 + if len(good) > MIN_MATCH_COUNT: + src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) + dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) + + # 3、查找单应矩阵 + # 修改第三个参数 1.0 -> 5.0 + # 利用基于RANSAC的鲁棒算法选择最优的四组配对点,再计算转换矩阵H(3*3)并返回,以便于反向投影错误率达到最小 + # ransacReprojThreshold 设置为 1.0,精度最高 + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, ransacReprojThreshold, maxIters=1500, confidence=0.998) ## 修改 1.0 -> 5.0 + # print("api_alg 单应性矩阵 M:\n", M) + matchesMask = mask.ravel().tolist() + + + # 用于测试显示,使用时注释 + import matplotlib.pyplot as plt + plt.ion() + draw_params = dict(matchColor = (0,255,0), + singlePointColor = None, + matchesMask = matchesMask, + flags = 2) + img3 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params) + plt.imshow(img3, 'gray'),plt.show() + + + # 4、采用PNP进行相机的姿态估计 + h, w = img1.shape + + # 模拟实际物体世界坐标参数 + if resolution == 1: + objpos = np.float32([[0.001, 0.001, 0], [0.001, 1.200, 0], [1.600, 1.200, 0], [1.600, 0.001, 0]]).reshape(-1, 1, 3) + else: + objpos = np.float32([[0.0008, 0.0008, 0], [0.0008, 0.5994, 0], [0.7992, 0.5994, 0], [0.7992, 0.0008, 0]]).reshape(-1, 1, 3) + imgpos = np.float32([[0,0], [0,h-1], [w-1,h-1], [w-1,0]]).reshape(-1, 1, 2) + + # 模拟相机参数 + focal_length = img1.shape[1] # 使用摄像头的宽度(像素)代表焦距 + center = (img1.shape[1] / 2, img1.shape[0] / 2) # 使用图像的中心代替光学中心 + K = np.array([[focal_length, 0, center[0]], + [0, focal_length, center[1]], + [0, 0, 1]]) + + angles, T = Pnp(objpos, imgpos, M, K, None) + rand = [angles[0] / 180 * math.pi, angles[1] / 180 * math.pi, angles[2] / 180 * math.pi] + R = eulerAnglesToRotationMatrix(angles) + # print("api_alg 图像计算旋转矩阵 R: \n", R) + # print("api_alg 图像计算角度偏移 a: ", angles) + # print("api_alg 图像计算弧度偏移 r: ", rand) + # print("api_alg 图像计算平移偏移 t: ", [[T[0][0]], [T[1][0]], [T[2][0]]]) + # print("mmatches count: ", len(matches), " good count: ", len(good), " matchesMask count: ", len(matchesMask)) + # print(rand[0], rand[1], rand[2], M[0][0], M[1][1], M[0][2], M[1][2]) + print("mmatches count: ", len(matches), " good count: ", len(good), " matchesMask count: ", len(matchesMask)) + print(rand[0], rand[1], rand[2], M[0][0], M[1][1], M[0][2], M[1][2]) + + end = time.time() + print("api_alg 程序的运行时间为:{}".format(end-start)) + # print(rand[0], rand[1], rand[2]) + if angle_zoom != 1: + rand[0], rand[1], rand[2] = _angel_zoom(rand[0], rand[1], rand[2], angle_zoom) + return rand[0], rand[1], rand[2], M[0][0], M[1][1], M[0][2], M[1][2], R, T + # img2 = cv2.polylines(img2, [np.int32(dst)], True, 255, 3, cv2.LINE_AA) + + else: + # print ("api_alg : Not enough matches are found - %d/%d") % (len(good), MIN_MATCH_COUNT) + matchesMask = None + # print("good features is too few!", "mmatches count: ", len(matches), " good count: ", len(good)) + + +if __name__ == '__main__': + cal_homo(homo_train, homo) + + # resp = {'code': 0, 'message': 'success'} + # if len(sys.argv) < 3: + # resp['code'] = -1 + # resp['message'] = '参数错误!' + # else: + # img1 = sys.argv[1] + # img2 = sys.argv[2] + # mirror = False + # resolution = 0 + # angle_zoom = 1 + # sigma = 1.3 + # if len(sys.argv) >= 4: + # mirror = sys.argv[3].lower() == 'true' + # if len(sys.argv) >= 5: + # resolution = int(sys.argv[4]) + # if len(sys.argv) >= 6: + # angle_zoom = float(sys.argv[5]) + # if len(sys.argv) >= 7: + # sigma = float(sys.argv[6]) + + # result = cal_homo(img1, img2, mirror, resolution, angle_zoom, sigma) + + # if result is not None: + # resp['result'] = { + # 'drx': result[0], + # 'dry': result[1], + # 'drz': result[2], + # 'hs': result[3], + # 'ws': result[4], + # 'xf': result[5], + # 'yf': result[6], + # 'dx': result[8][0][0], + # 'dy': result[8][1][0], + # 'dz': result[8][2][0], + # } + # else: + # resp['code'] = -1 + # resp['message'] = '解析错误!' + + # print(json.dumps(resp, indent = 2, ensure_ascii = False)) diff --git a/cloud.png b/cloud.png new file mode 100644 index 0000000..ec093a3 Binary files /dev/null and b/cloud.png differ diff --git a/config_file.txt b/config_file.txt new file mode 100644 index 0000000..14fc48b --- /dev/null +++ b/config_file.txt @@ -0,0 +1,12 @@ +9344 7000 +-2.5 2.5 +-2.5 2.5 +0.0 3.8 +0.000001 +2 +0 +11057.154 0.0 4538.85 0.0 +0.0 11044.943 3350.918 0.0 +0.0 0.0 1.0 0.0 +1.57 -1.57 1.0 +0 \ No newline at end of file diff --git a/convert.py b/convert.py new file mode 100644 index 0000000..aee07cc --- /dev/null +++ b/convert.py @@ -0,0 +1,97 @@ +# -- coding: utf-8 -- +import numpy as np +from scipy.spatial.transform import Rotation as rot + +import cv2 +import numpy as np +import math + +# 旋转矩阵转旋转向量(Rxyz->Rvector,按特定轴旋转) +def rotvector2rot(rotvector): + Rm = cv2.Rodrigues(rotvector)[0] + return Rm + +# 旋转矩阵转欧拉角 +def isRotationMatrix(R): + Rt = np.transpose(R) + shouldBeIdentity = np.dot(Rt, R) + I = np.identity(3, dtype=R.dtype) + n = np.linalg.norm(I - shouldBeIdentity) + return n < 1e-6 +def rot2euler(R): + # assert (isRotationMatrix(R)) + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) * 180 / np.pi + y = math.atan2(-R[2, 0], sy) * 180 / np.pi + z = math.atan2(R[1, 0], R[0, 0]) * 180 / np.pi + else: + x = math.atan2(-R[1, 2], R[1, 1]) * 180 / np.pi + y = math.atan2(-R[2, 0], sy) * 180 / np.pi + z = 0 + return np.array([x, y, z]) +def rot2eulerpi(R): + # assert (isRotationMatrix(R)) + sy = math.sqrt(R[0, 0] * R[0, 0] + R[1, 0] * R[1, 0]) + singular = sy < 1e-6 + if not singular: + x = math.atan2(R[2, 1], R[2, 2]) + y = math.atan2(-R[2, 0], sy) + z = math.atan2(R[1, 0], R[0, 0]) + else: + x = math.atan2(-R[1, 2], R[1, 1]) + y = math.atan2(-R[2, 0], sy) + z = 0 + return np.array([x, y, z]) +def rot_to_ypr_zyx(R): + """ + 将旋转矩阵R转换为Yaw-Pitch-Roll角度(Z-Y-X顺序) + """ + sin_p = 2 * (R[2, 0] ** 2 - R[0, 0] ** 2 + R[1, 0] ** 2) ** 0.5 + if sin_p < 1e-6: + sin_p = 1e-6 + if R[2, 0] > 0: + sin_p = -sin_p + + roll = np.arctan2(R[2, 0], R[2, 2]) + pitch = np.arcsin(-R[2, 1]) + yaw = np.arctan2(R[1, 0], R[0, 0]) + + return yaw, pitch, roll +def rot_to_ypr_xyz(R): + # 计算R的trace值 + tr = np.trace(R) + # 计算sqrt(R.T.R) - 1的模长,即平方根trace值 + sqrt_tr_m1 = np.sqrt(0.25 * ((tr - 3) ** 2) + (R[2, 2] - 1) ** 2) + + # 根据平方根trace值判断Yaw-Pitch-Roll角的计算方法 + yaw = np.arctan2(R[2, 1], R[2, 2]) # 使用arctan2计算Yaw角 + pitch = np.arcsin(-R[2, 0]) # 使用arcsin计算Pitch角 + roll = np.arctan2(R[1, 0], R[0, 0]) # 使用arctan2计算Roll角 + + return yaw, pitch, roll + +# 四元数转欧拉角 +def quaternion2euler(quaternion): + r = rot.from_quat(quaternion) + euler = r.as_euler('xyz', degrees=True) + return euler + +# 四元数转旋转矩阵 +def quaternion2rot(quaternion): + r = rot.from_quat(quaternion) + rot = r.as_matrix() + return rot + +# 欧拉角转四元数 +def euler2quaternion(euler): + r = rot.from_euler('xyz', euler, degrees=True) + quaternion = r.as_quat() + return quaternion + +# 欧拉角转旋转矩阵 +def euler2rot(euler): + r = rot.from_euler('xyz', euler, degrees=True) + rotation_matrix = r.as_matrix() + return rotation_matrix \ No newline at end of file diff --git a/deploy.prototxt b/deploy.prototxt new file mode 100644 index 0000000..1522f9f --- /dev/null +++ b/deploy.prototxt @@ -0,0 +1,130 @@ +name: "FCN" + +input: "data" +input_dim: 1 +input_dim: 1 +input_dim: 500 +input_dim: 500 + +layer { bottom: 'data' top: 'conv1_1' name: 'conv1_1' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 64 pad: 35 kernel_size: 3 } } +layer { bottom: 'conv1_1' top: 'conv1_1' name: 'relu1_1' type: "ReLU" } +layer { bottom: 'conv1_1' top: 'conv1_2' name: 'conv1_2' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 64 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv1_2' top: 'conv1_2' name: 'relu1_2' type: "ReLU" } +layer { name: 'pool1' bottom: 'conv1_2' top: 'pool1' type: "Pooling" + pooling_param { pool: MAX kernel_size: 2 stride: 2 } } + +layer { name: 'conv2_1' bottom: 'pool1' top: 'conv2_1' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 128 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv2_1' top: 'conv2_1' name: 'relu2_1' type: "ReLU" } +layer { bottom: 'conv2_1' top: 'conv2_2' name: 'conv2_2' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 128 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv2_2' top: 'conv2_2' name: 'relu2_2' type: "ReLU" } +layer { bottom: 'conv2_2' top: 'pool2' name: 'pool2' type: "Pooling" + pooling_param { pool: MAX kernel_size: 2 stride: 2 } } + +layer { bottom: 'pool2' top: 'conv3_1' name: 'conv3_1' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 256 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv3_1' top: 'conv3_1' name: 'relu3_1' type: "ReLU" } +layer { bottom: 'conv3_1' top: 'conv3_2' name: 'conv3_2' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 256 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv3_2' top: 'conv3_2' name: 'relu3_2' type: "ReLU" } +layer { bottom: 'conv3_2' top: 'conv3_3' name: 'conv3_3' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 256 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv3_3' top: 'conv3_3' name: 'relu3_3' type: "ReLU" } +layer { bottom: 'conv3_3' top: 'pool3' name: 'pool3' type: "Pooling" + pooling_param { pool: MAX kernel_size: 2 stride: 2 } } + +layer { bottom: 'pool3' top: 'conv4_1' name: 'conv4_1' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 512 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv4_1' top: 'conv4_1' name: 'relu4_1' type: "ReLU" } +layer { bottom: 'conv4_1' top: 'conv4_2' name: 'conv4_2' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 512 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv4_2' top: 'conv4_2' name: 'relu4_2' type: "ReLU" } +layer { bottom: 'conv4_2' top: 'conv4_3' name: 'conv4_3' type: "Convolution" + param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 512 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv4_3' top: 'conv4_3' name: 'relu4_3' type: "ReLU" } +layer { bottom: 'conv4_3' top: 'pool4' name: 'pool4' type: "Pooling" + pooling_param { pool: MAX kernel_size: 2 stride: 2 } } + +layer { bottom: 'pool4' top: 'conv5_1' name: 'conv5_1' type: "Convolution" + param { lr_mult: 100 decay_mult: 1 } param { lr_mult: 200 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 512 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv5_1' top: 'conv5_1' name: 'relu5_1' type: "ReLU" } +layer { bottom: 'conv5_1' top: 'conv5_2' name: 'conv5_2' type: "Convolution" + param { lr_mult: 100 decay_mult: 1 } param { lr_mult: 200 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 512 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv5_2' top: 'conv5_2' name: 'relu5_2' type: "ReLU" } +layer { bottom: 'conv5_2' top: 'conv5_3' name: 'conv5_3' type: "Convolution" + param { lr_mult: 100 decay_mult: 1 } param { lr_mult: 200 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 512 pad: 1 kernel_size: 3 } } +layer { bottom: 'conv5_3' top: 'conv5_3' name: 'relu5_3' type: "ReLU" } + +## DSN conv 1 ### +layer { name: 'score-dsn1' type: "Convolution" bottom: 'conv1_2' top: 'score-dsn1-up' + param { lr_mult: 0.01 decay_mult: 1 } param { lr_mult: 0.02 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 1 kernel_size: 1 } } +layer { type: "Crop" name: 'crop' bottom: 'score-dsn1-up' bottom: 'data' top: 'upscore-dsn1' } +layer { type: "Sigmoid" name: "sigmoid-dsn1" bottom: "upscore-dsn1" top:"sigmoid-dsn1"} + +### DSN conv 2 ### +layer { name: 'score-dsn2' type: "Convolution" bottom: 'conv2_2' top: 'score-dsn2' + param { lr_mult: 0.01 decay_mult: 1 } param { lr_mult: 0.02 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 1 kernel_size: 1 } } +layer { type: "Deconvolution" name: 'upsample_2' bottom: 'score-dsn2' top: 'score-dsn2-up' + param { lr_mult: 0 decay_mult: 1 } param { lr_mult: 0 decay_mult: 0} + convolution_param { kernel_size: 4 stride: 2 num_output: 1 } } +layer { type: "Crop" name: 'crop' bottom: 'score-dsn2-up' bottom: 'data' top: 'upscore-dsn2' } +layer { type: "Sigmoid" name: "sigmoid-dsn2" bottom: "upscore-dsn2" top:"sigmoid-dsn2"} + +### DSN conv 3 ### +layer { name: 'score-dsn3' type: "Convolution" bottom: 'conv3_3' top: 'score-dsn3' + param { lr_mult: 0.01 decay_mult: 1 } param { lr_mult: 0.02 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 1 kernel_size: 1 } } +layer { type: "Deconvolution" name: 'upsample_4' bottom: 'score-dsn3' top: 'score-dsn3-up' + param { lr_mult: 0 decay_mult: 1 } param { lr_mult: 0 decay_mult: 0} + convolution_param { kernel_size: 8 stride: 4 num_output: 1 } } +layer { type: "Crop" name: 'crop' bottom: 'score-dsn3-up' bottom: 'data' top: 'upscore-dsn3' } +layer { type: "Sigmoid" name: "sigmoid-dsn3" bottom: "upscore-dsn3" top:"sigmoid-dsn3"} + +###DSN conv 4### +layer { name: 'score-dsn4' type: "Convolution" bottom: 'conv4_3' top: 'score-dsn4' + param { lr_mult: 0.01 decay_mult: 1 } param { lr_mult: 0.02 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 1 kernel_size: 1 } } +layer { type: "Deconvolution" name: 'upsample_8' bottom: 'score-dsn4' top: 'score-dsn4-up' + param { lr_mult: 0 decay_mult: 1 } param { lr_mult: 0 decay_mult: 0} + convolution_param { kernel_size: 16 stride: 8 num_output: 1 } } +layer { type: "Crop" name: 'crop' bottom: 'score-dsn4-up' bottom: 'data' top: 'upscore-dsn4' } +layer { type: "Sigmoid" name: "sigmoid-dsn4" bottom: "upscore-dsn4" top:"sigmoid-dsn4"} + + +###DSN conv 5### +layer { name: 'score-dsn5' type: "Convolution" bottom: 'conv5_3' top: 'score-dsn5' + param { lr_mult: 0.01 decay_mult: 1 } param { lr_mult: 0.02 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 1 kernel_size: 1 } } +layer { type: "Deconvolution" name: 'upsample_16' bottom: 'score-dsn5' top: 'score-dsn5-up' + param { lr_mult: 0 decay_mult: 1 } param { lr_mult: 0 decay_mult: 0} + convolution_param { kernel_size: 32 stride: 16 num_output: 1 } } +layer { type: "Crop" name: 'crop' bottom: 'score-dsn5-up' bottom: 'data' top: 'upscore-dsn5' } +layer { type: "Sigmoid" name: "sigmoid-dsn5" bottom: "upscore-dsn5" top:"sigmoid-dsn5"} + + +### Concat and multiscale weight layer ### +layer { name: "concat" bottom: "upscore-dsn1" bottom: "upscore-dsn2" bottom: "upscore-dsn3" + bottom: "upscore-dsn4" bottom: "upscore-dsn5" top: "concat-upscore" type: "Concat" + concat_param { concat_dim: 1} } +layer { name: 'new-score-weighting' type: "Convolution" bottom: 'concat-upscore' top: 'upscore-fuse' + param { lr_mult: 0.01 decay_mult: 1 } param { lr_mult: 0.02 decay_mult: 0} + convolution_param { engine: CAFFE num_output: 1 kernel_size: 1 weight_filler {type: "constant" value: 0.2} } } +layer { type: "Sigmoid" name: "sigmoid-fuse" bottom: "upscore-fuse" top:"sigmoid-fuse"} \ No newline at end of file diff --git a/distorted_img.png b/distorted_img.png new file mode 100644 index 0000000..d888cc6 Binary files /dev/null and b/distorted_img.png differ diff --git a/find_velodyne_points_self_define.cpp b/find_velodyne_points_self_define.cpp new file mode 100644 index 0000000..88052eb --- /dev/null +++ b/find_velodyne_points_self_define.cpp @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#include + +#include "opencv2/opencv.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "lidar_camera_calibration/Corners.h" +#include "lidar_camera_calibration/PreprocessUtils.h" +#include "lidar_camera_calibration/Find_RT.h" + +#include "lidar_camera_calibration/marker_6dof.h" + +using namespace cv; +using namespace std; +using namespace ros; +using namespace message_filters; +using namespace pcl; + + +string CAMERA_INFO_TOPIC; +string VELODYNE_TOPIC; + + +Mat projection_matrix; + +pcl::PointCloud point_cloud; +Hesai::PointCloud point_cloud_hesai; + +Eigen::Quaterniond qlidarToCamera; +Eigen::Matrix3d lidarToCamera; + + +void callback_noCam(const sensor_msgs::PointCloud2ConstPtr& msg_pc, + const lidar_camera_calibration::marker_6dof::ConstPtr& msg_rt) +{ + ROS_INFO_STREAM("Velodyne scan received at " << msg_pc->header.stamp.toSec()); + ROS_INFO_STREAM("marker_6dof received at " << msg_rt->header.stamp.toSec()); + + // Loading Velodyne point cloud_sub + if (config.lidar_type == 0) // velodyne lidar + { + fromROSMsg(*msg_pc, point_cloud); + } + else if (config.lidar_type == 1) //hesai lidar + { + fromROSMsg(*msg_pc, point_cloud_hesai); + point_cloud = *(toMyPointXYZRID(point_cloud_hesai)); + } + + point_cloud = transform(point_cloud, config.initialTra[0], config.initialTra[1], config.initialTra[2], config.initialRot[0], config.initialRot[1], config.initialRot[2]); + + //Rotation matrix to transform lidar point cloud to camera's frame + + qlidarToCamera = Eigen::AngleAxisd(config.initialRot[2], Eigen::Vector3d::UnitZ()) + *Eigen::AngleAxisd(config.initialRot[1], Eigen::Vector3d::UnitY()) + *Eigen::AngleAxisd(config.initialRot[0], Eigen::Vector3d::UnitX()); + + lidarToCamera = qlidarToCamera.matrix(); + + std:: cout << "\n\nInitial Rot" << lidarToCamera << "\n"; + point_cloud = intensityByRangeDiff(point_cloud, config); + // x := x, y := -z, z := y + + //pcl::io::savePCDFileASCII ("/home/vishnu/PCDs/msg_point_cloud.pcd", pc); + + + cv::Mat temp_mat(config.s, CV_8UC3); + pcl::PointCloud retval = *(toPointsXYZ(point_cloud)); + + std::vector marker_info; + + for(std::vector::const_iterator it = msg_rt->dof.data.begin(); it != msg_rt->dof.data.end(); ++it) + { + marker_info.push_back(*it); + std::cout << *it << " "; + } + std::cout << "\n"; + + bool no_error = getCorners(temp_mat, retval, config.P, config.num_of_markers, config.MAX_ITERS); + if(no_error){ + find_transformation(marker_info, config.num_of_markers, config.MAX_ITERS, lidarToCamera); + } + //ros::shutdown(); +} + +void callback(const sensor_msgs::CameraInfoConstPtr& msg_info, + const sensor_msgs::PointCloud2ConstPtr& msg_pc, + const lidar_camera_calibration::marker_6dof::ConstPtr& msg_rt) +{ + + ROS_INFO_STREAM("Camera info received at " << msg_info->header.stamp.toSec()); + ROS_INFO_STREAM("Velodyne scan received at " << msg_pc->header.stamp.toSec()); + ROS_INFO_STREAM("marker_6dof received at " << msg_rt->header.stamp.toSec()); + + float p[12]; + float *pp = p; + for (boost::array::const_iterator i = msg_info->P.begin(); i != msg_info->P.end(); i++) + { + *pp = (float)(*i); + pp++; + } + cv::Mat(3, 4, CV_32FC1, &p).copyTo(projection_matrix); + + + + // Loading Velodyne point cloud_sub + if (config.lidar_type == 0) // velodyne lidar + { + fromROSMsg(*msg_pc, point_cloud); + } + else if (config.lidar_type == 1) //hesai lidar + { + fromROSMsg(*msg_pc, point_cloud_hesai); + point_cloud = *(toMyPointXYZRID(point_cloud_hesai)); + } + + point_cloud = transform(point_cloud, config.initialTra[0], config.initialTra[1], config.initialTra[2], config.initialRot[0], config.initialRot[1], config.initialRot[2]); + + //Rotation matrix to transform lidar point cloud to camera's frame + + qlidarToCamera = Eigen::AngleAxisd(config.initialRot[2], Eigen::Vector3d::UnitZ()) + *Eigen::AngleAxisd(config.initialRot[1], Eigen::Vector3d::UnitY()) + *Eigen::AngleAxisd(config.initialRot[0], Eigen::Vector3d::UnitX()); + + lidarToCamera = qlidarToCamera.matrix(); + + point_cloud = intensityByRangeDiff(point_cloud, config); + // x := x, y := -z, z := y + + //pcl::io::savePCDFileASCII ("/home/vishnu/PCDs/msg_point_cloud.pcd", pc); + + + cv::Mat temp_mat(config.s, CV_8UC3); + pcl::PointCloud retval = *(toPointsXYZ(point_cloud)); + + std::vector marker_info; + + for(std::vector::const_iterator it = msg_rt->dof.data.begin(); it != msg_rt->dof.data.end(); ++it) + { + marker_info.push_back(*it); + std::cout << *it << " "; + } + std::cout << "\n"; + + getCorners(temp_mat, retval, projection_matrix, config.num_of_markers, config.MAX_ITERS); + find_transformation(marker_info, config.num_of_markers, config.MAX_ITERS, lidarToCamera); + //ros::shutdown(); +} + + +int main(int argc, char** argv) +{ + readConfig(); + ros::init(argc, argv, "find_transform"); + + ros::NodeHandle n; + + if(config.useCameraInfo) + { + ROS_INFO_STREAM("Reading CameraInfo from topic"); + n.getParam("/lidar_camera_calibration/camera_info_topic", CAMERA_INFO_TOPIC); + n.getParam("/lidar_camera_calibration/velodyne_topic", VELODYNE_TOPIC); + + message_filters::Subscriber info_sub(n, CAMERA_INFO_TOPIC, 1); + message_filters::Subscriber cloud_sub(n, VELODYNE_TOPIC, 1); + message_filters::Subscriber rt_sub(n, "lidar_camera_calibration_rt", 1); + + std::cout << "done1\n"; + + typedef sync_policies::ApproximateTime MySyncPolicy; + Synchronizer sync(MySyncPolicy(10), info_sub, cloud_sub, rt_sub); + sync.registerCallback(boost::bind(&callback, _1, _2, _3)); + + ros::spin(); + } + else + { + ROS_INFO_STREAM("Reading CameraInfo from configuration file"); + n.getParam("/lidar_camera_calibration/velodyne_topic", VELODYNE_TOPIC); + + message_filters::Subscriber cloud_sub(n, VELODYNE_TOPIC, 1); + message_filters::Subscriber rt_sub(n, "lidar_camera_calibration_rt", 1); + + typedef sync_policies::ApproximateTime MySyncPolicy; + Synchronizer sync(MySyncPolicy(10), cloud_sub, rt_sub); + sync.registerCallback(boost::bind(&callback_noCam, _1, _2)); + + ros::spin(); + } + + return EXIT_SUCCESS; +} diff --git a/flow copy.py b/flow copy.py new file mode 100644 index 0000000..ae257cb --- /dev/null +++ b/flow copy.py @@ -0,0 +1,39 @@ +import open3d as o3d +import numpy as np +import cv2 +import matplotlib.pyplot as plt + +# 创建一些点云数据 +pcd = o3d.geometry.PointCloud() +pcd.points = o3d.utility.Vector3dVector(np.random.rand(100, 3)) + +# 设置相机参数 +fx = 525.0 # 焦距 +fy = 525.0 +cx = 319.5 # 主点 +cy = 239.5 +depth_scale = 1000.0 # 深度缩放因子 +intrinsic = np.identity(3) +intrinsic[0, 0] = fx +intrinsic[0, 2] = cx +intrinsic[1, 1] = fy +intrinsic[1, 2] = cy + +# 将点云投影到图像平面 +pcd.transform(intrinsic) + +# 转换为OpenCV的图像格式 +points = np.asarray(pcd.points) +depth = points[:, 2] +depth[depth < 0] = 0 # 设置负的深度值为0 +depth /= depth_scale # 归一化深度 +h, w = int(cy + 1), int(cx + 1) +image = np.zeros((h, w, 3), dtype=np.uint8) +for i in range(points.shape[0]): + x, y, z = points[i] + if 0 <= int(y) < h and 0 <= int(x) < w: + image[int(y), int(x)] = (int(255 * (1 - z / depth[i])), int(255 * (1 - z / depth[i])), int(255 * (1 - z / depth[i]))) + +# 显示结果 +plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) +plt.show() \ No newline at end of file diff --git a/flow_edge.py b/flow_edge.py new file mode 100644 index 0000000..93e8b43 --- /dev/null +++ b/flow_edge.py @@ -0,0 +1,354 @@ +# -- coding: utf-8 -- +import numpy as np +import cv2 +import math + + +def _sobel(image): + ''' + _sobel + ''' + if image.ndim > 2: + image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + # todo 增加几个参数 http://blog.csdn.net/sunny2038/article/details/9170013 + _sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=1) + _sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=1) + + _sobelx = np.uint8(np.absolute(_sobelx)) + _sobely = np.uint8(np.absolute(_sobely)) + _sobelcombine = cv2.bitwise_or(_sobelx,_sobely) + return _sobelcombine + +# ################################################################## + +# # 展平 +# img_flat = _im_gray.reshape((_im_gray.shape[0] * _im_gray.shape[1], 1)) + + +# img_flat = np.float32(img_flat) + +# # 迭代参数 +# criteria = (cv2.TERM_CRITERIA_EPS + cv2.TermCriteria_MAX_ITER, 20, 0.0) +# flags = cv2.KMEANS_RANDOM_CENTERS + +# # 进行聚类 +# compactness, labels, centers = cv2.kmeans(img_flat, 20, None, criteria, 10, flags) + +# segmented_img = labels.reshape(_im_gray.shape) +# _im_gray = np.uint8(segmented_img) +# _im_gray = cv2.equalizeHist(_im_gray) + +# cv2.imshow("_im2", im) +# cv2.waitKey(0) +# ################################################################## + +def _findContours(image): + ''' + _findContours + http://blog.csdn.net/mokeding/article/details/20153325 + ''' + contours, _ = cv2.findContours(image.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) + return sorted(contours, key=cv2.contourArea, reverse=True) + +def _drawContours(image, contours, cidx=-1): + ''' + _drawContours + ''' + image_contour = cv2.drawContours(image, contours, -1, (255, 255, 255), 1) + return image_contour + +import time +class CropLayer(object): + def __init__(self, params, blobs): + self.xstart = 0 + self.xend = 0 + self.ystart = 0 + self.yend = 0 + # Our layer receives two inputs. We need to crop the first input blob + # to match a shape of the second one (keeping batch size and number of channels) + def getMemoryShapes(self, inputs): + inputShape, targetShape = inputs[0], inputs[1] + batchSize, numChannels = inputShape[0], inputShape[1] + height, width = targetShape[2], targetShape[3] + + self.ystart = int((inputShape[2] - targetShape[2]) / 2) + self.xstart = int((inputShape[3] - targetShape[3]) / 2) + self.yend = self.ystart + height + self.xend = self.xstart + width + + return [[batchSize, numChannels, height, width]] + + def forward(self, inputs): + return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]] + +class Arguments: + def __init__(self): + self.description = "" + self.input = "./images/x.png" + self.prototxt = "./deploy.prototxt" + self.caffemodel = "./hed_pretrained_bsds.caffemodel" + self.width = 360 + self.height = 115 + self.savefile = "./1.jpg" + +def dnn(im): + args = Arguments() + args.width = im.shape[1] + args.height = im.shape[0] + args.input = im + # Load the model. + net = cv2.dnn.readNetFromCaffe(args.prototxt, args.caffemodel) + # 设置网络运行参数 + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) # 或者GPU + # net.setPreferableTarget(cv2.dnn.DNN_TARGET_OPENCL) + cv2.dnn_registerLayer('Crop', CropLayer) + kWinName = 'Holistically-Nested_Edge_Detection' + mean_value = cv2.mean(im) + inp = cv2.dnn.blobFromImage(im, scalefactor=1.5, size=(args.width, args.height), + mean=mean_value, + swapRB=True, crop=True) + net.setInput(inp) + # edges = cv2.Canny(frame,args.width,args.height) + # edges = cv2.Canny(frame,frame.shape[1],frame.shape[0]) + out = net.forward() + out = out[0, 0] + _im_gray = cv2.resize(out, (im.shape[1], im.shape[0])) + _im_gray = 255 * _im_gray + # print(out) + _im_gray = _im_gray.astype(np.uint8) + _im_gray = cv2.resize(_im_gray, (640, 480)) + cv2.imshow('Input', _im_gray) + cv2.waitKey(0) + +def Scharr(image): + ''' + _sobel + ''' + if image.ndim > 2: + image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + # todo 增加几个参数 http://blog.csdn.net/sunny2038/article/details/9170013 + _scharrx = cv2.Scharr(image, cv2.CV_8U, dx=1, dy=0, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT) + _scharry = cv2.Scharr(image, cv2.CV_8U, dx=0, dy=1, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT) + + _scharrx = np.uint8(np.absolute(_scharrx)) + _scharry = np.uint8(np.absolute(_scharry)) + _sobelcombine = cv2.bitwise_or(_scharrx,_scharry) + + return _sobelcombine + +def cal_conners_edges_sort(im, thresh_hold = 80, minLineLength = 400): + + _im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) + # for test + _im_gray = cv2.GaussianBlur(_im_gray, (5, 5), 0) + _im_edge_sobel = _sobel(_im_gray) + # _im_edge_sobel = Scharr(_im_gray) + + _, _im_thresh = cv2.threshold(_im_edge_sobel, 5, 255, cv2.THRESH_BINARY) + + cnts = _findContours(_im_thresh) + for contour in cnts: + if cv2.contourArea(contour) > 500: + # 计算轮廓的边界框 + x, y, w, h = cv2.boundingRect(contour) + # 在原图上绘制矩形 + cv2.rectangle(_im, (x, y), (x + w, y + h), (0, 255, 0), 2) + cv2.imshow("_im2", _im_thresh) + cv2.waitKey(0) + + _lines = cv2.HoughLinesP(_im_thresh, 1, np.pi / 180, thresh_hold, minLineLength=minLineLength, maxLineGap=120) + + # for test + for _line in _lines: + x1,y1,x2,y2 = _line[0] + cv2.line(_im, (x1,y1), (x2,y2), (0,255,0), 1) + # for test + cv2.imshow("_im", _im) + cv2.imshow("_im2", _im_edge_sobel) + cv2.waitKey(0) + + # print(len(_lines)) + _line4 = [] + for _line in _lines: + x1,y1,x2,y2 = _line[0] + if x2 == x1: x2 += 0.001 + theta = np.arctan((y2 - y1) / (x2 - x1)) * (180 / math.pi) + x2 = int(x2) + r = math.sqrt(pow((y2 - y1), 2) + pow((x2 - x1), 2)) + # 计算直线的斜率(如果 1 ≠ 2) + if x2 == x1: x2 += 0.001 # 如果x2 == x1,会出现分母为0 + m = (y2 - y1) / (x2 - x1) + x2 = int(x2) + A, B, C = m, -1, y1 - m * x1 + brepeat = False + for i in range(len(_line4)): + if abs(abs(theta) - abs(_line4[i][4])) < 30: # 20° + cx, cy = (_line4[i][2] + _line4[i][0]) / 2, (_line4[i][3] + _line4[i][1]) / 2 + d = abs(A * cx + B * cy + C) / math.sqrt(pow(A, 2) + pow(B, 2)) + r_max = max(_line4[i][5], r) + if d < r_max / 3: + brepeat = True + if (r > _line4[i][5]) : + _line4[i] = [x1,y1,x2,y2, theta, r] + if not brepeat : + _line4.append([x1,y1,x2,y2, theta, r]) + # print(x1,y1,x2,y2, theta, r) + + # # for test + for x1,y1,x2,y2, theta, r in _line4: + cv2.line(_im, (x1,y1), (x2,y2), (0,255,0), 10) + print(x1,y1,x2,y2, theta, r) + _im_samll = cv2.resize(_im, (500, 500)) + # for test + cv2.imshow("_im", _im_samll) + cv2.waitKey(0) + + # 4条边排序 + # assert(len(_line4) == 4) + _line4_sort = [] + Ax, Bx, Cx = 1, 0, 0 + Ay, By, Cy = 0, 1, 0 + min_dx, max_dx, min_dy, max_dy = 10000, 0, 10000, 0 + min_dx_idx, max_dx_id, min_dy_id, max_dy_id = -1, -1, -1, -1 + for i in range(len(_line4)): + cx, cy = (_line4[i][2] + _line4[i][0]) / 2, (_line4[i][3] + _line4[i][1]) / 2 + dx = abs(Ay * cx + By * cy + Cy) / math.sqrt(pow(Ay, 2) + pow(By, 2)) + dy = abs(Ax * cx + Bx * cy + Cx) / math.sqrt(pow(Ax, 2) + pow(Bx, 2)) + if dx < min_dx: + min_dx = dx + min_dx_idx = i + if dx > max_dx: + max_dx = dx + max_dx_id = i + if dy < min_dy: + min_dy = dy + min_dy_id = i + if dy > max_dy: + max_dy = dy + max_dy_id = i + _line4_sort = _line4[min_dx_idx], _line4[max_dy_id], _line4[max_dx_id], _line4[min_dy_id] + print(_line4_sort) + + # # for test + for x1,y1,x2,y2, theta, r in _line4_sort: + cv2.line(_im, (x1,y1), (x2,y2), (0,0,255), 10) + print(x1,y1,x2,y2, theta, r) + _im_samll = cv2.resize(_im, (500, 500)) + # for test + cv2.imshow("_im", _im_samll) + cv2.waitKey(0) + + # 找四个交点 + _conners4_sort = [0,0,0,0] + for i in range(len(_line4_sort)): + x1, y1, x2, y2, _, _ = _line4_sort[i] + x1_next, y1_next, x2_next, y2_next, _, _ = _line4_sort[(i + 1) % 4] + + # 检查是否为垂直线 + # if x2 - x1 == 0: + # A, B, C = 1, 0, -x1 # 垂直线 + # else: + if x2 == x1: x2 += 0.00001 # 如果x2 == x1,会出现分母为0 + m = (y2 - y1) / (x2 - x1) + x2 = int(x2) + A, B, C = m, -1, y1 - m * x1 + + # if x2_next - x1_next == 0: + # A_next, B_next, C_next = 1, 0, -x1_next # 垂直线 + # else: + if x2_next == x1_next: x2_next += 0.001 # 如果x2 == x1,会出现分母为0 + m_next = (y2_next - y1_next) / (x2_next - x1_next) + x2_next = int(x2_next) + A_next, B_next, C_next = m_next, -1, y1_next - m_next * x1_next + + # 检查是否平行 + if A * B_next == A_next * B: + continue # 跳过平行的线段 + + # 计算交点 + x_p = (B_next * C - B * C_next) / (A_next * B - A * B_next) + y_p = (A * x_p + C) / - B + + # 确保交点在图像范围内 + if 0 <= int(x_p) < _im.shape[1] and 0 <= int(y_p) < _im.shape[0]: + _conners4_sort[(i + 1) % 4] = [int(x_p), int(y_p)] + + assert(len(_conners4_sort) == 4) + + return _conners4_sort, _line4_sort + + +def cal_sub_conners(im, conners4_sort, line4_sort, sub_pixels=100): + assert(len(conners4_sort)==4) + + for i in range(4): + cx, cy = conners4_sort[i] + x = int(cx - sub_pixels / 2) + if x < 0: x = 0 + y = int(cy - sub_pixels / 2) + if y < 0: y = 0 + w = sub_pixels + h = sub_pixels + + roi = im[y:y+h, x:x+w].copy() + roi_gray = cv2.cvtColor(roi, cv2.COLOR_RGB2GRAY) + roi_gray = cv2.Canny(roi_gray, threshold1=100, threshold2=200) + _tmp_corners = cv2.goodFeaturesToTrack(roi_gray, maxCorners=100, qualityLevel=0.001, minDistance=2) + + roi_cx = cx - x + roi_cy = cy - y + min = 10000 + tar_conner = [] + + for conner in _tmp_corners: + conner = conner.tolist()[0] + d = math.sqrt(pow((conner[0] - roi_cx), 2) + pow((conner[1] - roi_cy), 2)) + if d < min : + min = d + tar_conner = [conner[0], conner[1]] + cv2.circle(_im, (int(conner[0]+x), int(conner[1]+y)), 1, (255,0,0), -1) + cv2.circle(roi, (int(roi_cx), int(roi_cy)), 2, (0,0,255), -1) + cv2.circle(roi, (int(tar_conner[0]), int(tar_conner[1])), 2, (255,0,0), -1) + cv2.circle(_im, (int(roi_cx+x), int(roi_cy+y)), 2, (0,0,255), -1) + cv2.circle(_im, (int(tar_conner[0]+x), int(tar_conner[1]+y)), 2, (255,0,0), -1) + # corners = np.int0(corners) + + # for test + cv2.imshow("roi", roi) + cv2.waitKey(0) + +if __name__ == '__main__': + + _im = cv2.imread("./3_roi_image.png") + + edge = np.sqrt(pow((0.323 - 0.32222), 2) + + pow((1.32- 14.2), 2) + + pow((41 - 32.1), 2)) + cv2.putText(_im, str(edge)[:6], (int((23+23)/2), int((23+32)/2)), \ + cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) + + + _gray = cv2.cvtColor(_im, cv2.COLOR_BGR2GRAY) + # 测试自适应阈值分割 + # thresh = cv2.adaptiveThreshold(_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) + # t, result_img = cv2.threshold(_gray, 5, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) + # print(t) + # cv2.imshow("thresh", result_img) + # cv2.waitKey(0) + + + _conners4_sort, _line4_sort = cal_conners_edges_sort(_im) + + # cal_sub_conners(_im, _conners4_sort, _line4_sort) + + for i in range(4): + x1, y1, x2, y2, _, _ = _line4_sort[i] + x_p, y_p = _conners4_sort[i] + # # for test + cv2.circle(_im, (int(x_p), int(y_p)), 2, (0,0,255), -1) + cv2.line(_im, (x1,y1), (x2,y2), (0,255,0), 1) + + cv2.imwrite("./2_roi_imagerest.png", _im) + cv2.imshow("im_edge", _im) + cv2.waitKey(0) \ No newline at end of file diff --git a/flow_homo.py b/flow_homo.py new file mode 100644 index 0000000..0746818 --- /dev/null +++ b/flow_homo.py @@ -0,0 +1,223 @@ +# -- coding: utf-8 -- +import numpy as np +import cv2 +import math +import open3d as o3d + + +class rect_roi: + def __init__(self, x:int, y:int, w:int, h:int): + self.x = x + self.y = y + self.w = w + self.h = h + + +class obj_info: + def __init__(self, name:str, id:str, points_2d_to_3d:cv2.Mat, bim=None): + self.name = name + self.id = id + self.rect_points_2d_to_3d = points_2d_to_3d + self.bim = bim + self.edges = [] + self.orgin_pt = [0.0, 0.0] + self.centor_pt = [0.0, 0.0] + + +def _api_cal_homography(_3d_points, _2d_points): + ransacReprojThreshold = 5.0 # Homography: 该值越小,精度越高,对时间没有影像 + # 查找单应矩阵 + # 修改第三个参数 1.0 -> 5.0 + # 利用基于RANSAC的鲁棒算法选择最优的四组配对点,再计算转换矩阵H(3*3)并返回,以便于反向投影错误率达到最小 + # ransacReprojThreshold 设置为 1.0,精度最高 + # H, mask = cv2.findHomography(np.array(src_points), np.array(dst_points), cv2.RANSAC, ransacReprojThreshold, maxIters=1500, confidence=0.998) ## 修改 1.0 -> 5.0 + pts_hom = [] + for i in range(len(_2d_points)): + pt = _2d_points[i] + x,y = pt[0], pt[1] + pts_hom.append([x*1.0, y*1.0, 1.0]) + H, _ = cv2.findHomography(np.array(_3d_points), np.array(pts_hom), cv2.RANSAC, ransacReprojThreshold) ## 修改 1.0 -> 5.0 + print(H) + return H + + +# 暂时不需要 +def _api_get_fake_roi_data(): + return [[]] + + +def _api_get_obj_2d_roi(im, rois): + _roi_im_list = [] + for i in range(len(rois)): + roi = rois[i] + _roi_im = im[roi.y:roi.y+roi.h, roi.x:roi.x+roi.w] + _roi_im_list.append(_roi_im) + return _roi_im_list + + +def __get_small_conners(conners, offset): + # pts = np.array([[conners[0][0] - offset, conners[0][1] - offset], + # [conners[1][0] - offset, conners[1][1] - offset], + # [conners[2][0] - offset, conners[2][1] - offset], + # [conners[3][0] - offset, conners[3][1] - offset]], + # np.int32) + pts = [[conners[0][0] + offset, conners[0][1]], + [conners[1][0] - offset, conners[1][1] + offset], + [conners[2][0] - offset, conners[2][1]], + [conners[3][0], conners[3][1] - offset]] + return pts + # cv2.polylines(img, [pts], isClosed=True, color=(0, 255, 0), thickness=2) + + +def _api_get_sub_rois_with_conners(conners): + _conners = [] + _conners.append(__get_small_conners(conners, 200)) + return _conners + + +def _api_get_obj_2d_to_3d_pts(im_2d_to_3d:cv2.Mat, sub_rois_in_conners): + in_rect_2d_to_3d_pts = [] + in_rect_2d_pts = [] + in_rect_3d_pts = [] + + for i in range(len(sub_rois_in_conners)): + _sub_rois = sub_rois_in_conners[i] + _sub_rois_mask = np.zeros_like(im_2d_to_3d) + + # for test + # normalized_image = np.uint8(_sub_rois_mask) + # _sub_rois_mask = cv2.normalize(normalized_image, None, 0, 255, cv2.NORM_MINMAX) + + _sub_rois_mask = cv2.fillPoly(_sub_rois_mask, [np.array(_sub_rois)], color=(255, 255, 255)) + im_2d_to_3d_roi = cv2.bitwise_and(im_2d_to_3d, _sub_rois_mask) + # im_2d_to_3d_roi = cv2.resize(im_2d_to_3d_roi, (int(934*1.5), int(700*1.5)), interpolation=cv2.INTER_LINEAR) + # cv2.imshow("1", im_2d_to_3d_roi) + # cv2.waitKey(0) + + normalized_image = np.uint8(im_2d_to_3d_roi) + normalized_image = cv2.cvtColor(normalized_image, cv2.COLOR_BGR2GRAY) + _2d_pts = cv2.findNonZero(normalized_image) + + for i in range(len(_2d_pts)): + _2d_pt = _2d_pts[i][0].tolist() + if i % 20 == 0: + in_rect_2d_pts.append(_2d_pt) + in_rect_3d_pts.append([im_2d_to_3d[_2d_pt[1],_2d_pt[0]][0], + im_2d_to_3d[_2d_pt[1],_2d_pt[0]][1], + im_2d_to_3d[_2d_pt[1],_2d_pt[0]][2]]) + return in_rect_2d_to_3d_pts, in_rect_2d_pts, in_rect_3d_pts + + +# _conners:返回预埋件角点在原图中的坐标(非在roi图中的坐标) +def _api_get_edges_and_conners(roi_im, roi_rect, fake=True): + _edges = [] + _conners = [] + rst = "ok" # 如果识别改区域不是预埋件区域,则返回错误 + if fake: + # 人工定好4个角点 + _conners = [[465,436],[615,260],[783,405],[630,581]] + for i in range(4): + _conners[i] = [int(_conners[i][0]*9344/934/1.5), int(_conners[i][1]*7000/700/1.5)] + return rst, _edges, _conners + + +# 在未来使用roi_im, roi_rect进行优化 +# def _api_cal_3d_edge_scale(roi_im, roi_rect, conners, H): +def _api_cal_3d_edge_scale(conners, H, _2pts, _3pts): + + _edges = [] + + _conners_3d = [] + + if len(conners) != 4: + assert("_cal_scale: len(conners) is not 4") + + # 计算点云的拟合平面 + _3pts_cloud = o3d.geometry.PointCloud() + _3pts_cloud.points = o3d.utility.Vector3dVector(_3pts) + [A,B,C,D], inliers = _3pts_cloud.segment_plane(distance_threshold=0.01, ransac_n=3, num_iterations=1500) + # [a,b,c,d]= plane model + + H_inv = np.linalg.inv(H) + for i in range(4): + conner = conners[i] + x, y = conner[0], conner[1] + pts_hom = np.array([x, y, 1]) + # pts_hom = cv2.convertPointsToHomogeneous(pts) + pts_3d = np.dot(H_inv, pts_hom.T) + pts_3d = pts_3d/pts_3d[2] + + # 求线与平面的交点 + t = -D / (A * pts_3d[0] + B * pts_3d[1] + C * pts_3d[2]) + pts_3d = np.array([t * pts_3d[0], t * pts_3d[1], t * pts_3d[2]]) + + _conners_3d.append(list(pts_3d)) + + for i in range(4): + _conner_3d = _conners_3d[i] + _conner_3d_next = _conners_3d[(i+1)%4] + _edge = math.sqrt(pow((_conner_3d[0] - _conner_3d_next[0]), 2) + + pow((_conner_3d[1] - _conner_3d_next[1]), 2) + + pow((_conner_3d[2] - _conner_3d_next[2]), 2)) + _edges.append(_edge) + return _edges + + +# 主处理流程 +# for test: roi_rects = [[0,0,0,0]] +def api_cal_info(im, im_2d_to_3d, roi_rects): + + print("api_cal_info start!") + + _obj_info_list = [] + + # for test,人工定义roi区域 + # roi_rects = _api_get_fake_roi_data() + + # 图像剪切到一个个roi图像 + _roi_im_list = _api_get_obj_2d_roi(im, roi_rects) + + # 遍历所有预埋件的子区域图像,这里可以分线程跑,提升效率 + for i in range(len(_roi_im_list)): + + # 获取单个预埋件图像 + _roi_im = _roi_im_list[i] + + # 在单个预埋件图像中计算区域内预埋件边缘和角点 + _rst, _, _2d_conners = _api_get_edges_and_conners(_roi_im, roi_rects[i]) + print("api_cal_info _2d_conners ==> ") + print(_2d_conners) + # assert(_rst != "ok") + + # 计算预埋件内部用于检测 H矩阵的2d 3d区域 + # _sub_rois_in_conners:全局坐标系 + _sub_rois_in_conners = _api_get_sub_rois_with_conners(_2d_conners) + + # 挑选合适的预埋件区域内2d和3d点映射,挑选算法需要设计和优化 + _, _2pts, _3pts = _api_get_obj_2d_to_3d_pts(im_2d_to_3d, _sub_rois_in_conners) + + # 计算H矩阵 + H = _api_cal_homography(_3pts, _2pts) + + # 通过角点和边缘计算尺寸 + # _2d_conners:为全局坐标,不是roi坐标 + # _edgs_scale = _api_cal_3d_edge_scale(_roi_im, roi_rects[i], _2d_conners, H) + _edgs_scale = _api_cal_3d_edge_scale(_2d_conners, H, _2pts, _3pts) + + print(_edgs_scale) + + # _obj_info = obj_info() + + # _obj_info_list.append(_obj_info) + + print("api_cal_info end!") + return _obj_info_list + + +if __name__ == '__main__': + pass + + # _edge = math.sqrt(pow(-0.19919018 - 0.271936, 2) + # + pow(-0.48743263 - -0.32997242, 2) + # + pow(3.513779 - 3.527755, 2)) + # print(_edge) \ No newline at end of file diff --git a/flow_main.py b/flow_main.py new file mode 100644 index 0000000..6574714 --- /dev/null +++ b/flow_main.py @@ -0,0 +1,384 @@ +# -- coding: utf-8 -- +from ctypes import * +import cv2 # 4.9.0 +print(cv2.__version__) # 4.9.0 +import numpy as np +print(np.__version__) # 1.24.4 +# import pyc # https://github.com/PointCloudLibrary/pcl/releases/tag/pcl-1.8.1 +import open3d as o3d +print(o3d.__version__) # 0.18.0 +import convert +import copy +import math +import flow_homo +import time + +WIDTH = 9344 +HEIGH = 7000 +step = 40 + +# 相机内参矩阵,这里假设为简单的相机参数 +w = WIDTH +h = HEIGH + +fx = 11241.983 +fy = 11244.0599 +cx = 4553.03821 +cy = 3516.9118 + +k1 = -0.04052072 +k2 = 0.22211572 +p1 = 0.00042405 +p2 = -0.00367346 +k3 = -0.15639485 + +###################################################1:不带畸变,不带激光雷达补偿标定 +# R_mat_avg = np.asarray([ +# [0.999835, -0.0162967, 0.00799612], +# [0.0164626, 0.999641, -0.0211427], +# [-0.00764869, 0.0212709, 0.999744]]) + +# T_vector = np.array([0.115324, 0.0797254, 0.00324282]) + +# R_T_mat_avg = np.asarray([ +# [0.999835, -0.0162967, 0.00799612, 0.115324], +# [0.0164626, 0.999641, -0.0211427, 0.0797254], +# [-0.00764869, 0.0212709, 0.999744, 0.00324282], +# [0.0, 0.0, 0.0, 1.0]]) + +# R_mat_fin = np.asarray([ +# [0.0079925, -0.999835, 0.0163003], +# [-0.0211428, -0.0164661, -0.999641], +# [0.999745, 0.007645, -0.0212709]]) + +# y,p,r = 1.93222, -1.5934, -0.345034 + +###################################################2:带畸变,带激光雷达补偿标定 +R_mat_avg = np.asarray([ + [0.999812, -0.0178348, 0.00765956], + [0.0179972, 0.999603, -0.021687], + [-0.00726974, 0.0218207, 0.999735]]) + +T_vector = np.array([0.109253, 0.0710213, 0.0175978]) + +R_T_mat_avg = np.asarray([ + [0.999812, -0.0178348, 0.00765956, 0.109253], + [0.0179972, 0.999603, -0.021687, 0.0710213], + [-0.00726974, 0.0218207, 0.999735, 0.0175978], + [0.0, 0.0, 0.0, 1.0]]) + +R_mat_fin = np.asarray([ + [0.00765987, -0.999812, 0.0178345], + [-0.021687, -0.0179969, -0.999603], + [0.999735, 0.00727006, -0.0218207]]) + +y,p,r = 1.91032, -1.5938, -0.321605 + +# y,p,r = 1.57086, -1.57086, -0.0 + +###################################################3:不带畸变,不带激光雷达补偿标定 +# R_mat_avg = np.asarray([ +# [0.999849, -0.048776, 0.00900869], +# [0.014993, 0.999805, -0.0128836], +# [-0.00881525, 0.0130167, 0.999876]]) + +# T_vector = np.array([0.120222, 0.0442982, 0.00136219]) + +# R_T_mat_avg = np.asarray([ +# [0.999849, -0.048776, 0.00900869, 0.120222], +# [0.014993, 0.999805, -0.0128836, 0.0442982], +# [-0.00881525, 0.0130167, 0.999876, 0.00136219], +# [0.0, 0.0, 0.0, 1.0]]) + +# R_mat_fin = np.asarray([ +# [0.009009, -0.999849, 0.0148772], +# [0.0128836, -0.0149927, -0.999805], +# [0.999876, 0.00881577, -0.0130167]]) + +# y,p,r = 2.18103, -1.58652, -0.595295 + + +# x,y,z +def _eulerAnglesToRotationMatrix(theta) : + R_x = np.array([[1, 0, 0 ], + [0, math.cos(theta[0]), -math.sin(theta[0]) ], + [0, math.sin(theta[0]), math.cos(theta[0]) ] + ]) + R_y = np.array([[math.cos(theta[1]), 0, math.sin(theta[1]) ], + [0, 1, 0 ], + [-math.sin(theta[1]), 0, math.cos(theta[1]) ] + ]) + R_z = np.array([[math.cos(theta[2]), -math.sin(theta[2]), 0], + [math.sin(theta[2]), math.cos(theta[2]), 0], + [0, 0, 1] + ]) + R = np.dot(R_z, np.dot( R_y, R_x )) + return R + +def cal_project_matrix(): + # 假设camera_matrix和dist_coeffs是已知的摄像机内参和畸变参数 + camera_matrix = np.array([[fx, 0, cx], + [0, fy, cy], + [0, 0, 1]]) + + camera_matrix = np.array([[11550.4192, 0.00000000, 4672.28001], + [0.00000000, 11546.8773, 3.49929103], + [0.00000000e+00, 0.00000000, 1.00000000]]) + + + dist_coeffs = np.array([k1, k2, p1, p2, k3]) # 这里k1, k2, p1, p2, k3是畸变系数 + dist_coeffs = np.array([-0.0198130402, 0.0446498902, 0.000332909792, -0.000424586371, 0.371045970]) + # src_size是原始图像的大小 + src_size = (w, h) + + # 计算新的摄像机矩阵 + new_camera_matrix = cv2.getOptimalNewCameraMatrix(camera_matrix, dist_coeffs, src_size, alpha=0) + print(new_camera_matrix) + # print(new_camera_matrix) + return new_camera_matrix + + +def cal_rectification_matrix(): + pass + + +# 定义获取点云深度最大最小值 +def get_pcd_depth_range(pts_3d): + # 初始化最小值和最大值为第一个点的x坐标 + min_x = 0 + max_x = 0 + + # 遍历所有点,更新最小值和最大值 + for point_3d in pts_3d: + x = point_3d[0] + if x < min_x: + min_x = x + elif x > max_x: + max_x = x + + return max_x, min_x + + +# 定义函数根据深度获取颜色 +def get_color(cur_depth, max_depth, min_depth): + scale = (max_depth - min_depth) / 10 + if cur_depth < min_depth: + return (0, 0, 255) # 返回蓝色 + elif cur_depth < min_depth + scale: + green = int((cur_depth - min_depth) / scale * 255) + return (0, green, 255) # 返回蓝到黄的渐变色 + elif cur_depth < min_depth + scale * 2: + red = int((cur_depth - min_depth - scale) / scale * 255) + return (0, 255, 255 - red) # 返回黄到红的渐变色 + elif cur_depth < min_depth + scale * 4: + blue = int((cur_depth - min_depth - scale * 2) / scale * 255) + return (blue, 255, 0) # 返回红到绿的渐变色 + elif cur_depth < min_depth + scale * 7: + green = int((cur_depth - min_depth - scale * 4) / scale * 255) + return (255, 255 - green, 0) # 返回绿到黄的渐变色 + elif cur_depth < min_depth + scale * 10: + blue = int((cur_depth - min_depth - scale * 7) / scale * 255) + return (255, 0, blue) # 返回黄到蓝的渐变色 + else: + return (255, 0, 255) # 返回紫色 + + +def undistort(distorted_img): + camera_matrix = np.array([[fx, 0, cx], + [0, fy, cy], + [0, 0, 1]]) + dist_coeffs = np.array([k1, k2, p1, p2, k3]) # 畸变系数 + + # 矫正畸变 + undistorted_img = cv2.undistort(distorted_img, camera_matrix, dist_coeffs, None, camera_matrix) + # cv2.imwrite("distorted_img.png", undistorted_img) + # undistorted_img = cv2.imread("distorted_img.png") + # cv2.imshow("1", undistorted_img) + # cv2.waitKey(0) + return undistorted_img + + +def _origin_project(pcd): + # 删除人才 + pts_3d = [] + for point_3d in np.asarray(pcd.points): + #筛选x,y,z坐标 + if -2.5 < point_3d[0] < 2.5 and -2.5 < point_3d[1] < 2.5 and point_3d[2] < 3.7: + pts_3d.append((point_3d[0], point_3d[1], point_3d[2])) + # pts_3d = np.asarray(pcd.points).tolist() + + # 3D投影2D + R_mat = pcd.get_rotation_matrix_from_xyz((0.0, 0.0, 0.0)) + rvec, _ = cv2.Rodrigues(R_mat) + tvec = np.float64([0.0, 0.0, 0.0]) + camera_matrix = np.float64([[fx, 0, cx], + [0, fy, cy], + [0, 0, 1]]) + distCoeffs = np.float64([k1, k2, p1, p2, k3]) + pts_2d, _ = cv2.projectPoints(np.array(pts_3d), rvec, tvec, camera_matrix, distCoeffs) + + # 2D图像绘制 + max_depth, min_depth = get_pcd_depth_range(pts_3d) + image_project = np.zeros((h,w,3), dtype=np.uint8) + for i, point_2d in enumerate(pts_2d): + x, y = point_2d.ravel() + x, y = int(x), int(y) + if 0 <= x < image_project.shape[1] and 0 <= y < image_project.shape[0]: + cur_depth = pts_3d[i][2] + color = get_color(cur_depth, max_depth, min_depth) # 根据深度获取颜色 + image_project[y, x] = color + + image_project = cv2.resize(image_project, (int(934), int(700)), interpolation=cv2.INTER_LINEAR) + # cv2.imshow("project image", image_project) + # cv2.waitKey(0) + +image_project = None +def _lidar2camera_project(pcd): + global image_project + # Extract 3D points within a certain range + kk = 0.02 + pts_3d_tmp = [] + for point_3d in np.asarray(pcd.points): + # r = math.sqrt(pow(point_3d[0], 2) + pow(point_3d[1], 2) + pow(point_3d[2], 2)) + # point_3d[0] = point_3d[0] + point_3d[0] / r * kk + # point_3d[1] = point_3d[1] + point_3d[1] / r * kk + # point_3d[2] = point_3d[2] + point_3d[2] / r * kk + point_3d[2] -= 0.02 + pts_3d_tmp.append((point_3d[0], point_3d[1], point_3d[2])) + + pts_3d = [] + # pts_3d = np.asarray(pcd.points).tolist() + for point_3d in np.asarray(pts_3d_tmp): + if -2.5 < point_3d[0] < 2.5 and -2.5 < point_3d[1] < 2.5 and point_3d[2] < 2.8 : #筛选x,y,z坐标 + pts_3d.append((point_3d[0], point_3d[1], point_3d[2])) + + pcd1 = o3d.geometry.PointCloud() + for pts in pts_3d: + pcd1.points.append(pts) + o3d.visualization.draw_geometries([pcd1], mesh_show_wireframe=True) + + # R_mat = cloud_load.get_rotation_matrix_from_xyz((0.0, 0.0, 0.0)) + # rvec, _ = cv2.Rodrigues(R_mat) + rvec = np.array([np.array([0.]), np.array([0.]), np.array([0.])]) + tvec = np.float64([0.0, 0.0, 0.0]) + camera_matrix = np.float64([[fx, 0, cx], + [0, fy, cy], + [0, 0, 1]]) + # distCoeffs = np.float64([k1, k2, p1, p2, k3]) + distCoeffs = np.float64([0.0, 0.0, 0.0, 0.0, 0.0]) + pts_2d, _ = cv2.projectPoints(np.array(pts_3d), rvec, tvec, camera_matrix, distCoeffs) + + image_project_zero = np.zeros((h,w,3), dtype=np.uint8) + image_project_red = np.zeros((h,w,3), dtype=np.uint8) + image_project_red[:] = (0,0,255) + # image_project = cv2.imread("./caowei/output.png") + image_project = undistort(image_project) + image_project_2d_to_3d = np.zeros((h,w,3), dtype=np.float64) + # image_project[:] = (255,255,255) + + max_depth, min_depth = get_pcd_depth_range(pts_3d) + # sub_depth = max_depth - min_depth + for i, point_2d in enumerate(pts_2d): + x, y = point_2d.ravel() + x, y = int(x), int(y) + if 0 <= x < image_project.shape[1] and 0 <= y < image_project.shape[0]: + cur_depth = pts_3d[i][2] # 获取当前点的深度 + color = get_color(cur_depth, max_depth, min_depth) # 根据深度获取颜色 + # gray = int(cur_depth/sub_depth) + color = (255,255,255) + image_project_zero[y, x] = color # 设置点云的颜色 + image_project_2d_to_3d[y, x][0] = pts_3d[i][0] + image_project_2d_to_3d[y, x][1] = pts_3d[i][1] + image_project_2d_to_3d[y, x][2] = pts_3d[i][2] + + # for test + rect_roi = flow_homo.rect_roi(0,0,0,0) + flow_homo.api_cal_info(image_project, image_project_2d_to_3d, [rect_roi]) + + image_project_zero = cv2.cvtColor(image_project_zero, cv2.COLOR_RGB2GRAY) + _, mask = cv2.threshold(image_project_zero, 1,255, cv2.THRESH_BINARY) + kernel = np.ones((11,11), np.uint8) + mask = cv2.dilate(mask, kernel, iterations=1) + # cv2.imshow("project image", mask) + image_project = cv2.bitwise_and(image_project_red, image_project, image_project, mask) + + image_project = cv2.resize(image_project, (int(934*1.5), int(700*1.5)), interpolation=cv2.INTER_LINEAR) + # cv2.imwrite("./project.jpg", image_project) + # cv2.imshow("project image", image_project) + # cv2.waitKey(0) + + +if __name__ == '__main__': + cal_project_matrix() + + + + image_project = cv2.imread("./caowei/output.png") + if image_project is None: + print("image_project is None!") + exit() + # cal_project_matrix() + + # 读取PLY文件 + ply_file_path = './output.ply' + cloud_load = o3d.io.read_point_cloud(ply_file_path) + + + + start_time = time.time() + pts_3d = np.asarray(cloud_load.points).tolist() + # 打印坐标点 + # xyz_load = np.asarray(cloud_load.points) + # print(len(xyz_load)) + # print(xyz_load) + + # 指定外参:旋转矩阵和平移向量 -0.271002 1.81304 -1.75592 + Rz = cloud_load.get_rotation_matrix_from_xyz((0, 0, y)) + Ry = cloud_load.get_rotation_matrix_from_xyz((0, p, 0)) + Rx = cloud_load.get_rotation_matrix_from_xyz((r, 0, 0)) + RR = _eulerAnglesToRotationMatrix([1.5707963267948966,-1.5707963267948966,0.0]) + print(np.pi/2) + print(RR) + + # ypr 不等于 xyz 旋转角 + euler = convert.rot_to_ypr_xyz(R_mat_avg) + print(euler) + + t_matrix = np.identity(4) + t_matrix[:3, 3] = T_vector + # cloud_load.rotate(R_mat_avg) + # cloud_load.transform(t_matrix) + cloud_load_2 = copy.deepcopy(cloud_load).rotate(Rx, (1,0,0)) + cloud_load_2.rotate(Ry, (0,1,0)) + cloud_load_2.rotate(Rz, (0,0,1)) + cloud_load_2.translate(T_vector) + # print(np.asarray(cloud_load.points)) + # print(np.asarray(cloud_load_2.points)) + + # 要用 + _lidar2camera_project(cloud_load_2) + + # Rx = cloud_load.get_rotation_matrix_from_xyz((1.5708, 0, 0)) + # Ry = cloud_load.get_rotation_matrix_from_xyz((0, -1.5708, 0)) + # Rz = cloud_load.get_rotation_matrix_from_xyz((0, 0, 1.5708)) + # Rxyz = cloud_load.get_rotation_matrix_from_xyz((1.5708, -1.5708, 0.0)) + # cloud_load_1 = copy.deepcopy(cloud_load).rotate(Rxyz) + # cloud_load_2 = copy.deepcopy(cloud_load).rotate(Rx,(1,0,0)) + # cloud_load_2.rotate(Ry,(0,1,0)) + # # cloud_load_2 = copy.deepcopy(cloud_load).rotate(Ry,(0,1,0)) + # # cloud_load_2.rotate(Rz,(0,0,1)) + # _origin_project(cloud_load_2) + end_time = time.time() + execution_time = end_time - start_time + print(execution_time * 1000) + + # 可以选择将读取的网格可视化 + vis = o3d.visualization.Visualizer() + # 创建三个轴的几何体 + axes = o3d.geometry.TriangleMesh.create_coordinate_frame(size=1.0) + # 添加轴到可视化窗口 + vis.add_geometry(axes) + + o3d.visualization.draw_geometries([cloud_load,cloud_load_2], mesh_show_wireframe=True) + + exit() \ No newline at end of file diff --git a/libMVSDK.so b/libMVSDK.so new file mode 100644 index 0000000..cc940a7 Binary files /dev/null and b/libMVSDK.so differ diff --git a/lidar_camera_calibration.yaml b/lidar_camera_calibration.yaml new file mode 100644 index 0000000..cf1b078 --- /dev/null +++ b/lidar_camera_calibration.yaml @@ -0,0 +1,5 @@ +lidar_camera_calibration: + camera_frame_topic: /frontNear/left/image_raw + camera_info_topic: /frontNear/left/camera_info + velodyne_topic: /velodyne_points + diff --git a/marker_coordinates.txt b/marker_coordinates.txt new file mode 100644 index 0000000..ea2883e --- /dev/null +++ b/marker_coordinates.txt @@ -0,0 +1,11 @@ +2 +49.0 +47.0 +4.0 +5.0 +20.0 +49.0 +47.0 +4.0 +5.0 +20.0 \ No newline at end of file diff --git a/points.txt b/points.txt new file mode 100644 index 0000000..26798a2 --- /dev/null +++ b/points.txt @@ -0,0 +1,17 @@ +8 +-0.28833 -0.55161 3.53169 +0.0474619 -0.264463 3.52989 +-0.250885 0.0993589 3.53297 +-0.578516 -0.195354 3.5413 +0.426036 -0.623606 3.5126 +0.780823 -0.371227 3.47242 +0.530741 0.0234222 3.52194 +0.159776 -0.247036 3.50937 +1.1191 0.440097 0.441259 +1.46611 0.726851 0.576376 +1.15461 1.10508 0.573659 +0.807603 0.81833 0.438541 +1.82957 0.348847 0.640063 +2.20513 0.601418 0.766776 +1.938 1.01141 0.741323 +1.56243 0.758839 0.614611 diff --git a/project.jpg b/project.jpg new file mode 100644 index 0000000..b664a4b Binary files /dev/null and b/project.jpg differ diff --git a/rct copy.txt b/rct copy.txt new file mode 100644 index 0000000..73a6182 --- /dev/null +++ b/rct copy.txt @@ -0,0 +1,16 @@ +2528 +2715 +3440 +1574 +4528 +2471 +3607 +3613 +4881 +2549 +5719 +1309 +6876 +2102 +6052 +3367 \ No newline at end of file diff --git a/rct.txt b/rct.txt new file mode 100644 index 0000000..38781eb --- /dev/null +++ b/rct.txt @@ -0,0 +1,16 @@ +2598 +2715 +3490 +1574 +4578 +2471 +3677 +3673 +4931 +2549 +5769 +1309 +6886 +2132 +6102 +3327 \ No newline at end of file diff --git a/rect.py b/rect.py new file mode 100644 index 0000000..67a1af3 --- /dev/null +++ b/rect.py @@ -0,0 +1,138 @@ +# -- coding: utf-8 -- +import os +import sys +import threading +import ctypes +from ctypes import * +import platform +import time +import cv2 # 4.2.0.32 +import numpy as np + + +WIDTH = 9344 +HEIGH = 7000 +step = 40 + +rect_conner_points = [] +edge_rect_points = [] + + +# 生成一个随机颜色 +def generate_random_color(): + color_bgr = np.random.randint(0, 255, size=(3, )) + return color_bgr.tolist() + + +def cal_edge_rect(p1, p2, idx, im): + print(p1, p2) + tmp = [] + if idx == 1: + tmp.append([p1[0]-step,p1[1]-step]) + tmp.append([p1[0]-step,p1[1]+step*3]) + tmp.append([p2[0]+step*3,p2[1]-step]) + tmp.append([p2[0]-step,p2[1]-step]) + elif idx == 2: + tmp.append([p1[0]+step,p1[1]-step]) + tmp.append([p1[0]-step*3,p1[1]-step]) + tmp.append([p2[0]+step,p2[1]+step*3]) + tmp.append([p2[0]+step,p2[1]-step]) + elif idx == 3: + tmp.append([p1[0]+step,p1[1]+step]) + tmp.append([p1[0]+step,p1[1]-step*3]) + tmp.append([p2[0]-step*3,p2[1]+step]) + tmp.append([p2[0]+step,p2[1]+step]) + else: + tmp.append([p1[0]+step*3,p1[1]+step]) + tmp.append([p1[0]-step,p1[1]+step]) + tmp.append([p2[0]-step,p2[1]+step]) + tmp.append([p2[0]-step,p2[1]-step*3]) + + edge_rect_points.append(tmp) + pts = np.array(tmp, np.int32) + # pts = [pts] + color = (0, 255, 0) + color = generate_random_color() + # if idx == 4: + cv2.polylines(im, [pts], True, color, 5) + + +def cal_edge_rect2(p1, p2, idx, im): + print(p1, p2) + tmp = [] + if idx == 1: + tmp.append([p1[0]-step,p1[1]]) + tmp.append([p1[0]+step,p1[1]]) + tmp.append([p2[0],p2[1]+step]) + tmp.append([p2[0],p2[1]-step]) + elif idx == 2: + tmp.append([p1[0],p1[1]-step]) + tmp.append([p1[0],p1[1]+step]) + tmp.append([p2[0]-step,p2[1]]) + tmp.append([p2[0]+step,p2[1]]) + elif idx == 3: + tmp.append([p1[0]+step,p1[1]]) + tmp.append([p1[0]-step,p1[1]]) + tmp.append([p2[0],p2[1]-step]) + tmp.append([p2[0],p2[1]+step]) + else: + tmp.append([p1[0],p1[1]+step]) + tmp.append([p1[0],p1[1]-step]) + tmp.append([p2[0]+step,p2[1]]) + tmp.append([p2[0]-step,p2[1]]) + + edge_rect_points.append(tmp) + pts = np.array(tmp, np.int32) + # pts = [pts] + color = (0, 255, 0) + color = generate_random_color() + # if idx == 4: + cv2.polylines(im, [pts], True, color, 5) + + +with open('rct.txt', 'r') as file: + + # im = np.zeros((HEIGH,WIDTH,3), np.uint8) + im = cv2.imread("cloud.png") + # im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) + # _,im= cv2.threshold(im, 20, 255, cv2. THRESH_BINARY) + # im = cv2.merge([im, im, im]) + + while True: + line1 = file.readline() + if not line1: break + line2 = file.readline() + + x = int(line1) + 80 +40 + y = int(line2) + 40 + + rect_conner_points.append([x, y]) + cv2.circle(im, (x,y), 25, (255, 0, 0) , -1) + # print(rect_conner_points) + rpts = rect_conner_points + + cal_edge_rect2(rpts[0], rpts[1], 1, im) + cal_edge_rect2(rpts[1], rpts[2], 2, im) + cal_edge_rect2(rpts[2], rpts[3], 3, im) + cal_edge_rect2(rpts[3], rpts[0], 4, im) + cal_edge_rect2(rpts[4], rpts[5], 1, im) + cal_edge_rect2(rpts[5], rpts[6], 2, im) + cal_edge_rect2(rpts[6], rpts[7], 3, im) + cal_edge_rect2(rpts[7], rpts[4], 4, im) + print(edge_rect_points) + + im = cv2.resize(im, (1800, 1400)) + cv2.imshow("im", im) + cv2.waitKey(0) + cv2.destroiyAllWindows() + +with open('self_define_point.txt', 'w') as file2: + print("11") + for i in range(8): + for y in range(4): + print(str(edge_rect_points[i][y][0])) + print(str(edge_rect_points[i][y][1])) + file2.write(str(edge_rect_points[i][y][0])+'\n') + file2.write(str(edge_rect_points[i][y][1])+'\n') + +exit() \ No newline at end of file diff --git a/rst.txt b/rst.txt new file mode 100644 index 0000000..6695589 --- /dev/null +++ b/rst.txt @@ -0,0 +1,64 @@ +2608 +2715 +2708 +2715 +3570 +1624 +3570 +1524 +3570 +1524 +3570 +1624 +4608 +2471 +4708 +2471 +4708 +2471 +4608 +2471 +3737 +3563 +3737 +3663 +3737 +3663 +3737 +3563 +2708 +2715 +2608 +2715 +4961 +2549 +5061 +2549 +5849 +1359 +5849 +1259 +5849 +1259 +5849 +1359 +6956 +2152 +7056 +2152 +7056 +2152 +6956 +2152 +6182 +3317 +6182 +3417 +6182 +3417 +6182 +3317 +5061 +2549 +4961 +2549 diff --git a/self_define_point.txt b/self_define_point.txt new file mode 100644 index 0000000..b270aa9 --- /dev/null +++ b/self_define_point.txt @@ -0,0 +1,64 @@ +2673 +2755 +2723 +2755 +3610 +1639 +3610 +1589 +3610 +1589 +3610 +1639 +4673 +2511 +4723 +2511 +4723 +2511 +4673 +2511 +3777 +3628 +3777 +3678 +3777 +3678 +3777 +3628 +2723 +2755 +2673 +2755 +5026 +2589 +5076 +2589 +5889 +1374 +5889 +1324 +5889 +1324 +5889 +1374 +7021 +2192 +7071 +2192 +7071 +2192 +7021 +2192 +6222 +3382 +6222 +3432 +6222 +3432 +6222 +3382 +5076 +2589 +5026 +2589 diff --git a/transform.txt b/transform.txt new file mode 100644 index 0000000..8ab3851 --- /dev/null +++ b/transform.txt @@ -0,0 +1,2 @@ +26=(4184.22,2816.69) (3784.89,3306.51) (3299.05,2902.9) (3694.91,2412.14) Txyz=1.00735 0.801781 0.48244 Rxyz=-0.363316 1.80462 -1.63302 +582=(6575.88,2558.57) (6207.98,3087.54) (5682.26,2725.23) (6048.3,2195.78) Txyz=1.75862 0.722306 0.662323 Rxyz=-0.276921 1.80714 -1.75415 diff --git a/vidgear_client.py b/vidgear_client.py new file mode 100644 index 0000000..4deacd0 --- /dev/null +++ b/vidgear_client.py @@ -0,0 +1,47 @@ +from vidgear.gears import NetGear +import cv2 +import time + +# 设置,这里都是消息接收的方式,直接默认就行了,不用管。 +options = { + "flag": 0, "copy": False, "track": False, + # "jpeg_compression": "GRAY", + "jpeg_compression": True, + "jpeg_compression_quality": 90, + "jpeg_compression_fastdct": True, + "jpeg_compression_fastupsample": True +} + + +# address设置为客户端的ip,port设置为客户端的端口 +client = NetGear( + address="192.168.101.46", + port="5454", + protocol="tcp", + pattern=1, + receive_mode=True, + logging=True, + **options +) + +idx = 0 +while True: + # 收取数据 + frame = client.recv() + + if frame is None: + break + + cv2.imshow("Output Frame", frame) + idx += 1 + if idx == 30: + print(time.time()) + idx = 0 + + key = cv2.waitKey(1) & 0xFF + if key == ord("q"): + break + +cv2.destroyAllWindows() + +client.close() \ No newline at end of file diff --git a/wurenji.py b/wurenji.py new file mode 100644 index 0000000..3732792 --- /dev/null +++ b/wurenji.py @@ -0,0 +1,78 @@ +# -- coding: utf-8 -- +from ctypes import * +import cv2 # 4.2.0.32 +import numpy as np +from datetime import datetime +import time + +drawing = False # 鼠标是否按下 +ix, iy = -1, -1 # 初始坐标 +roi = None # ROI区域 + + +def _cal_roi(img): + # 获取当前时间 + now = datetime.now() + # 转换为时间戳(秒) + timestamp = time.mktime(now.timetuple()) + # 转换为时间戳(毫秒) + timestamp_ms = int(timestamp * 1000) + # 获取当前时间的毫秒部分 + milliseconds = now.microsecond // 1000 + # 合并秒和毫秒 + timestamp_ms += milliseconds + date_str = time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime(timestamp)) + path = "./wurenji/" + date_str + ".jpg" + rst = cv2.imwrite(path, img) + print(date_str) + print("cv2.imwrite rst: " + str(rst)) + + +# 鼠标回调函数 +def cal_roi(event, x, y, flags, param): + global ix, iy, drawing, roi + + if event == cv2.EVENT_LBUTTONDOWN: + drawing = True + ix, iy = x, y + + # elif event == cv2.EVENT_MOUSEMOVE: + # if drawing: + # img = param + # cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), 1) + # roi = (min(ix, x), min(iy, y), abs(ix - x), abs(iy - y)) + + elif event == cv2.EVENT_LBUTTONUP: + drawing = False + roi = (min(ix, x), min(iy, y), abs(ix - x), abs(iy - y)) + if roi: + x = roi[0] + y = roi[1] + w = roi[2] + h = roi[3] + img = param + _roi_im = img[y:y+h, x:x+w].copy() + # cv2.rectangle(img, (roi[0], roi[1]), (roi[0] + roi[2], roi[1] + roi[3]), (0, 255, 0), 1) + _cal_roi(_roi_im) + + +# 主程序 +img = cv2.imread('project.jpg') # 替换为你的图片路径 +cv2.imshow('image', img) +cv2.setMouseCallback('image', cal_roi, param=img) + +while True: + k = cv2.waitKey(1) & 0xFF + if k == 27: # ESC键退出 + break + +cv2.destroyAllWindows() + +# roi变量现在包含了你勾选的ROI区域 +if roi: + x, y, w, h = roi + # 处理ROI区域 + # roi_img = img[y:y+h, x:x+w] + # cv2.imshow('ROI', roi_img) + # cv2.waitKey(0) + # cv2.destroyAllWindows() \ No newline at end of file