V20251127-2.2.7
修复CLS切图函数。 同步最新的相机模块。
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include <QDir>
|
||||
|
||||
#pragma execution_character_set("utf-8")
|
||||
const std::string softwareVersion = "20251125-2.2.6";
|
||||
const std::string softwareVersion = "20251127-2.2.7";
|
||||
const std::string euiJsonVersion = "1.0.6";
|
||||
#define globalDatabasePth "./sqlDatabase/eui_db.db" //全局数据库路径
|
||||
#define saveImgEnable 1
|
||||
|
||||
+61
-31
@@ -126,49 +126,79 @@ static std::vector<cv::Mat> cutImg2ClsVec(cv::Rect boundingBox, cv::Mat imgInput
|
||||
}
|
||||
if (boundingBox.width < targetSize.width && boundingBox.height < targetSize.height)
|
||||
return { cutImg2Cls(boundingBox, imgInput, targetSize) };
|
||||
|
||||
const int w = boundingBox.width;
|
||||
const int h = boundingBox.height;
|
||||
const bool splitHoriz = (w > h);// 横向长 -> 沿X方向切
|
||||
const int targetMinSide = std::max(1, std::min(targetSize.width, targetSize.height));
|
||||
int minSide = std::min(w, h);
|
||||
minSide = std::max(minSide, targetMinSide);
|
||||
int minSide = std::max(std::min(w, h), targetMinSide);
|
||||
if (minSide <= 0) {
|
||||
std::cerr << "Bounding box has zero width or height." << std::endl;
|
||||
return result;
|
||||
}
|
||||
const int longSide = splitHoriz ? w : h;
|
||||
const int step = minSide;
|
||||
//根据长宽是否小于targetsize来分开处理
|
||||
// 沿长边切分为若干个 size=minSide 的方块,覆盖到末端且避免重复最后一块
|
||||
if (w < targetSize.width || h < targetSize.height) {
|
||||
|
||||
const int beginCoord = splitHoriz ? boundingBox.x - targetSize.height / 2 + boundingBox.height / 2 : boundingBox.y - targetSize.width / 2 + boundingBox.width / 2;
|
||||
const int endCoord = beginCoord + longSide;
|
||||
|
||||
// 沿长边切分为若干个 size=minSide 的方块,覆盖到末端且避免重复最后一块
|
||||
const bool splitHoriz = (w > h); // 横向长 -> 沿X方向切
|
||||
const int longSide = splitHoriz ? w : h;
|
||||
const int step = minSide;
|
||||
const int beginCoord = splitHoriz ? boundingBox.x - targetSize.height / 2 + boundingBox.height / 2 : boundingBox.y - targetSize.width / 2 + boundingBox.width / 2;
|
||||
const int endCoord = beginCoord + longSide + (splitHoriz ? targetSize.width / 2 : targetSize.height / 2);
|
||||
|
||||
// 计算切块起点列表
|
||||
std::vector<int> starts;
|
||||
starts.reserve((longSide + step - 1) / step);
|
||||
for (int s = beginCoord; s + step <= endCoord; s += step) {
|
||||
starts.emplace_back(s);
|
||||
}
|
||||
// 确保包含末端(避免遗漏),同时避免与最后一个重复
|
||||
const int lastStart = std::max(beginCoord, endCoord - step);
|
||||
if (starts.empty() || starts.back() != lastStart) {
|
||||
starts.emplace_back(lastStart);
|
||||
}
|
||||
|
||||
result.reserve(starts.size());
|
||||
if (splitHoriz) {
|
||||
int y = boundingBox.y - targetSize.width / 2 + boundingBox.height / 2;
|
||||
for (int x : starts) {
|
||||
result.emplace_back(cutImg2Cls(cv::Rect(x, y, minSide, minSide), imgInput, targetSize));
|
||||
// 计算切块起点列表
|
||||
std::vector<int> starts;
|
||||
starts.reserve((longSide + step - 1) / step);
|
||||
for (int s = beginCoord; s + step <= endCoord; s += step) {
|
||||
starts.emplace_back(s);
|
||||
}
|
||||
} else {
|
||||
int x = boundingBox.x - targetSize.width / 2 + boundingBox.width / 2;
|
||||
for (int y : starts) {
|
||||
result.emplace_back(cutImg2Cls(cv::Rect(x, y, minSide, minSide), imgInput, targetSize));
|
||||
// 确保包含末端(避免遗漏),同时避免与最后一个重复
|
||||
const int lastStart = std::max(beginCoord, endCoord - step);
|
||||
if (starts.empty() || starts.back() != lastStart) {
|
||||
starts.emplace_back(lastStart);
|
||||
}
|
||||
|
||||
result.reserve(starts.size());
|
||||
if (splitHoriz) {
|
||||
int y = boundingBox.y - targetSize.width / 2 + boundingBox.height / 2;
|
||||
for (int x : starts) {
|
||||
result.emplace_back(cutImg2Cls(cv::Rect(x, y, minSide, minSide), imgInput, targetSize));
|
||||
}
|
||||
}
|
||||
else {
|
||||
int x = boundingBox.x - targetSize.width / 2 + boundingBox.width / 2;
|
||||
for (int y : starts) {
|
||||
result.emplace_back(cutImg2Cls(cv::Rect(x, y, minSide, minSide), imgInput, targetSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
const int beginCoord = splitHoriz ? boundingBox.x : boundingBox.y ;
|
||||
const int endCoord = beginCoord + longSide;
|
||||
|
||||
// 计算切块起点列表
|
||||
std::vector<int> starts;
|
||||
starts.reserve((longSide + step - 1) / step);
|
||||
for (int s = beginCoord; s + step <= endCoord; s += step) {
|
||||
starts.emplace_back(s);
|
||||
}
|
||||
// 确保包含末端(避免遗漏),同时避免与最后一个重复
|
||||
const int lastStart = std::max(beginCoord, endCoord - step);
|
||||
if (starts.empty() || starts.back() != lastStart) {
|
||||
starts.emplace_back(lastStart);
|
||||
}
|
||||
|
||||
result.reserve(starts.size());
|
||||
if (splitHoriz) {
|
||||
for (int x : starts) {
|
||||
result.emplace_back(cutImg2Cls(cv::Rect(x, boundingBox.y, minSide, minSide), imgInput, targetSize));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int y : starts) {
|
||||
result.emplace_back(cutImg2Cls(cv::Rect(boundingBox.x, y, minSide, minSide), imgInput, targetSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -6,8 +6,20 @@ int main(int argc, char* argv[])
|
||||
//rlj_hanyin("D:\\º¸Ó¡Image\\11.20\\T\\NG", "bmp", "./outputs/", cv::Size(300, 300));
|
||||
//yuhan_hanqian("D:\\testImage\\OK", "bmp", "./outputs/" , cv::Size(300, 300));
|
||||
// yuhan_hanqian("D:\\testImg\\L", "bmp", "./outputs/", cv::Size(50, 50));
|
||||
cv::Mat img = cv::imread("D:\\testImage\\04QCB82602000JFBN00206BN_Camera3_ORI_0_09-42-34-710.bmp", -1);
|
||||
//755 4300 60 300
|
||||
auto imgs = cutImg2ClsVec(cv::Rect(8120, 4850, 1007, 129), img);
|
||||
cv::Mat img = cv::imread("D:\\testImage\\cutImageTest (2).bmp", -1);
|
||||
img(cv::Rect(1000, 1500, 2350, 1020)).copyTo(img);
|
||||
cv::Mat imgR = cv::imread("D:\\testImage\\cutImageTest (1).bmp", -1);
|
||||
std::vector<std::vector<cv::Point>> contours;
|
||||
cv::findContours(imgR, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
|
||||
std::vector<std::vector<cv::Mat>> allCutImgs;
|
||||
std::vector<cv::Mat> samples;
|
||||
for (auto& contour : contours) {
|
||||
//755 4300 60 300
|
||||
auto imgs = cutImg2ClsVec(cv::boundingRect(contour), img);
|
||||
allCutImgs.push_back(imgs);
|
||||
samples.push_back(img(cv::boundingRect(contour)));
|
||||
}
|
||||
auto imgs = cutImg2ClsVec(cv::Rect(370, 320, 384, 70), img);
|
||||
cv::Mat sa = img(cv::Rect(370, 320, 384, 70));
|
||||
return 1;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
# 获取获取当前目录名
|
||||
get_filename_component(CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
string(TIMESTAMP RUN_TIME)
|
||||
message( " model start : " ${CURRENT_FOLDER}:${RUN_TIME})
|
||||
|
||||
set(DLL_NAMES "keyence3D" "opencv")
|
||||
foreach(child ${DLL_NAMES})
|
||||
|
||||
LIST(APPEND ENV_INCLUDE ${${child}_include})
|
||||
LIST(APPEND ENV_LIB ${${child}_lib})
|
||||
LIST(APPEND ENV_TARGET ${${child}_target_link})
|
||||
endforeach()
|
||||
message(" ENV_INCLUDE : " ${ENV_INCLUDE} )
|
||||
message(" ENV_LIB : " ${ENV_LIB} )
|
||||
message(" ENV_TARGET : " ${ENV_TARGET} )
|
||||
include_directories(
|
||||
|
||||
${ENV_INCLUDE}
|
||||
)
|
||||
|
||||
link_directories (
|
||||
${ENV_LIB}
|
||||
|
||||
)
|
||||
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
SET(CMAKE_AUTOUIC OFF)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
FILE(GLOB HEAD_FILES "./*.h" )
|
||||
FILE(GLOB SRC_FILES "./*.cpp")
|
||||
FILE(GLOB UI_FILES "./*.ui")
|
||||
|
||||
|
||||
#find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
|
||||
|
||||
add_library(${CURRENT_FOLDER} SHARED
|
||||
${HEAD_FILES}
|
||||
${SRC_FILES}
|
||||
${UI_FILES}
|
||||
)
|
||||
|
||||
|
||||
|
||||
set_target_properties(${CURRENT_FOLDER} PROPERTIES LINKER_LANGUAGE C
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}
|
||||
)
|
||||
|
||||
|
||||
target_link_libraries(${CURRENT_FOLDER} PRIVATE
|
||||
${ENV_TARGET}
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
)
|
||||
|
||||
|
||||
# target_compile_definitions(${CURRENT_FOLDER} PRIVATE HD_AIDEMO_MODULE_LIBRARY)
|
||||
|
||||
|
||||
|
||||
|
||||
string(TIMESTAMP RUN_TIME)
|
||||
message( " model end : " ${CURRENT_FOLDER}:${RUN_TIME})
|
||||
@@ -1,567 +0,0 @@
|
||||
#include "Hd_CameraModule_3DKeyence.h"
|
||||
#include <exception>
|
||||
#include <qthread.h>
|
||||
#include <QTextCodec>
|
||||
#include <qqueue.h>
|
||||
#include <qmutex.h>
|
||||
|
||||
int G_xImageSize = 0; // Number of X points.
|
||||
int G_yImageSize = 0; // Number of Y lines.
|
||||
//const int MAX_LJXA_XDATANUM = 3200;
|
||||
//const unsigned int BUFFER_FULL_COUNT = 30000;
|
||||
//
|
||||
//int _imageAvailable[MAX_LJXA_DEVICENUM] = { 0 };
|
||||
//unsigned short* _luminanceBuf[MAX_LJXA_DEVICENUM] = { 0 };
|
||||
//unsigned short* _heightBuf[MAX_LJXA_DEVICENUM] = { 0 };
|
||||
//int _lastImageSizeHeight[MAX_LJXA_DEVICENUM];
|
||||
int imgTakeNum = 0, imgTarget = 1;
|
||||
int imgIndex = 0;
|
||||
int getImageTimeOut = 3000;
|
||||
QString lastError;
|
||||
QMutex* m_mutex = nullptr;
|
||||
std::mutex bufferMutex;
|
||||
QQueue< cv::Mat> heightMatS;//高度图
|
||||
QQueue<cv::Mat> luminanceMatS;//灰度图
|
||||
//data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。
|
||||
bool ifBreak = false;
|
||||
//ifRunning减少ifBreak的判断;"rest_newProductIn"时,Logic_camera_thread框架会结束未处理完的相相机取图
|
||||
bool ifRunning = false;
|
||||
QString byteArrayToUnicode(const QByteArray array) {
|
||||
|
||||
// state用于保存转换状态,它的成员invalidChars,可用来判断是否转换成功
|
||||
// 如果转换成功,则值为0,如果值大于0,则说明转换失败
|
||||
QTextCodec::ConverterState state;
|
||||
// 先尝试使用utf-8的方式把QByteArray转换成QString
|
||||
QString text = QTextCodec::codecForName("UTF-8")->toUnicode(array.constData(), array.size(), &state);
|
||||
// 如果转换时无效字符数量大于0,说明编码格式不对
|
||||
if (state.invalidChars > 0)
|
||||
{
|
||||
// 再尝试使用GBK的方式进行转换,一般就能转换正确(当然也可能是其它格式,但比较少见了)
|
||||
text = QTextCodec::codecForName("GBK")->toUnicode(array);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
bool JumpFlag = false;
|
||||
int yCounts;
|
||||
void myCallbackFunc(LJX8IF_PROFILE_HEADER* pProfileHeaderArray, WORD* pHeightProfileArray, WORD* pLuminanceProfileArray, DWORD dwLuminanceEnable, DWORD dwProfileDataCount, DWORD dwCount, DWORD dwNotify, DWORD dwUser)
|
||||
{
|
||||
try
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " --> Enter callback function";
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwProfileDataCount = " << dwProfileDataCount;
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwCount = " << dwCount;
|
||||
std::cout << "dwCount->" << dwCount <<" dwProfileDataCount"<< dwProfileDataCount << "dwNotify = " << dwNotify<< std::endl;
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "dwNotify = " << dwNotify;
|
||||
//if (dwCount < 1000)return;
|
||||
/* if ((dwNotify != 0) || (dwNotify & 0x10000) != 0)
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
std::lock_guard<std::mutex> lock(bufferMutex);
|
||||
if (dwCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_imageAvailable[dwUser] == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// _heightBuf 代表的含义:程序里的高度缓存区,pHeightProfileArray 回调函数里的数据
|
||||
// 此处崩溃的可能性:xImageSize 配置文件中设置的值和3D相机调试软件设置的值不一致,会崩溃。
|
||||
if (JumpFlag)
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "JumpFlag";
|
||||
return;
|
||||
}
|
||||
if (_heightBuf[dwUser] == NULL)
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_heightBuf[dwUser] == NULL";
|
||||
_heightBuf[dwUser] = (unsigned short*)malloc(G_yImageSize * MAX_LJXA_XDATANUM * 2);
|
||||
//return;
|
||||
}
|
||||
if (pHeightProfileArray == NULL)
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pHeightProfileArray== NULL";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_heightBuf[dwUser]: " << _heightBuf[dwUser];
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pHeightProfileArray: " << pHeightProfileArray;
|
||||
|
||||
//判断内存是否重叠
|
||||
if (_heightBuf[dwUser] <= pHeightProfileArray || (unsigned short*)_heightBuf[dwUser] >= (WORD*)pHeightProfileArray + dwProfileDataCount * dwCount * 2)
|
||||
{
|
||||
memcpy(&_heightBuf[dwUser][0], pHeightProfileArray, dwProfileDataCount * dwCount * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "first memcpy _heightBuf error";
|
||||
if (_heightBuf[dwUser] != NULL)
|
||||
{
|
||||
free(_heightBuf[dwUser]);
|
||||
_heightBuf[dwUser] = NULL;
|
||||
}
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " memcpy _heightBuf again ";
|
||||
_heightBuf[dwUser] = (unsigned short*)malloc(yCounts * MAX_LJXA_XDATANUM * 2);
|
||||
memcpy(&_heightBuf[dwUser][0], pHeightProfileArray, dwProfileDataCount * dwCount * 2);
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Second memcpy _heightBuf success ";
|
||||
|
||||
}
|
||||
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_luminanceBuf[dwUser]: " << _luminanceBuf[dwUser];
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "pLuminanceProfileArray: " << pLuminanceProfileArray;
|
||||
if (dwLuminanceEnable == 1)
|
||||
{
|
||||
if (_luminanceBuf[dwUser] == NULL)
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "_luminanceBuf[dwUser]== NULL";
|
||||
//return;
|
||||
_luminanceBuf[dwUser] = (unsigned short*)malloc(G_yImageSize * MAX_LJXA_XDATANUM * 2);
|
||||
}
|
||||
if (_luminanceBuf[dwUser] <= pLuminanceProfileArray || (unsigned short*)_luminanceBuf[dwUser] >= (WORD*)pLuminanceProfileArray + dwProfileDataCount * dwCount * 2)
|
||||
memcpy(&_luminanceBuf[dwUser][0], pLuminanceProfileArray, dwProfileDataCount * dwCount * 2);
|
||||
else
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "memcpy _luminanceBuf error";
|
||||
}
|
||||
_imageAvailable[dwUser] = 1; // 图像获取成功 dwUser 和 deviceId 一致
|
||||
_lastImageSizeHeight[dwUser] = dwCount; // 扫描的行数, dwCount 和 yImageSize 一致
|
||||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " --> execute callback function error";
|
||||
}
|
||||
}
|
||||
|
||||
int Hd_CameraModule_3DKeyence::LJXA_ACQ_OpenDevice(int lDeviceId, LJX8IF_ETHERNET_CONFIG* EthernetConfig, int HighSpeedPortNo)
|
||||
{
|
||||
int errCode = LJX8IF_EthernetOpen(lDeviceId, EthernetConfig);
|
||||
|
||||
_ethernetConfig[lDeviceId] = *EthernetConfig;
|
||||
_highSpeedPortNo[lDeviceId] = HighSpeedPortNo;
|
||||
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Open device ! errCode:" << errCode;
|
||||
return errCode;
|
||||
}
|
||||
|
||||
void Hd_CameraModule_3DKeyence::LJXA_ACQ_CloseDevice(int lDeviceId)
|
||||
{
|
||||
LJX8IF_FinalizeHighSpeedDataCommunication(lDeviceId);
|
||||
LJX8IF_CommunicationClose(lDeviceId);
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Close device!";
|
||||
}
|
||||
|
||||
|
||||
bool Hd_CameraModule_3DKeyence::decodeInitData(QByteArray byteArray,QVector<QByteArray> &vector_data)
|
||||
{
|
||||
while (!byteArray.isEmpty())
|
||||
{
|
||||
int type = 0;
|
||||
QByteArray m_type = byteArray.mid(0,4);
|
||||
memcpy((void*)&type,(void*)m_type.data(), 4);
|
||||
byteArray.remove(0,4);
|
||||
|
||||
int len = 0;
|
||||
QByteArray m_len = byteArray.mid(0,4);
|
||||
memcpy((void*)&len,(void*)m_len.data(), 4);
|
||||
byteArray.remove(0,4);
|
||||
|
||||
QByteArray mm_data = byteArray.mid(0,len);
|
||||
vector_data.append(mm_data);
|
||||
byteArray.remove(0,len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Hd_CameraModule_3DKeyence* create()
|
||||
{
|
||||
qDebug() << __FUNCTION__ << "line:" << __LINE__ << " Hd_CameraModule_3DKeyence create success!" ;
|
||||
return new Hd_CameraModule_3DKeyence;
|
||||
}
|
||||
|
||||
void destory(Hd_CameraModule_3DKeyence * ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
ptr = nullptr;
|
||||
}
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Hd_CameraModule_3DKeyence destory success!";
|
||||
}
|
||||
|
||||
Hd_CameraModule_3DKeyence::Hd_CameraModule_3DKeyence()
|
||||
{
|
||||
m_mutex = new QMutex;
|
||||
}
|
||||
|
||||
|
||||
Hd_CameraModule_3DKeyence::~Hd_CameraModule_3DKeyence()
|
||||
{
|
||||
if (isopen)
|
||||
{
|
||||
isopen = false;
|
||||
|
||||
// Stop HighSpeed
|
||||
errCode = LJX8IF_StopHighSpeedDataCommunication(deviceId);
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Stop HighSpeed errCode:" << errCode;
|
||||
|
||||
LJXA_ACQ_CloseDevice(deviceId);
|
||||
qDebug() << __FUNCTION__ << "line:" << __LINE__ << " CloseDevice success!";
|
||||
if (heightImage)
|
||||
{
|
||||
free(heightImage);
|
||||
|
||||
}
|
||||
if (luminanceImage)
|
||||
{
|
||||
free(luminanceImage);
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory
|
||||
if (_heightBuf[deviceId] != NULL)
|
||||
{
|
||||
free(_heightBuf[deviceId]);
|
||||
}
|
||||
|
||||
if (_luminanceBuf[deviceId] != NULL)
|
||||
{
|
||||
free(_luminanceBuf[deviceId]);
|
||||
}
|
||||
|
||||
if (startReq_ptr)
|
||||
{
|
||||
delete startReq_ptr;
|
||||
startReq_ptr = nullptr;
|
||||
}
|
||||
|
||||
if (profileInfo_ptr)
|
||||
{
|
||||
delete profileInfo_ptr;
|
||||
profileInfo_ptr = nullptr;
|
||||
}
|
||||
|
||||
if (setParam_Ptr)
|
||||
{
|
||||
delete setParam_Ptr;
|
||||
setParam_Ptr = nullptr;
|
||||
}
|
||||
|
||||
if (getParam_Ptr)
|
||||
{
|
||||
delete getParam_Ptr;
|
||||
getParam_Ptr = nullptr;
|
||||
}
|
||||
if (m_mutex)
|
||||
{
|
||||
delete m_mutex;
|
||||
m_mutex = nullptr;
|
||||
}
|
||||
qDebug() << __FUNCTION__ << "line:" << __LINE__ << " delete success!";
|
||||
}
|
||||
|
||||
bool Hd_CameraModule_3DKeyence::readData(std::vector<cv::Mat> &mats,QByteArray &data)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
|
||||
QMutexLocker locker(m_mutex);
|
||||
if (luminanceMatS.empty() || heightMatS.empty())
|
||||
{
|
||||
qDebug() << " [Error] " << " srcImage is null";
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < imgTarget; i++) {
|
||||
if (heightMatS.size() >= 1 && luminanceMatS.size() >= 1) {
|
||||
mats.push_back(luminanceMatS.dequeue());
|
||||
mats.push_back(heightMatS.dequeue());
|
||||
}
|
||||
else {
|
||||
mats.push_back(cv::Mat(G_xImageSize, G_yImageSize, CV_8UC1, cv::Scalar(0, 0, 0)));
|
||||
mats.push_back(cv::Mat(G_xImageSize, G_yImageSize, CV_8UC1, cv::Scalar(0, 0, 0)));
|
||||
}
|
||||
}
|
||||
imgTakeNum = 0;
|
||||
qCritical() << " [info] " << __FUNCTION__ << " line:" << __LINE__ << " checkImg readData,deviceId" << deviceId << " imgIndex" << imgIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Hd_CameraModule_3DKeyence::writeData(std::vector<cv::Mat> &mat,QByteArray &data)
|
||||
{
|
||||
if (data == "clearCahce") {
|
||||
QMutexLocker locker(m_mutex);
|
||||
heightMatS.clear();
|
||||
luminanceMatS.clear();
|
||||
}
|
||||
//2024.02.18更新,相机对应的读SN信号时,表示新产品进入,设置初始值
|
||||
//if (data == "rest_newProductIn")
|
||||
//{
|
||||
// //根据实际项目,设置初始值:曝光、增益,ROI区域等
|
||||
// /*{
|
||||
// if (expourseTimeList.size() > 0)
|
||||
// SetExposureTime(expourseTimeList[0]);
|
||||
// if (gainList.size() > 0)
|
||||
// SetGain(gainList[0]);
|
||||
// }
|
||||
// getImageNum = 0;*/
|
||||
// if (luminanceMatS.size() > 0 || heightMatS.size() > 0)
|
||||
// {
|
||||
// m_mutex->lock();
|
||||
// luminanceMatS.clear();
|
||||
// heightMatS.clear();
|
||||
// m_mutex->unlock();
|
||||
// std::cout << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << camera_name.toStdString() << std::endl;
|
||||
// qWarning() << __FUNCTION__ << " line: " << __LINE__ << "rest_newProductIn , queuePic.size() > 0 ,signal maybe too fast " << camera_name;
|
||||
// }
|
||||
// if (ifRunning == true)
|
||||
// {
|
||||
// ifBreak = true;
|
||||
// Sleep(10);
|
||||
// }
|
||||
// imgIndex = 0;
|
||||
// //getImageNum = 0;
|
||||
// return true;
|
||||
//}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//传入initParas函数,格式为:相机key+参数名1#参数值1#参数值2+参数名2#参数值1...
|
||||
bool Hd_CameraModule_3DKeyence::initParas(QByteArray& initData)
|
||||
{
|
||||
QByteArrayList valueList = initData.split('#');
|
||||
if (valueList.size() < 6) {
|
||||
qDebug() << "[Error] " << " Hd_CameraModule_HIK initParas fail--params error!参数数量不满足";
|
||||
lastError = "参数数量不满足";
|
||||
return false;
|
||||
}
|
||||
EthernetConfig.wPortNo = 24691;
|
||||
|
||||
camera_name = valueList[0];
|
||||
auto valueL1 = valueList[0].split('.');
|
||||
if (valueL1.size() == 4)
|
||||
{
|
||||
EthernetConfig.abyIpAddress[0] = valueL1.at(0).toInt();
|
||||
EthernetConfig.abyIpAddress[1] = valueL1.at(1).toInt();
|
||||
EthernetConfig.abyIpAddress[2] = valueL1.at(2).toInt();
|
||||
EthernetConfig.abyIpAddress[3] = valueL1.at(3).toInt();
|
||||
}
|
||||
|
||||
deviceId = valueList[1].toInt();
|
||||
|
||||
xImageSize = valueList[2].toInt();
|
||||
G_xImageSize = valueList[2].toInt();
|
||||
|
||||
yImageSize = valueList[3].toInt();
|
||||
G_yImageSize = valueList[3].toInt();
|
||||
|
||||
imgTarget = valueList[4].toInt();
|
||||
|
||||
getImageTimeOut = valueList[5].toInt();
|
||||
yCounts = yImageSize;
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " camera_name:" << camera_name << " paras init is success!";
|
||||
|
||||
// 初始化申请空间 20230214
|
||||
startReq_ptr = new LJX8IF_HIGH_SPEED_PRE_START_REQ;
|
||||
profileInfo_ptr = new LJX8IF_PROFILE_INFO;
|
||||
startReq_ptr->bySendPosition = 2;
|
||||
|
||||
setParam_Ptr = new LJXA_ACQ_SETPARAM;
|
||||
getParam_Ptr = new LJXA_ACQ_GETPARAM;
|
||||
|
||||
setParam_Ptr->y_linenum = yImageSize;
|
||||
setParam_Ptr->y_pitch_um = y_pitch_um;
|
||||
setParam_Ptr->timeout_ms = timeout_ms;
|
||||
setParam_Ptr->use_external_batchStart = use_external_batchStart;
|
||||
|
||||
// Allocate user memory
|
||||
heightImage = (unsigned short*)malloc(sizeof(unsigned short) * xImageSize * yImageSize);
|
||||
luminanceImage = (unsigned short*)malloc(sizeof(unsigned short) * xImageSize * yImageSize);
|
||||
|
||||
errCode = LJXA_ACQ_OpenDevice(deviceId, &EthernetConfig, HighSpeedPortNo);
|
||||
if ( errCode != LJX8IF_RC_OK )
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Failed to open device ";
|
||||
//Free user memory
|
||||
if ( heightImage )
|
||||
{
|
||||
free(heightImage);
|
||||
}
|
||||
|
||||
if ( luminanceImage )
|
||||
{
|
||||
free(luminanceImage);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isopen = true;
|
||||
|
||||
// Allocate memory
|
||||
_heightBuf[deviceId] = (unsigned short*)malloc(yImageSize * MAX_LJXA_XDATANUM * 2);
|
||||
if (_heightBuf[deviceId] == NULL)
|
||||
{
|
||||
return LJX8IF_RC_ERR_NOMEMORY;
|
||||
}
|
||||
|
||||
_luminanceBuf[deviceId] = (unsigned short*)malloc(yImageSize * MAX_LJXA_XDATANUM * 2);
|
||||
if (_luminanceBuf[deviceId] == NULL)
|
||||
{
|
||||
return LJX8IF_RC_ERR_NOMEMORY;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
if (!InitHighSpeed())
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " InitHighSpeed error! " ;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Hd_CameraModule_3DKeyence::InitHighSpeed()
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( startReq_ptr == nullptr )
|
||||
{
|
||||
startReq_ptr = new LJX8IF_HIGH_SPEED_PRE_START_REQ;
|
||||
startReq_ptr->bySendPosition = 2;
|
||||
qWarning() << __FUNCTION__ << " line: " << __LINE__ << " startReq_ptr is null! ";
|
||||
}
|
||||
if ( profileInfo_ptr == nullptr )
|
||||
{
|
||||
profileInfo_ptr = new LJX8IF_PROFILE_INFO;
|
||||
qWarning() << __FUNCTION__ << " line: " << __LINE__ << " profileInfo_ptr is null! ";
|
||||
}
|
||||
errCode = LJX8IF_InitializeHighSpeedDataCommunicationSimpleArray(deviceId, &_ethernetConfig[deviceId], _highSpeedPortNo[deviceId], &myCallbackFunc, yImageSize, deviceId); // 初始化高速通讯
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode:" << errCode;
|
||||
errCode = LJX8IF_PreStartHighSpeedDataCommunication(deviceId, startReq_ptr, profileInfo_ptr); // 预开始启动高速通信,作用 做预连接
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode:" << errCode;
|
||||
|
||||
// zUnit
|
||||
errCode = LJX8IF_GetZUnitSimpleArray(deviceId, &zUnit);
|
||||
if (errCode != 0 || zUnit == 0)
|
||||
{
|
||||
qCritical() << __FUNCTION__ << " line:" << __LINE__ << " Failed to acquire zunit! ";
|
||||
return false;
|
||||
}
|
||||
errCode = LJX8IF_StartHighSpeedDataCommunication(deviceId); // 正式开始高速通讯
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " errCode: " << errCode;
|
||||
|
||||
//Start HighSpeed
|
||||
_imageAvailable[deviceId] = 0;
|
||||
_lastImageSizeHeight[deviceId] = 0;
|
||||
}
|
||||
catch (const QString ev)
|
||||
{
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " ev: " << ev;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool Hd_CameraModule_3DKeyence::run()
|
||||
{
|
||||
|
||||
ifRunning = true;
|
||||
ifBreak = false;
|
||||
if ( !isopen )
|
||||
{
|
||||
qCritical() << __FUNCTION__ << " line:" << __LINE__ << " device is not opened! ";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while (imgTakeNum != imgTarget)
|
||||
{
|
||||
int sleepMs = 10;
|
||||
int cnt = 0;
|
||||
int timeoutCnt = getImageTimeOut / sleepMs;
|
||||
while (_imageAvailable[deviceId] != 1 )
|
||||
{
|
||||
QThread::msleep(10);
|
||||
if (cnt++ >= timeoutCnt)
|
||||
{
|
||||
heightMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0)));
|
||||
luminanceMatS.push_back(cv::Mat(G_yImageSize, G_xImageSize, CV_8UC1, cv::Scalar(0, 0, 0)));
|
||||
imgTakeNum++;
|
||||
qDebug() << "imgGetERROR insert blank img cameraID:" << camera_name;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::lock_guard<std::mutex> lock(bufferMutex);
|
||||
_getParam[deviceId].luminance_enabled = profileInfo_ptr->byLuminanceOutput;
|
||||
_getParam[deviceId].x_pointnum = profileInfo_ptr->wProfileDataCount;
|
||||
_getParam[deviceId].y_linenum_acquired = _lastImageSizeHeight[deviceId];
|
||||
_getParam[deviceId].x_pitch_um = profileInfo_ptr->lXPitch / 100.0f;
|
||||
_getParam[deviceId].y_pitch_um = y_pitch_um;
|
||||
_getParam[deviceId].z_pitch_um = zUnit / 100.0f;
|
||||
|
||||
*getParam_Ptr = _getParam[deviceId];
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " getPara Finished: ";
|
||||
int xDataNum = _getParam[deviceId].x_pointnum;
|
||||
|
||||
unsigned short* dwHeightBuf = (unsigned short*)&_heightBuf[deviceId][0];
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " dwHeightBuf Init Finished: ";
|
||||
memcpy(heightImage, dwHeightBuf, xDataNum * yImageSize * 2);
|
||||
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Height Img memcpy Finished: ";
|
||||
std::vector<unsigned short>poits(xDataNum * yImageSize * 2, 0);
|
||||
if (_getParam[deviceId].luminance_enabled > 0)
|
||||
{
|
||||
unsigned short* dwLuminanceBuf = (unsigned short*)&_luminanceBuf[deviceId][0];
|
||||
memcpy(luminanceImage, dwLuminanceBuf, xDataNum * yImageSize * 2);
|
||||
}
|
||||
// Free memory
|
||||
if (_heightBuf[deviceId] != NULL)
|
||||
{
|
||||
free(_heightBuf[deviceId]);
|
||||
_heightBuf[deviceId] = NULL;
|
||||
}
|
||||
|
||||
if (_luminanceBuf[deviceId] != NULL)
|
||||
{
|
||||
free(_luminanceBuf[deviceId]);
|
||||
_luminanceBuf[deviceId] = NULL;
|
||||
}
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " Free memory Finished: ";
|
||||
|
||||
m_mutex->lock();
|
||||
cv::Mat luminanceMat;
|
||||
if(_lastImageSizeHeight[deviceId] != 0)
|
||||
luminanceMat = cv::Mat(_lastImageSizeHeight[deviceId], xImageSize, CV_16UC1, luminanceImage);
|
||||
else
|
||||
luminanceMat = cv::Mat(yImageSize, xImageSize, CV_16UC1, luminanceImage);
|
||||
cv::normalize(luminanceMat, luminanceMat, 0, 255, cv::NORM_MINMAX);
|
||||
cv::convertScaleAbs(luminanceMat, luminanceMat);
|
||||
|
||||
luminanceMatS.enqueue(luminanceMat);
|
||||
|
||||
cv::Mat heightImg;
|
||||
if (_lastImageSizeHeight[deviceId] != 0)
|
||||
cv::Mat(_lastImageSizeHeight[deviceId], xImageSize, CV_16UC1, heightImage).copyTo(heightImg);
|
||||
else
|
||||
cv::Mat(yImageSize, xImageSize, CV_16UC1, heightImage).copyTo(heightImg);
|
||||
heightMatS.enqueue(heightImg);
|
||||
m_mutex->unlock();
|
||||
qDebug() << __FUNCTION__ << " line:" << __LINE__ << " success to acquire 3d image! camera_name: " << camera_name;
|
||||
//Start HighSpeed
|
||||
_imageAvailable[deviceId] = 0;
|
||||
_lastImageSizeHeight[deviceId] = 0;
|
||||
imgTakeNum++;
|
||||
}
|
||||
qDebug() << camera_name <<"Finish";
|
||||
return true;
|
||||
}
|
||||
catch (QString ev)
|
||||
{
|
||||
qCritical() << __FUNCTION__ << " line: " << __LINE__ << " ev: " << ev;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef Hd_CameraModule_3DKeyence_H
|
||||
#define Hd_CameraModule_3DKeyence_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include<iostream>
|
||||
#include <Windows.h>
|
||||
|
||||
#include "LJX8_IF.h"
|
||||
#include "LJX8_ErrorCode.h"
|
||||
|
||||
#include <subModuleBase.h>
|
||||
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
typedef struct {
|
||||
int y_linenum;
|
||||
float y_pitch_um;
|
||||
int timeout_ms;
|
||||
int use_external_batchStart;
|
||||
} LJXA_ACQ_SETPARAM;
|
||||
|
||||
typedef struct {
|
||||
int luminance_enabled;
|
||||
int x_pointnum;
|
||||
int y_linenum_acquired;
|
||||
float x_pitch_um;
|
||||
float y_pitch_um;
|
||||
float z_pitch_um;
|
||||
} LJXA_ACQ_GETPARAM;
|
||||
|
||||
|
||||
const int MAX_LJXA_DEVICENUM = 6;
|
||||
const int MAX_LJXA_XDATANUM = 3200;
|
||||
const unsigned int BUFFER_FULL_COUNT = 30000;
|
||||
|
||||
static int _imageAvailable[MAX_LJXA_DEVICENUM] = { 0 };
|
||||
static unsigned short* _luminanceBuf[MAX_LJXA_DEVICENUM] = { 0 };
|
||||
static unsigned short* _heightBuf[MAX_LJXA_DEVICENUM] = { 0 };
|
||||
static int _lastImageSizeHeight[MAX_LJXA_DEVICENUM];
|
||||
|
||||
class Hd_CameraModule_3DKeyence :public dsModuleBase
|
||||
{
|
||||
public:
|
||||
Hd_CameraModule_3DKeyence();
|
||||
virtual ~Hd_CameraModule_3DKeyence();
|
||||
//从类中读数据到实例对象
|
||||
bool readData(std::vector<cv::Mat>& mats, QByteArray& data);
|
||||
//实例对象把数据写入到类
|
||||
bool writeData(std::vector<cv::Mat>& mat, QByteArray& data);
|
||||
bool initParas(QByteArray& initData);
|
||||
bool run();
|
||||
|
||||
int LJXA_ACQ_OpenDevice(int lDeviceId, LJX8IF_ETHERNET_CONFIG* EthernetConfig, int HighSpeedPortNo);
|
||||
//int LJXA_ACQ_StartAsync(int lDeviceId, LJXA_ACQ_SETPARAM* setParam);
|
||||
//int LJXA_ACQ_AcquireAsync(int lDeviceId, unsigned short* heightImage, unsigned short* luminanceImage, LJXA_ACQ_SETPARAM* setParam, LJXA_ACQ_GETPARAM* getParam);
|
||||
void LJXA_ACQ_CloseDevice(int lDeviceId);
|
||||
|
||||
bool decodeInitData(QByteArray byteArray, QVector<QByteArray>& vector_data);
|
||||
bool InitHighSpeed();
|
||||
private:
|
||||
//int LJXA_ACQ_Acquire(int lDeviceId, unsigned short* heightImage, unsigned short* luminanceImage, LJXA_ACQ_SETPARAM* setParam, LJXA_ACQ_GETPARAM* getParam);
|
||||
LJX8IF_HIGH_SPEED_PRE_START_REQ* startReq_ptr = nullptr;
|
||||
LJX8IF_PROFILE_INFO* profileInfo_ptr = nullptr;
|
||||
|
||||
// Static variable
|
||||
LJX8IF_ETHERNET_CONFIG _ethernetConfig[MAX_LJXA_DEVICENUM];
|
||||
int _highSpeedPortNo[MAX_LJXA_DEVICENUM];
|
||||
|
||||
LJXA_ACQ_GETPARAM _getParam[MAX_LJXA_DEVICENUM];
|
||||
|
||||
int deviceId = 0; // Set "0" if you use only 1 head.
|
||||
int xImageSize = 0; // Number of X points.
|
||||
int yImageSize = 0; // Number of Y lines.
|
||||
float y_pitch_um = 0; // Data pitch of Y data. (e.g. your encoder setting)
|
||||
int timeout_ms = 0; // Timeout value for the acquiring image (in milisecond).
|
||||
int use_external_batchStart = 1; // Set "1" if you controll the batch start timing externally. (e.g. terminal input) 0内部触发,1外部触发
|
||||
std::string outputFilePath1 = "sample_height.csv";
|
||||
std::string outputFilePath2 = "sample_height.tif";
|
||||
std::string outputFilePath3 = "sample_luminance.tif";
|
||||
|
||||
//std::vector< cv::Mat> vector_mat;
|
||||
unsigned short zUnit = 0;
|
||||
|
||||
unsigned short* heightImage = nullptr; // Height image
|
||||
unsigned short* luminanceImage = nullptr; // Luminance image
|
||||
|
||||
LJXA_ACQ_SETPARAM* setParam_Ptr = nullptr;
|
||||
LJXA_ACQ_GETPARAM* getParam_Ptr = nullptr;
|
||||
int HighSpeedPortNo = 24692; // Port number for high-speed communication
|
||||
bool isopen = false;
|
||||
int errCode;
|
||||
|
||||
LJX8IF_ETHERNET_CONFIG EthernetConfig;
|
||||
|
||||
QString camera_name; // 相机名称
|
||||
int recontimeout_ms = 3000;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
Q_DECL_EXPORT Hd_CameraModule_3DKeyence* create();
|
||||
Q_DECL_EXPORT void destory(Hd_CameraModule_3DKeyence* ptr);
|
||||
}
|
||||
|
||||
#endif // HD_MVCAMERA_MODULE_H
|
||||
@@ -1,3 +0,0 @@
|
||||
基恩士3D相机
|
||||
初始化格式 IP#DEVICE-ID(手动按照初始化的顺序从0开始递增)#图像宽(X)#图像高(Y)#取图次数#超时时间
|
||||
192.168.31.1#0#3200#850#1#1000
|
||||
@@ -15,7 +15,9 @@ enum triggerModeEnum {
|
||||
HARDWARE,
|
||||
EMPTY
|
||||
};
|
||||
statusEnum cameraStatus = DISCONNECTED;
|
||||
std::atomic<statusEnum> cameraStatus(DISCONNECTED);
|
||||
std::atomic<bool> reconnecting(false);
|
||||
std::mutex handleMutex;
|
||||
triggerModeEnum triggerMode = HARDWARE;
|
||||
int getImageTimeOut = 3000;
|
||||
bool runFlag = true;
|
||||
@@ -77,11 +79,14 @@ bool connectDevice()
|
||||
lastError = "找不到相机" + QString::fromStdString(Username);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(handleMutex);
|
||||
if (handle != NULL)
|
||||
{
|
||||
MV_CC_StopGrabbing(handle);
|
||||
MV_CC_CloseDevice(handle);
|
||||
MV_CC_DestroyHandle(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
//打开相机
|
||||
@@ -111,7 +116,7 @@ bool connectDevice()
|
||||
if (MV_OK != nRet)return false;
|
||||
|
||||
MV_CC_StartGrabbing(handle);
|
||||
cameraStatus = CONNECTED;
|
||||
cameraStatus.store(CONNECTED);
|
||||
return true;
|
||||
}
|
||||
void SetExposureTime(float exposureValue)
|
||||
@@ -133,27 +138,42 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser){
|
||||
|
||||
qDebug() << "[Error] " << " MV camera disconnects!";
|
||||
|
||||
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus == CONNECTED){
|
||||
|
||||
cameraStatus = RECONNECTING;
|
||||
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus.load() == CONNECTED){
|
||||
|
||||
// 防止重复启动重连线程
|
||||
bool expected = false;
|
||||
if (!reconnecting.compare_exchange_strong(expected, true)) {
|
||||
qDebug() << "[Warning] Reconnect already in progress, skipping duplicate request";
|
||||
return;
|
||||
}
|
||||
|
||||
cameraStatus.store(RECONNECTING);
|
||||
// 启动后台线程负责重连,避免在回调线程中长时间阻塞
|
||||
std::thread([]() {
|
||||
qDebug() << "[Info] start reconnect thread";
|
||||
qDebug() << QString::fromStdString(Username) << " start reconnect thread";
|
||||
|
||||
// 确保设备资源关闭
|
||||
CloseDevice();
|
||||
int times = 0;
|
||||
while (runFlag)
|
||||
{
|
||||
qDebug() << "[Info] reconnect times:" << times++;
|
||||
qDebug() << QString::fromStdString(Username) << " reconnect attempt:" << times++;
|
||||
if (connectDevice())
|
||||
{
|
||||
qWarning() << "[Hd_CameraModule_HIK] reconnect success!";
|
||||
cameraStatus = CONNECTED;
|
||||
qWarning() << QString::fromStdString(Username) << " reconnect success!";
|
||||
cameraStatus.store(CONNECTED);
|
||||
reconnecting.store(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 1 seconds before retry...";
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
// 如果runFlag为false,线程退出
|
||||
qDebug() << "[Info] reconnect thread stopped (runFlag=false)";
|
||||
cameraStatus.store(DISCONNECTED);
|
||||
reconnecting.store(false);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
@@ -234,21 +254,43 @@ void __stdcall ImageCallBackEx(unsigned char* pData0, MV_FRAME_OUT_INFO_EX* pFra
|
||||
//关闭设备
|
||||
void CloseDevice()
|
||||
{
|
||||
|
||||
std::lock_guard<std::mutex> lock(handleMutex);
|
||||
|
||||
// 如果 handle 已经为空,直接返回
|
||||
if (handle == nullptr)
|
||||
return;
|
||||
|
||||
// 使用 SDK 正确的停止/关闭/销毁流程,避免使用 CloseHandle 等不匹配的 API
|
||||
MV_CC_StopGrabbing(handle);
|
||||
MV_CC_CloseDevice(handle);
|
||||
MV_CC_DestroyHandle(handle);
|
||||
int nRet = MV_CC_StopGrabbing(handle);
|
||||
if (MV_OK != nRet) {
|
||||
qDebug() << "[Warning] MV_CC_StopGrabbing failed, nRet=" << nRet;
|
||||
}
|
||||
|
||||
nRet = MV_CC_CloseDevice(handle);
|
||||
if (MV_OK != nRet) {
|
||||
qDebug() << "[Warning] MV_CC_CloseDevice failed, nRet=" << nRet;
|
||||
}
|
||||
|
||||
nRet = MV_CC_DestroyHandle(handle);
|
||||
if (MV_OK != nRet) {
|
||||
qDebug() << "[Warning] MV_CC_DestroyHandle failed, nRet=" << nRet;
|
||||
}
|
||||
|
||||
handle = nullptr;
|
||||
}
|
||||
|
||||
Hd_CameraModule_HIK_General::~Hd_CameraModule_HIK_General()
|
||||
{
|
||||
runFlag = false;
|
||||
|
||||
// 等待重连线程结束
|
||||
int waitCount = 0;
|
||||
while (reconnecting.load() && waitCount < 50) { // 最多等待5秒
|
||||
qDebug() << "[Info] Waiting for reconnect thread to finish...";
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
waitCount++;
|
||||
}
|
||||
|
||||
CloseDevice();
|
||||
if (n_mutex)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,9 @@ enum triggerModeEnum {
|
||||
HARDWARE,
|
||||
EMPTY
|
||||
};
|
||||
statusEnum cameraStatus = DISCONNECTED;
|
||||
std::atomic<statusEnum> cameraStatus(DISCONNECTED);
|
||||
std::atomic<bool> reconnecting(false);
|
||||
std::mutex handleMutex;
|
||||
triggerModeEnum triggerMode = HARDWARE;
|
||||
int getImageTimeOut = 3000;
|
||||
bool runFlag = true;
|
||||
@@ -90,8 +92,9 @@ bool connectDevice()
|
||||
if (handle != NULL)
|
||||
{
|
||||
MV_CC_StopGrabbing(handle);
|
||||
MV_CC_CloseDevice(handle);
|
||||
MV_CC_DestroyHandle(handle);
|
||||
handle = NULL;
|
||||
//MV_CC_CloseDevice(handle);
|
||||
//MV_CC_DestroyHandle(handle);
|
||||
}
|
||||
|
||||
//打开相机
|
||||
@@ -113,6 +116,7 @@ bool connectDevice()
|
||||
if (MV_OK != nRet)
|
||||
return false;
|
||||
MV_CC_StartGrabbing(handle);
|
||||
cameraStatus.store(CONNECTED);
|
||||
return true;
|
||||
}
|
||||
void SetExposureTime(float exposureValue)
|
||||
@@ -133,27 +137,42 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser) {
|
||||
|
||||
qDebug() << "[Error] " << " MV camera disconnects!";
|
||||
|
||||
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus == CONNECTED) {
|
||||
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT && cameraStatus.load() == CONNECTED) {
|
||||
|
||||
cameraStatus = RECONNECTING;
|
||||
// 防止重复启动重连线程
|
||||
bool expected = false;
|
||||
if (!reconnecting.compare_exchange_strong(expected, true)) {
|
||||
qDebug() << "[Warning] Reconnect already in progress, skipping duplicate request";
|
||||
return;
|
||||
}
|
||||
|
||||
cameraStatus.store(RECONNECTING);
|
||||
// 启动后台线程负责重连,避免在回调线程中长时间阻塞
|
||||
std::thread([]() {
|
||||
qDebug() << "[Info] start reconnect thread";
|
||||
qDebug() << QString::fromStdString(Username) << " start reconnect thread";
|
||||
|
||||
// 确保设备资源关闭
|
||||
CloseDevice();
|
||||
int times = 0;
|
||||
while (runFlag)
|
||||
{
|
||||
qDebug() << "[Info] reconnect times:" << times++;
|
||||
qDebug() << QString::fromStdString(Username) << " reconnect attempt:" << times++;
|
||||
if (connectDevice())
|
||||
{
|
||||
qWarning() << "[Hd_CameraModule_HIK] reconnect success!";
|
||||
cameraStatus = CONNECTED;
|
||||
qWarning() << QString::fromStdString(Username) << " reconnect success!";
|
||||
cameraStatus.store(CONNECTED);
|
||||
reconnecting.store(false);
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << QString::fromStdString(Username) << " reconnect failed, waiting 1 seconds before retry...";
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
// 如果runFlag为false,线程退出
|
||||
qDebug() << "[Info] reconnect thread stopped (runFlag=false)";
|
||||
cameraStatus.store(DISCONNECTED);
|
||||
reconnecting.store(false);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
@@ -249,6 +268,7 @@ void CloseDevice()
|
||||
//MV_CC_CloseDevice(handle);
|
||||
//MV_CC_DestroyHandle(handle);
|
||||
}
|
||||
handle = NULL;
|
||||
//nRet = MV_CC_CloseDevice(handle);
|
||||
//nRet = MV_CC_DestroyHandle(handle);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user