Machine Vision

cancel
Showing results for 
Search instead for 
Did you mean: 

Use Imaq in C dll to be called in LabVIEW

Solved!
Go to solution

I can't get this code to work:

int TestImage(Image *image)
{
    PixelValue    pixelValue;

    MessageBoxA(0, "Start", "Info", MB_OK);

    image = imaqCreateImage(IMAQ_IMAGE_U8, 3);
    if (image == NULL) {
        MessageBoxA(0, "Create image failed.", "Error", MB_OK);
    }

   

    if (imaqSetImageSize(image, 100, 100) == 0) {
        MessageBoxA(0, "Set image size fail.", "Error", MB_OK);
    }

    pixelValue.grayscale = 128;
    imaqFillImage(image, pixelValue, NULL);

    return imaqGetLastError();
}

 

image.png

 

No error.

Image is blank.  Size is 0.

 

TIA

 

George Zou
0 Kudos
Message 1 of 11
(4,018 Views)
No, this will not work, because you mixing two different data types.
What you can do - use IMAQ Image Cluster to pass in DLL, then use Data type conversion to get native type back.
You DLL code will looks like this:
Screenshot 2020-01-16 17.05.29.png
where IMAQ_Image declared like this:
Screenshot 2020-01-16 17.06.06.png
and then used in LabVIEW like this:
Screenshot 2020-01-16 17.07.01.png
then it will work.
 
On the other hand its not a good idea to allocate image within DLL and using it outside.
 
Better way - to allocate in LabVIEW code, then pass to DLL like this:
Screenshot 2020-01-16 17.13.01.png
your source code will looks like this:
Screenshot 2020-01-16 17.14.01.png
Of course, you can call LV_ImageToLVDT/LV_LVDTToImage inside of your DLL as well, then you can pass IMAQ Image.ctl directly to the DLL and get Block Diagram like shown on your screenshot, but this is "advanced" level. These two functions located in nivissvc.dll.
 
best regards,
Andrey.
 
Message 2 of 11
(3,963 Views)

Thanks for reply Andrey.

I got the idea from your post at:

https://forums.ni.com/t5/Machine-Vision/IMAQ-GetImagePixelPtr-Unmap-Pixel-Pointer-do-I-really-need-t...

Where Greg said you don't need the test image.

 

If you take a look the diagram of IMAQ Create, it uses the image as input, not image cluster.

 

I don't know the image size/pixel format before I call the dll.  So I have to create image and set image size inside the dll.

I got multiple cameras, from vendors SDK, I can't specify which camera.  Each time I call the dll, I lock onto a the "first" camera driver finds.

 

By the way, we have already tried IMAQdx.  Can't get it to work.  Got a lot of black stripes on the image.  the position and width are random.  It might be a band with issue?  On the other hand, vendor's viewer has no problem to get right image.

 

George Zou
0 Kudos
Message 3 of 11
(3,955 Views)
Solution
Accepted by topic author zou

You can pass image directly, but then you should call LV_SetImageSize instead of imaqSetImageSize and LV_FillImage instead of imaqFillImage (which also not a good idea, I think). Better way to use imaq* functions and perform conversion to the desired type inside of DLL or just keep everything as shown above. But anyway you should keep in mind that these ways are "undocumented", and the only officially supported way is using pixel pointer. But passing image directly to DLL will keep Block Diagram more clear.

 

With IMAQdx I also got some troubles in the past with GigE Vision camera because NI-IMAQdx High Performance GigE Vision Driver was replaced with the driver from camera supplier. If you have performance issues - be sure that this driver is installed and used (assumed that you have GigE Vision camera).

Message 4 of 11
(3,937 Views)

But from C language point of view, you passed in a structure, and used only one component of the structure, why not simply pass in that component by itself?

 

All the function calls are used on the image (which is created in the dll) not on the structure.

Only one line of code related to the structure:

LV_Image->address = image;

 

By the way, image structure works. Kudos.

 

George Zou
0 Kudos
Message 5 of 11
(3,932 Views)

I don't know about IMAQ specifics but it looks to me like you may not be handling the pointers correctly.

 

Your function prototype is expecting a pointer to some Image data but instead of manipulating the data image is pointing to, you are completely replacing the pointer. At a high level, LabVIEW is passing address A and then you are locally creating an image with address B and filling that image. Those functions can work exactly as advertised (hence no errors returned) but when we return to LabVIEW we look back at address A (what we passed to the function) and see an empty image.

Matt J | National Instruments | CLA
0 Kudos
Message 6 of 11
(3,827 Views)

It's very IMAQ specific.

The input pointer has no data.  Because I don't know the image type or size, I can't create the image in LabVIEW.  

 

George Zou
0 Kudos
Message 7 of 11
(3,820 Views)

If that's what you're looking to do you would probably want the parameter to be a pointer to the image pointer then right? That's more or less what the struct gives you as far as I can tell (the LV cluster is not exactly handled that way in memory but it ends up working itself out).

Matt J | National Instruments | CLA
0 Kudos
Message 8 of 11
(3,813 Views)

If that's what you're looking to do you would probably want the parameter to be a pointer

> to the image pointer then right?

 

What the parameter are you referring to?  I don't know the image size or type in LabVIEW.  And I don't want them return to LabVIEW.  I have only one input: the pointer to an image(Image *image).

 

 

George Zou
0 Kudos
Message 9 of 11
(3,807 Views)

@zou wrote:

 

What the parameter are you referring to?  I don't know the image size or type in LabVIEW.  And I don't want them return to LabVIEW.  I have only one input: the pointer to an image(Image *image).


I was talking about the image parameter of the TestImage function. I'm also assuming in your original post that you are expecting to look at the image pointer in LabVIEW after the function has executed and find that it is a 100x100 gray image so let me know if that is not correct.

 

If that is what you would be expecting then I don't think the C function is set up correctly. You are passing in a pointer to an image, basically an address to some memory location that should hold the image. If I'm reading everything correctly then imaqCreateImage will create a new image pointer (different address to a different memory location) that replaces image and then that new image is set to size 100x100 and filled with grey. When we return to LabVIEW we will be looking at the original pointer passed to the function only to find out that it is still empty because we were operating on a completely different image.

Matt J | National Instruments | CLA
0 Kudos
Message 10 of 11
(3,792 Views)