diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8b8f2d5..5a03e25 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -109,7 +109,8 @@ "Bash(grep -rn \"catch.*cv::Exception\" 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 -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\\)$\")" ] } } diff --git a/core/ANSLicensingSystem/ANSLicense.h b/core/ANSLicensingSystem/ANSLicense.h index b55fbf1..7497409 100644 --- a/core/ANSLicensingSystem/ANSLicense.h +++ b/core/ANSLicensingSystem/ANSLicense.h @@ -8,7 +8,7 @@ // Set to 0 for production builds to eliminate all debug output overhead. // ============================================================================ #ifndef ANSCORE_DEBUGVIEW -#define ANSCORE_DEBUGVIEW 1 // 1 = enabled (debug), 0 = disabled (production) +#define ANSCORE_DEBUGVIEW 0 // 1 = enabled (debug), 0 = disabled (production) #endif // ANS_DBG: Debug logging macro for DebugView (OutputDebugStringA on Windows). diff --git a/modules/ANSCV/ANSOpenCV.cpp b/modules/ANSCV/ANSOpenCV.cpp index 7479fcc..7f56497 100644 --- a/modules/ANSCV/ANSOpenCV.cpp +++ b/modules/ANSCV/ANSOpenCV.cpp @@ -1,5 +1,6 @@ #include "ANSOpenCV.h" #include "ANSMatRegistry.h" +#include #include #include #include @@ -5103,4 +5104,131 @@ extern "C" __declspec(dllexport) int ANSCV_AddSpeckleNoise_V2(uint64_t handleVal else return 0; } catch (...) { return -1; } +} + +// ── IMAQ <-> cv::Mat conversion ────────────────────────────────── + +extern "C" __declspec(dllexport) int ANSCV_IMAQ2Image(Image* imaqImage, cv::Mat** imageOut) { + try { + if (!imaqImage || !imageOut) return -2; + + ImageInfo info; + if (!imaqGetImageInfo(imaqImage, &info)) return -4; + if (!info.imageStart || info.xRes <= 0 || info.yRes <= 0) return -2; + + int width = info.xRes; + int height = info.yRes; + int stride = info.pixelsPerLine; // pixels per row (may include padding) + + 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 + } + + *imageOut = anscv_mat_new(result); + return 1; + } + catch (const std::exception& e) { + std::cerr << "Error in ANSCV_IMAQ2Image: " << e.what() << std::endl; + return -3; + } + catch (...) { return -1; } +} + +extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, Image* imaqImage) { + try { + if (!imageIn || !(*imageIn) || (*imageIn)->empty() || !imaqImage) return -2; + + const cv::Mat& mat = **imageIn; + int width = mat.cols; + int height = mat.rows; + + // Set the IMAQ image size (allocates pixel buffer) + if (!imaqSetImageSize(imaqImage, width, height)) return -4; + + ImageInfo info; + if (!imaqGetImageInfo(imaqImage, &info)) return -4; + if (!info.imageStart) return -4; + + int dstStride = info.pixelsPerLine; + + switch (mat.type()) { + case CV_8UC1: { + // Grayscale -> IMAQ_IMAGE_U8 + for (int y = 0; y < height; y++) { + memcpy(static_cast(info.imageStart) + y * dstStride, + mat.ptr(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(info.imageStart) + y * dstStride * sizeof(unsigned short), + mat.ptr(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(info.imageStart) + y * dstStride * sizeof(RGBValue), + bgra.ptr(y), width * sizeof(RGBValue)); + } + break; + } + case CV_8UC4: { + // BGRA -> IMAQ_IMAGE_RGB directly + for (int y = 0; y < height; y++) { + memcpy(static_cast(info.imageStart) + y * dstStride * sizeof(RGBValue), + mat.ptr(y), width * sizeof(RGBValue)); + } + break; + } + case CV_32FC1: { + // Float -> IMAQ_IMAGE_SGL + for (int y = 0; y < height; y++) { + memcpy(static_cast(info.imageStart) + y * dstStride * sizeof(float), + mat.ptr(y), width * sizeof(float)); + } + break; + } + default: + return -5; // Unsupported cv::Mat type + } + + return 1; + } + catch (const std::exception& e) { + std::cerr << "Error in ANSCV_Image2IMAQ: " << e.what() << std::endl; + return -3; + } + catch (...) { return -1; } } \ No newline at end of file diff --git a/modules/ANSCV/ANSOpenCV.h b/modules/ANSCV/ANSOpenCV.h index 0fc277a..006c399 100644 --- a/modules/ANSCV/ANSOpenCV.h +++ b/modules/ANSCV/ANSOpenCV.h @@ -7,6 +7,12 @@ #include #include +// Forward declaration for NI Vision IMAQ Image (avoids nivision.h dependency for consumers) +#ifndef NI_IMAGE_TYPE_DEF + #define NI_IMAGE_TYPE_DEF + typedef struct Image_struct Image; +#endif + #define MUTEX_TIMEOUT_MS 45000 namespace fs = std::filesystem; namespace ANSCENTER @@ -161,4 +167,8 @@ 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); +// IMAQ <-> cv::Mat conversion functions +extern "C" __declspec(dllexport) int ANSCV_IMAQ2Image(Image* imaqImage, cv::Mat** imageOut); +extern "C" __declspec(dllexport) int ANSCV_Image2IMAQ(cv::Mat** imageIn, Image* imaqImage); + #endif \ No newline at end of file diff --git a/modules/ANSCV/CMakeLists.txt b/modules/ANSCV/CMakeLists.txt index a46cd4d..bf1458f 100644 --- a/modules/ANSCV/CMakeLists.txt +++ b/modules/ANSCV/CMakeLists.txt @@ -45,6 +45,15 @@ target_include_directories(ANSCV PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) +# NI Vision (IMAQ) support +target_include_directories(ANSCV PRIVATE + "C:/Program Files (x86)/National Instruments/Shared/ExternalCompilerSupport/C/include" +) +target_link_directories(ANSCV PRIVATE + "C:/Program Files (x86)/National Instruments/Shared/ExternalCompilerSupport/C/lib64/msvc" +) +target_link_libraries(ANSCV PRIVATE nivision) + # MediaClient includes (referenced from original ANLS) target_include_directories(ANSCV PRIVATE ${CMAKE_SOURCE_DIR}/MediaClient diff --git a/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp b/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp index f51deb8..cee072b 100644 --- a/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp +++ b/tests/ANSLPR-UnitTest/ANSLPR-UnitTest.cpp @@ -3656,7 +3656,7 @@ int ALPR_OCR_Test() { ANSCENTER::ANSALPR* infHandle = nullptr; std::string licenseKey = ""; std::string modelFilePath = "C:\\Projects\\ANSVIS\\Models\\ANS_GenericALPR_v2.0.zip"; - std::string imagePath = "C:\\Programs\\ModelTraining\\JLPD\\data\\test7.jpg"; + std::string imagePath = "C:\\Programs\\ModelTraining\\JLPD\\data\\test3.jpg"; int engineType = 2; // ANSALPR_OCR double detectionThreshold = 0.3;