Add support to IMAQ conversion

This commit is contained in:
2026-04-13 10:39:26 +10:00
parent 749c7db3c6
commit 3a4320f253
3 changed files with 156 additions and 64 deletions

View File

@@ -5108,127 +5108,200 @@ extern "C" __declspec(dllexport) int ANSCV_AddSpeckleNoise_V2(uint64_t handleVal
// ── 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 {
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;
if (!imaqGetImageInfo(imaqImage, &info)) return -4;
if (!info.imageStart || info.xRes <= 0 || info.yRes <= 0) return -2;
// Try as Image* first (direct pointer)
Image* imaqImage = static_cast<Image*>(imaqHandle);
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 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;
switch (info.imageType) {
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));
result = wrapper.clone();
break;
}
case IMAQ_IMAGE_U16: {
// 16-bit grayscale
cv::Mat wrapper(height, width, CV_16UC1, info.imageStart, stride * sizeof(unsigned short));
result = wrapper.clone();
break;
}
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::cvtColor(bgra, result, cv::COLOR_BGRA2BGR);
break;
}
case IMAQ_IMAGE_SGL: {
// 32-bit float grayscale
cv::Mat wrapper(height, width, CV_32FC1, info.imageStart, stride * sizeof(float));
result = wrapper.clone();
break;
}
default:
return -5; // Unsupported image type
ANS_DBG("ANSCV", "IMAQ2Image: unsupported IMAQ type %d", info.imageType);
return -5;
}
*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;
}
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;
}
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 {
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;
int width = mat.cols;
int height = mat.rows;
ANS_DBG("ANSCV", "Image2IMAQ: Mat=%p (%dx%d type=%d)",
(void*)*imageIn, mat.cols, mat.rows, mat.type());
// Set the IMAQ image size (allocates pixel buffer)
if (!imaqSetImageSize(imaqImage, width, height)) return -4;
// Encode as lossless PNG
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;
if (!imaqGetImageInfo(imaqImage, &info)) return -4;
if (!info.imageStart) return -4;
int size = static_cast<int>(buf.size());
MgErr error = DSSetHandleSize(outputImage, sizeof(int32) + size * sizeof(uChar));
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()) {
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: {
// BGR -> IMAQ_IMAGE_RGB (BGRA with alpha=0)
cv::Mat bgra;
cv::cvtColor(mat, bgra, cv::COLOR_BGR2BGRA);
for (int y = 0; y < height; y++) {
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(RGBValue),
bgra.ptr<unsigned char>(y), width * sizeof(RGBValue));
}
// Force alpha to 0 (cvtColor may set it to 255)
std::vector<cv::Mat> ch;
cv::split(bgra, ch);
ch[3].setTo(0);
cv::merge(ch, bgra);
break;
}
case CV_8UC4: {
// BGRA -> IMAQ_IMAGE_RGB directly
for (int y = 0; y < height; y++) {
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(RGBValue),
mat.ptr<unsigned char>(y), width * sizeof(RGBValue));
}
bgra = mat.clone();
// Force alpha to 0 for IMAQ
std::vector<cv::Mat> ch;
cv::split(bgra, ch);
ch[3].setTo(0);
cv::merge(ch, bgra);
break;
}
case CV_32FC1: {
// Float -> IMAQ_IMAGE_SGL
for (int y = 0; y < height; y++) {
memcpy(static_cast<unsigned char*>(info.imageStart) + y * dstStride * sizeof(float),
mat.ptr<float>(y), width * sizeof(float));
}
case CV_8UC1:
cv::cvtColor(mat, bgra, cv::COLOR_GRAY2BGRA);
// cvtColor sets alpha to 0, which is correct for IMAQ
break;
}
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;
}
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;
}
catch (...) { return -1; }
catch (...) {
ANS_DBG("ANSCV", "ImageToArray: UNKNOWN EXCEPTION");
return -1;
}
}