Add support to IMAQ conversion
This commit is contained in:
@@ -110,7 +110,18 @@
|
|||||||
"Bash(grep -l \"ANS_DBG\" modules/ANSLPR/*.cpp modules/ANSCV/*.cpp modules/ANSODEngine/*.cpp)",
|
"Bash(grep -l \"ANS_DBG\" modules/ANSLPR/*.cpp modules/ANSCV/*.cpp modules/ANSODEngine/*.cpp)",
|
||||||
"Bash(grep -h \"ANS_DBG\\(\\\\\"\" modules/ANSLPR/*.cpp modules/ANSCV/ANSRTSP.cpp modules/ANSODEngine/ANSONNXYOLO.cpp modules/ANSODEngine/ANSRTYOLO.cpp modules/ANSODEngine/NV12PreprocessHelper.cpp)",
|
"Bash(grep -h \"ANS_DBG\\(\\\\\"\" modules/ANSLPR/*.cpp modules/ANSCV/ANSRTSP.cpp modules/ANSODEngine/ANSONNXYOLO.cpp modules/ANSODEngine/ANSRTYOLO.cpp modules/ANSODEngine/NV12PreprocessHelper.cpp)",
|
||||||
"Bash(grep -v \"DNError\\\\|ViewerConfigPath\\\\|Failed to get\\\\|RecursiveDirectory\\\\|qt.qpa\\\\|DispBroker\\\\|SyncInvokeTable\\\\|Created new AppDomain\\\\|Destroying AppDomain\\\\|Trace Start\\\\|ExpandNode\\\\|PublisherMetadata\\\\|at System\\\\.\\\\|at NationalInstruments\\\\|at Mscorlib\\\\|Parameter name\\\\|^[[:space:]]*$\\\\|ArgumentException\\\\|Wrong type\\\\|Concerning target\\\\|Unable to get\\\\|RenderEventToBuffer\\\\|Getting next\\\\|Fetching Next\\\\|Image.Dispose\\\\|Graphics.Dispose\\\\|Image.FromStream\\\\|Inner Exception\\\\|FontFamily\\\\|InitHash\\\\|get_Item\\\\|MethodHandle.InvokeMethod\\\\|RuntimeMethodInfo\\\\|TargetInvocationException\\\\|Hashtable\\\\|LookupControl\\\\|RemoveControl\\\\|CloseInstance\\\\|FreeInstance\\\\|CrossDomainServer\" \"C:/Users/nghia/Downloads/AVNET-8845HS1.log\")",
|
"Bash(grep -v \"DNError\\\\|ViewerConfigPath\\\\|Failed to get\\\\|RecursiveDirectory\\\\|qt.qpa\\\\|DispBroker\\\\|SyncInvokeTable\\\\|Created new AppDomain\\\\|Destroying AppDomain\\\\|Trace Start\\\\|ExpandNode\\\\|PublisherMetadata\\\\|at System\\\\.\\\\|at NationalInstruments\\\\|at Mscorlib\\\\|Parameter name\\\\|^[[:space:]]*$\\\\|ArgumentException\\\\|Wrong type\\\\|Concerning target\\\\|Unable to get\\\\|RenderEventToBuffer\\\\|Getting next\\\\|Fetching Next\\\\|Image.Dispose\\\\|Graphics.Dispose\\\\|Image.FromStream\\\\|Inner Exception\\\\|FontFamily\\\\|InitHash\\\\|get_Item\\\\|MethodHandle.InvokeMethod\\\\|RuntimeMethodInfo\\\\|TargetInvocationException\\\\|Hashtable\\\\|LookupControl\\\\|RemoveControl\\\\|CloseInstance\\\\|FreeInstance\\\\|CrossDomainServer\" \"C:/Users/nghia/Downloads/AVNET-8845HS1.log\")",
|
||||||
"Bash(grep -E \"\\\\.\\(h|cpp\\)$\")"
|
"Bash(grep -E \"\\\\.\\(h|cpp\\)$\")",
|
||||||
|
"WebSearch",
|
||||||
|
"WebFetch(domain:forums.ni.com)",
|
||||||
|
"WebFetch(domain:www.ni.com)",
|
||||||
|
"WebFetch(domain:lavag.org)",
|
||||||
|
"Read(//c/ProgramData/**)",
|
||||||
|
"Read(//c/Users/nghia/**)",
|
||||||
|
"Bash(dir /s /b \"C:\\\\Program Files\\\\National Instruments\\\\*NIImage*\" \"C:\\\\Program Files\\\\National Instruments\\\\*OpenCV*\")",
|
||||||
|
"Bash(dir /s /b \"C:\\\\Program Files \\(x86\\)\\\\National Instruments\\\\Vision\\\\*OpenCV*\")",
|
||||||
|
"Bash(dir /s /b \"C:\\\\Program Files \\(x86\\)\\\\National Instruments\\\\Vision\\\\Help\\\\*\")",
|
||||||
|
"Bash(findstr /i \"opencv\")",
|
||||||
|
"WebFetch(domain:documentation.help)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5108,127 +5108,200 @@ extern "C" __declspec(dllexport) int ANSCV_AddSpeckleNoise_V2(uint64_t handleVal
|
|||||||
|
|
||||||
// ── IMAQ <-> cv::Mat conversion ──────────────────────────────────
|
// ── IMAQ <-> cv::Mat conversion ──────────────────────────────────
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) int ANSCV_IMAQ2Image(Image* imaqImage, cv::Mat** imageOut) {
|
extern "C" __declspec(dllexport) int ANSCV_IMAQ2Image(void* imaqHandle, cv::Mat** imageOut) {
|
||||||
try {
|
try {
|
||||||
if (!imaqImage || !imageOut) return -2;
|
if (!imaqHandle || !imageOut) {
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: null pointer - imaqHandle=%p imageOut=%p", imaqHandle, (void*)imageOut);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
ImageInfo info;
|
// Try as Image* first (direct pointer)
|
||||||
if (!imaqGetImageInfo(imaqImage, &info)) return -4;
|
Image* imaqImage = static_cast<Image*>(imaqHandle);
|
||||||
if (!info.imageStart || info.xRes <= 0 || info.yRes <= 0) return -2;
|
ImageInfo info = {};
|
||||||
|
if (!imaqGetImageInfo(imaqImage, &info)) {
|
||||||
|
// Try as Image** (pointer-to-pointer, LabVIEW handle indirection)
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: Image* failed (err=%d), trying Image**", imaqGetLastError());
|
||||||
|
Image** imaqImagePtr = static_cast<Image**>(imaqHandle);
|
||||||
|
imaqImage = *imaqImagePtr;
|
||||||
|
if (!imaqImage || !imaqGetImageInfo(imaqImage, &info)) {
|
||||||
|
int errCode = imaqGetLastError();
|
||||||
|
const char* errFunc = imaqGetLastErrorFunc();
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: FAILED both Image* and Image** - err=%d func=%s",
|
||||||
|
errCode, errFunc ? errFunc : "unknown");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: resolved as Image** OK");
|
||||||
|
} else {
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: resolved as Image* OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.imageStart || info.xRes <= 0 || info.yRes <= 0) {
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: invalid image - start=%p xRes=%d yRes=%d",
|
||||||
|
info.imageStart, info.xRes, info.yRes);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
int width = info.xRes;
|
int width = info.xRes;
|
||||||
int height = info.yRes;
|
int height = info.yRes;
|
||||||
int stride = info.pixelsPerLine; // pixels per row (may include padding)
|
int stride = info.pixelsPerLine;
|
||||||
|
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: %dx%d stride=%d type=%d", width, height, stride, info.imageType);
|
||||||
|
|
||||||
cv::Mat result;
|
cv::Mat result;
|
||||||
switch (info.imageType) {
|
switch (info.imageType) {
|
||||||
case IMAQ_IMAGE_U8: {
|
case IMAQ_IMAGE_U8: {
|
||||||
// 8-bit grayscale: stride is in pixels = bytes
|
|
||||||
cv::Mat wrapper(height, width, CV_8UC1, info.imageStart, stride * sizeof(unsigned char));
|
cv::Mat wrapper(height, width, CV_8UC1, info.imageStart, stride * sizeof(unsigned char));
|
||||||
result = wrapper.clone();
|
result = wrapper.clone();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAQ_IMAGE_U16: {
|
case IMAQ_IMAGE_U16: {
|
||||||
// 16-bit grayscale
|
|
||||||
cv::Mat wrapper(height, width, CV_16UC1, info.imageStart, stride * sizeof(unsigned short));
|
cv::Mat wrapper(height, width, CV_16UC1, info.imageStart, stride * sizeof(unsigned short));
|
||||||
result = wrapper.clone();
|
result = wrapper.clone();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAQ_IMAGE_RGB: {
|
case IMAQ_IMAGE_RGB: {
|
||||||
// IMAQ RGB is 32-bit RGBX (RGBValue: B,G,R,alpha) — same layout as BGRA
|
|
||||||
cv::Mat bgra(height, width, CV_8UC4, info.imageStart, stride * sizeof(RGBValue));
|
cv::Mat bgra(height, width, CV_8UC4, info.imageStart, stride * sizeof(RGBValue));
|
||||||
cv::cvtColor(bgra, result, cv::COLOR_BGRA2BGR);
|
cv::cvtColor(bgra, result, cv::COLOR_BGRA2BGR);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IMAQ_IMAGE_SGL: {
|
case IMAQ_IMAGE_SGL: {
|
||||||
// 32-bit float grayscale
|
|
||||||
cv::Mat wrapper(height, width, CV_32FC1, info.imageStart, stride * sizeof(float));
|
cv::Mat wrapper(height, width, CV_32FC1, info.imageStart, stride * sizeof(float));
|
||||||
result = wrapper.clone();
|
result = wrapper.clone();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return -5; // Unsupported image type
|
ANS_DBG("ANSCV", "IMAQ2Image: unsupported IMAQ type %d", info.imageType);
|
||||||
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
*imageOut = anscv_mat_new(result);
|
*imageOut = anscv_mat_new(result);
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: SUCCESS - Mat=%p %dx%d type=%d",
|
||||||
|
(void*)*imageOut, result.cols, result.rows, result.type());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
std::cerr << "Error in ANSCV_IMAQ2Image: " << e.what() << std::endl;
|
ANS_DBG("ANSCV", "IMAQ2Image: EXCEPTION - %s", e.what());
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
catch (...) { return -1; }
|
catch (...) {
|
||||||
|
ANS_DBG("ANSCV", "IMAQ2Image: UNKNOWN EXCEPTION");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, Image* imaqImage) {
|
extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, LStrHandle outputImage) {
|
||||||
try {
|
try {
|
||||||
if (!imageIn || !(*imageIn) || (*imageIn)->empty() || !imaqImage) return -2;
|
if (!imageIn || !(*imageIn) || (*imageIn)->empty() || !outputImage) {
|
||||||
|
ANS_DBG("ANSCV", "Image2IMAQ: null input - imageIn=%p outputImage=%p",
|
||||||
|
(void*)imageIn, (void*)outputImage);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
const cv::Mat& mat = **imageIn;
|
const cv::Mat& mat = **imageIn;
|
||||||
int width = mat.cols;
|
ANS_DBG("ANSCV", "Image2IMAQ: Mat=%p (%dx%d type=%d)",
|
||||||
int height = mat.rows;
|
(void*)*imageIn, mat.cols, mat.rows, mat.type());
|
||||||
|
|
||||||
// Set the IMAQ image size (allocates pixel buffer)
|
// Encode as lossless PNG
|
||||||
if (!imaqSetImageSize(imaqImage, width, height)) return -4;
|
std::vector<unsigned char> buf;
|
||||||
|
std::vector<int> params = {cv::IMWRITE_PNG_COMPRESSION, 1};
|
||||||
|
if (!cv::imencode(".png", mat, buf, params)) {
|
||||||
|
ANS_DBG("ANSCV", "Image2IMAQ: imencode PNG failed");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
ImageInfo info;
|
int size = static_cast<int>(buf.size());
|
||||||
if (!imaqGetImageInfo(imaqImage, &info)) return -4;
|
MgErr error = DSSetHandleSize(outputImage, sizeof(int32) + size * sizeof(uChar));
|
||||||
if (!info.imageStart) return -4;
|
if (error != noErr) {
|
||||||
|
ANS_DBG("ANSCV", "Image2IMAQ: DSSetHandleSize failed - err=%d", error);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
(*outputImage)->cnt = size;
|
||||||
|
memcpy((*outputImage)->str, buf.data(), size);
|
||||||
|
|
||||||
int dstStride = info.pixelsPerLine;
|
ANS_DBG("ANSCV", "Image2IMAQ: SUCCESS - %d bytes PNG (%dx%d)", size, mat.cols, mat.rows);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
ANS_DBG("ANSCV", "Image2IMAQ: EXCEPTION - %s", e.what());
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
ANS_DBG("ANSCV", "Image2IMAQ: UNKNOWN EXCEPTION");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── cv::Mat -> LabVIEW 2D U32 array for IMAQ ArrayToColorImage VI ───
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) int ANSCV_ImageToArray(cv::Mat** imageIn, LVArray2D_U32Hdl arrayOut) {
|
||||||
|
// Outputs 2D U32 array (height x width), each U32 = packed XRGB
|
||||||
|
// Wire to IMAQ ArrayToColorImage "Image Pixels (U32)" input
|
||||||
|
try {
|
||||||
|
if (!imageIn || !(*imageIn) || (*imageIn)->empty() || !arrayOut) {
|
||||||
|
ANS_DBG("ANSCV", "ImageToArray: invalid input");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cv::Mat& mat = **imageIn;
|
||||||
|
int rows = mat.rows;
|
||||||
|
int cols = mat.cols;
|
||||||
|
ANS_DBG("ANSCV", "ImageToArray: Mat=%p (%dx%d type=%d)",
|
||||||
|
(void*)*imageIn, cols, rows, mat.type());
|
||||||
|
|
||||||
|
// Convert to BGRA with alpha=0 (IMAQ convention)
|
||||||
|
cv::Mat bgra;
|
||||||
switch (mat.type()) {
|
switch (mat.type()) {
|
||||||
case CV_8UC1: {
|
|
||||||
// Grayscale -> IMAQ_IMAGE_U8
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride,
|
|
||||||
mat.ptr<unsigned char>(y), width * sizeof(unsigned char));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CV_16UC1: {
|
|
||||||
// 16-bit grayscale -> IMAQ_IMAGE_U16
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(unsigned short),
|
|
||||||
mat.ptr<unsigned short>(y), width * sizeof(unsigned short));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CV_8UC3: {
|
case CV_8UC3: {
|
||||||
// BGR -> IMAQ_IMAGE_RGB (BGRA with alpha=0)
|
|
||||||
cv::Mat bgra;
|
|
||||||
cv::cvtColor(mat, bgra, cv::COLOR_BGR2BGRA);
|
cv::cvtColor(mat, bgra, cv::COLOR_BGR2BGRA);
|
||||||
for (int y = 0; y < height; y++) {
|
// Force alpha to 0 (cvtColor may set it to 255)
|
||||||
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(RGBValue),
|
std::vector<cv::Mat> ch;
|
||||||
bgra.ptr<unsigned char>(y), width * sizeof(RGBValue));
|
cv::split(bgra, ch);
|
||||||
}
|
ch[3].setTo(0);
|
||||||
|
cv::merge(ch, bgra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CV_8UC4: {
|
case CV_8UC4: {
|
||||||
// BGRA -> IMAQ_IMAGE_RGB directly
|
bgra = mat.clone();
|
||||||
for (int y = 0; y < height; y++) {
|
// Force alpha to 0 for IMAQ
|
||||||
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(RGBValue),
|
std::vector<cv::Mat> ch;
|
||||||
mat.ptr<unsigned char>(y), width * sizeof(RGBValue));
|
cv::split(bgra, ch);
|
||||||
}
|
ch[3].setTo(0);
|
||||||
|
cv::merge(ch, bgra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CV_32FC1: {
|
case CV_8UC1:
|
||||||
// Float -> IMAQ_IMAGE_SGL
|
cv::cvtColor(mat, bgra, cv::COLOR_GRAY2BGRA);
|
||||||
for (int y = 0; y < height; y++) {
|
// cvtColor sets alpha to 0, which is correct for IMAQ
|
||||||
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(float),
|
|
||||||
mat.ptr<float>(y), width * sizeof(float));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return -5; // Unsupported cv::Mat type
|
ANS_DBG("ANSCV", "ImageToArray: unsupported type %d", mat.type());
|
||||||
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int totalPixels = rows * cols;
|
||||||
|
|
||||||
|
// Resize LabVIEW 2D U32 array
|
||||||
|
MgErr err = NumericArrayResize(uL, 2, reinterpret_cast<UHandle*>(&arrayOut), totalPixels);
|
||||||
|
if (err != noErr) {
|
||||||
|
ANS_DBG("ANSCV", "ImageToArray: NumericArrayResize failed - err=%d", err);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
(*arrayOut)->dimSizes[0] = rows;
|
||||||
|
(*arrayOut)->dimSizes[1] = cols;
|
||||||
|
|
||||||
|
// IMAQ RGBValue layout is {B, G, R, alpha} which is the same memory layout as BGRA
|
||||||
|
// Copy directly — each 4 bytes of BGRA = one U32 in the array
|
||||||
|
memcpy((*arrayOut)->elt, bgra.data, totalPixels * sizeof(uInt32));
|
||||||
|
|
||||||
|
ANS_DBG("ANSCV", "ImageToArray: SUCCESS - %dx%d (%d pixels)", cols, rows, totalPixels);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
std::cerr << "Error in ANSCV_Image2IMAQ: " << e.what() << std::endl;
|
ANS_DBG("ANSCV", "ImageToArray: EXCEPTION - %s", e.what());
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
catch (...) { return -1; }
|
catch (...) {
|
||||||
|
ANS_DBG("ANSCV", "ImageToArray: UNKNOWN EXCEPTION");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -167,8 +167,16 @@ extern "C" __declspec(dllexport) int ANSCV_ImagePatternMatchs_S(cv::Mat** image
|
|||||||
|
|
||||||
extern "C" __declspec(dllexport) int ANSCV_ImagesToMP4_S(const char* imageFolder, const char* outputVideoPath, int targetDurationSec);
|
extern "C" __declspec(dllexport) int ANSCV_ImagesToMP4_S(const char* imageFolder, const char* outputVideoPath, int targetDurationSec);
|
||||||
|
|
||||||
// IMAQ <-> cv::Mat conversion functions
|
// IMAQ -> cv::Mat conversion (NI Vision Image*, auto-detects indirection level)
|
||||||
extern "C" __declspec(dllexport) int ANSCV_IMAQ2Image(Image* imaqImage, cv::Mat** imageOut);
|
extern "C" __declspec(dllexport) int ANSCV_IMAQ2Image(void* imaqHandle, cv::Mat** imageOut);
|
||||||
extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, Image* imaqImage);
|
// cv::Mat -> IMAQ: outputs lossless PNG to LStrHandle, use IMAQ ReadFromString in LabVIEW
|
||||||
|
extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, LStrHandle outputImage);
|
||||||
|
|
||||||
|
// cv::Mat -> LabVIEW 2D U32 array for IMAQ ArrayToColorImage VI "Image Pixels (U32)"
|
||||||
|
typedef struct { int32 dimSizes[2]; uInt32 elt[1]; } LVArray2D_U32;
|
||||||
|
typedef LVArray2D_U32** LVArray2D_U32Hdl;
|
||||||
|
extern "C" __declspec(dllexport) int ANSCV_ImageToArray(cv::Mat** imageIn, LVArray2D_U32Hdl arrayOut);
|
||||||
|
// cv::Mat -> IMAQ via LStrHandle (lossless PNG)
|
||||||
|
extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, LStrHandle outputImage);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user