04-05-2017 10:08 AM
I didnt know where to post this. I´m working with the OpenCV wrapper but my question is in regards to arrays so i thought Id post it here. I am working with machine vision to find contours in an image and from those find the minimum area rectangle from each contour.
I already did that and can pass the image from OpenCV .dll and .so into labview (In windows and LinuxRT respectively) now im trying to pass an array which has the largest size of the minarea rectangle but i havent been able to. I just need to pass a 1D array from C++ to labview. Would anyone help me? or point me to the right direction?
04-05-2017 12:26 PM
What have you already tried? What is the prototype (set of parameters) for the C++ function you're trying to call? Can you share the LabVIEW code that generates the array? Passing an array to a library function is straightforward using the Call Library Function Node; usually you want to configure the array to be passed as an array data pointer.
Note that LabVIEW can't handle C++ directly, so you need to define the function as a C export function before you compile the library, or you need to write a C wrapper library for the C++ library that provides access to the functions you want to call.
04-05-2017 12:59 PM - edited 04-05-2017 01:12 PM
Im working with a wrapper made for opencv, which can be downloaded through VIPM. I have been looking at the examples, but I dont really understand them. Im very new with this.
here is some example code that passes an array of typedef struc to labview.
//precompiled header #ifdef USE_PRECOMPILED_HEADER #include "stdafx.h" #endif #include <vector> #include <opencv2/features2d.hpp> #include <opencv2/objdetect.hpp> #include <opencv2/calib3d.hpp> #include <opencv2/opencv.hpp> #include <opencv2/core/core.hpp> #include <NIVisionExtLib.h> #include "..\NiVisionOpenCVExamples.h" using namespace std; using namespace cv; typedef cv::Point2f PointFloat; typedef cv::Point2d PointDouble; //Keep the classifier as static so that it does not have to load for every image static CascadeClassifier faceCascadeClsfr; static CascadeClassifier eyesCascadeClsfr; static bool bEyeClassifierLoaded = false; void Convert(const Rect& rect, LV_Rect& lvRect){ lvRect.left = rect.x; lvRect.top = rect.y; lvRect.right = rect.x + rect.width - 1; lvRect.bottom = rect.y + rect.height - 1; lvRect.angle = 0; } EXTERN_C void NI_EXPORT NIVisOpenCV_DetectFaces(NIImageHandle sourceHandle, const char* faceCascadePath, const char* eyesCascadePath, NIArrayHandle facesRectLV, NIArrayHandle eyesRectLV, NIErrorHandle errorHandle){ NIERROR error = NI_ERR_SUCCESS; ReturnOnPreviousError(errorHandle); try{ NIImage source(sourceHandle); NIArray1D<LV_Rect> facesRect(facesRectLV); NIArray1D<LV_Rect> eyesRect(eyesRectLV); //Load the face cascase classifier String faceCascadeString = faceCascadePath; String eyesCasCadeString = eyesCascadePath; if (faceCascadeClsfr.empty()) { if (!faceCascadeClsfr.load(faceCascadeString)) { return; } } //load eye cascade classifier // Eye classifier is optional if(eyesCascadePath != NULL && eyesCasCadeString.length() > 1) if (eyesCascadeClsfr.empty()) { if (eyesCascadeClsfr.load(eyesCasCadeString)) { bEyeClassifierLoaded = true; } } //Do image conversions vector<Rect> faces; vector<Rect> eyes; vector<LV_Rect> facesLV; vector<LV_Rect> eyesLV; Mat sourceMat; Mat faceImage; ThrowNIError(source.ImageToMat(sourceMat)); Mat matGray; int maxWidth = matGray.rows / 2; int minWidth = 15; if (sourceMat.type() != CV_8UC1) { cvtColor(sourceMat, matGray, COLOR_BGR2GRAY); } else { matGray = sourceMat.clone(); } //Equalize image equalizeHist(matGray, matGray); //Detect faces faceCascadeClsfr.detectMultiScale(matGray, faces, 1.5, 2, 0 | CASCADE_SCALE_IMAGE, Size(minWidth, minWidth), Size(maxWidth, maxWidth)); facesLV.resize(faces.size()); vector<LV_Rect>::iterator fLV = facesLV.begin(); if (faces.size()) { for (vector<Rect>::iterator f = faces.begin(); f != faces.end(); f++) { Convert(*f, *fLV++); if (minWidth > f->width) { minWidth = f->width; } if (maxWidth < f->width) { maxWidth = f->width; } } minWidth = static_cast<int>(minWidth * 0.8); maxWidth = static_cast<int>(maxWidth * 1.2); } else { minWidth = 15; maxWidth = matGray.rows/4; } facesRect.SetArray(facesLV); //Detect eyes for each faces if (bEyeClassifierLoaded) { for (vector<Rect>::iterator f = faces.begin(); f != faces.end(); f++) { faceImage = matGray(*f); eyesCascadeClsfr.detectMultiScale(faceImage, eyes, 2, 2, 0 //|CASCADE_FIND_BIGGEST_OBJECT | CASCADE_DO_ROUGH_SEARCH //|CASCADE_DO_CANNY_PRUNING | CASCADE_SCALE_IMAGE , Size(30, 30)); for (vector<Rect>::iterator e = eyes.begin(); e != eyes.end(); e++) { LV_Rect temp; Convert(*e, temp); temp.top += f->y; temp.left += f->x; temp.bottom += f->y; temp.right += f->x; eyesLV.push_back(temp); } } } eyesRect.SetArray(eyesLV); } catch (NIERROR _err){ error = _err; } catch (...){ error = NI_ERR_OCV_USER; } ProcessNIError(error, errorHandle); }
Whats weird to me is that they are using a vector. I just want to pass an array of no more than 600 floats. The problem is that the number changes with every image processed. The array could be 600, or 300 or 200 etc... But never more than 600. I thought of initializing a larger array into the call library node with lets say 1000 zeros, process the image and then get rid of the extra zeros at the end, but I dont know if that is possible.
The Wrapper for OpenCV states that it was made to also handle arrays as well as images. But i cant find an example for it so Im stuck since Im new to this.
04-05-2017 05:43 PM
I can't tell what you're trying to do from the code you posted. Are you trying to call a function that you will write? The example you provided does some fancy work to handle an array of LabVIEW clusters, but you don't need to do that if you simply want to pass an array of floating point values. The C++ code you posted is not a good starting point - it's elegant for what it does, but it's not a good example of passing a simple array to a DLL.
Again, it would be a lot easier if you post an example of the function you're trying to call, rather than a completely different one. If you're asking both how to write the function in C, and also how to call it from LabVIEW, then at least provide a rough idea of what parameters that function should accept.
For a variable-size array, it's common to pass a pointer to the first element of the array (this is what LabVIEW does when you configure a parameter to be passed by Array Data Pointer) and also a separate parameter indicating the array size.
04-06-2017 01:46 PM
I realized that what I posted was much more than what I needed. I was able to figure it out though. I used the same wrapper and did this.
EXTERN_C void NI_EXPORT NIVisOpenCV_Array(NIArrayHandle arrayHandle, NIErrorHandle errorHandle) { NIArray1D<float> arrayLV(arrayHandle); float array[5] = {5,4,3,2,1}; float *ptr; ptr = array; arrayLV.SetArray(ptr, 5); }
That was enough xD haha.
I included that in my code and i can pass the C++ array along with the processed image.
Thank you very much though.