Machine Vision

cancel
Showing results for 
Search instead for 
Did you mean: 

[NI Vision DLL] [C++] [IMAQ DLL] [IMAQ C Support] [Pass image from C to LV] How to Copy raw U16 data to LabVIEW Vision Image Buffer using memcpy()?

Solved!
Go to solution

I have a frame grabber that acquires 16bit grayscale image data as a 1d array of unsigned short. Now I need to convert this raw U16 data to a LabVIEW Vision Image for further processing.

 

Before proceeding with the actual acquisition, I thought of experimenting with the NI Vision Library Support for C++. I have slightly modified example code from NI to copy a Grayscale U8 image using memcpy(). When I run, for Grayscale U8 , It works.

 

For the initial test, I created a Grayscale U8 type Image Buffer in LabVIEW and passed the pointer to the Image Handle: 

 

GgSSU.png

The Parameter Configuration 

 

4HdN6.png

C++ Function:

#include "nivision.h"

//Image Data as LabVIEW Cluster
typedef struct {
    char* name;
    Image* address;
}IMAQ_Image;

int __stdcall copyImageToLV(IMAQ_Image *LVImage) 
{
  Image* myImage, *lvImage;
  PixelValue pixel;
  ImageInfo myImageInfo, lvImageInfo;
  int y, LVHeight, LVWidth;
  lvImage = LVImage->address;
  pixel.grayscale = 128;
  //Create a New Image buffer and fill it with grey.
  myImage = imaqCreateImage(IMAQ_IMAGE_U8, 3);
  imaqGetImageSize(lvImage, &LVWidth, &LVHeight);
  imaqSetImageSize(myImage, LVWidth, LVHeight);
  imaqFillImage(myImage,pixel, NULL);

  imaqGetImageInfo(myImage, &myImageInfo);
  imaqGetImageInfo(lvImage, &lvImageInfo);
  //LVImage->address = myImage;
  //Copy filled Image to Buffer created from LabVIEW
  for (y = 0; y < LVHeight; ++y)
  {
    memcpy((char *)lvImageInfo.imageStart + y * lvImageInfo.pixelsPerLine,
           (char *)myImageInfo.imageStart + y * myImageInfo.pixelsPerLine, LVWidth);
  }
  imaqDispose(myImage);
  return 0;
}

The Output:

2021-09-21_21h38_58.png

Then I tried to implement the same for Grayscale U16 by changing the following lines:

pixel.grayscale = 32000;
myImage = imaqCreateImage(IMAQ_IMAGE_U16, 3);
.
.
.
for(y=0;y<LVHeight;++y)
{
memcpy
((unsigned short*)lvImageInfo.imageStart + y * lvImageInfo.pixelsPerLine, (unsigned short*)myImageInfo.imageStart + y * myImageInfo.pixelsPerLine, LVWidth);
}

I get the following Image with a pixel value of 32000 from 0 to 49th columns and pixel value of 0 from 50 to 99 as output! 

 

2021-09-21_22h59_23.png

Then I tried the following:

pixel.grayscale = 32000;
myImage = imaqCreateImage(IMAQ_IMAGE_U16, 3);
.
.
.
for(y=0;y<LVHeight*2;++y)
{
memcpy
((char*)lvImageInfo.imageStart + y * lvImageInfo.pixelsPerLine, (char*)myImageInfo.imageStart + y * myImageInfo.pixelsPerLine, LVWidth*2);
}

I get the following Blank Image with a pixel value of 32000 as output:

2021-09-21_22h23_08.png

 

I even tried instead of copying the data, I just swapped the address and removing the Dispose part:

LVImage->address = myImage;

//for(y=0;y<LVHeight*2;++y)
//{
//memcpy
((char*)lvImageInfo.imageStart + y * lvImageInfo.pixelsPerLine, // (char*)myImageInfo.imageStart + y * myImageInfo.pixelsPerLine, LVWidth*2); //ImaqDispose(myImage);

Still, I'm getting the same blank Image!

 

Can anyone help me in copying the data? Any help would be really appreciated... Thanks!

0 Kudos
Message 1 of 6
(4,169 Views)

Using an image to a function in a dll is not that straightforward.

For such tasks, we use IMAQ GetImagePixelPtr.vi

You can check this example.

 

Sami

 

0 Kudos
Message 2 of 6
(4,115 Views)

Hi Sami,

 

Thank you for your time and effort. 🙂

 

I totally understand that this isn't a straightforward approach. But the method I used here is almost the same. There are many threads confirming this method. 

 

Here, Take a look at this thread.

 

Also, I figured out why the Image is blank! It's because I haven't used the16-Bit Display Mappingoption. Once I chose theMost Significant Bitoption. I was able to see the actual pixels with the appropriate gray values.

 

2021-09-26_12h53_47.png

 

 

2021-09-26_12h54_33.png

 

Achuthaperumal_0-1632641722855.png

 

0 Kudos
Message 3 of 6
(4,090 Views)

Now, I'm trying to actually acquire the images from Framegrabber. It writes the pixel data into a .raw file. I need to read the pixel data from the file and then copy that to LabVIEW's Image Buffer.

#include <iostream>
#include "nivision.h"
#include<fstream>
using namespace std;

int readRawFile(unsigned short* pSrc, int Width, int Height)
{
  ifstream file;
  file.open("test.raw", ios::in | ios::binary);
  if (file.is_open() == true)
  {
    file.read(reinterpret_cast<char*>(pSrc), Width * Height * 2);
    file.close();
    return 1;
  }

  else return 0;
}

int main()
{
  Image* myImage;
  PixelValue pixel;
  ImageInfo myImageInfo;
  int LVHeight, LVWidth, i,handle,y;
  LVHeight = 3052;
  LVWidth = 2500;
  pixel.grayscale = 65535;

  unsigned short* psrc=new unsigned short(LVHeight * LVWidth);
  readRawFile(pSrc, LVWidth, LVHeight);

  myImage = imaqCreateImage(IMAQ_IMAGE_U16, 3);
  imaqSetImageSize(myImage, LVWidth, LVHeight);
  imaqFillImage(myImage, pixel, NULL);
  imaqGetImageInfo(myImage, &myImageInfo);

  //Display Filled Image.
  imaqGetWindowHandle(&handle);
  imaqDisplayImage(myImage, handle, 1);
  std::cin >>i;

  std::cout << "Height = " <<LVHeight << "\tWidth = " << LVWidth 
            <<std::endl;
  std::cout << "PixelsPerLine = " << 
  myImageInfo.pixelsPerLine<<std::endl;

  for (y = 0; y < LVHeight; ++y)
  {
      memcpy((unsigned short*)myImageInfo.imageStart + y * 
              myImageInfo.pixelsPerLine, pSrc + LVWidth * y, LVWidth 
               *sizeof(unsigned short));
  }

  imaqDisplayImage(myImage, handle, 1);
  std::cin >>i;

  imaqDispose(myImage);
  delete pSrc;
} 

 

When I run this code, I get the following Access Violation Error:

Exception thrown at 0x00007FFF9D821470 (vcruntime140.dll) in
TestApplication.exe: 0xC0000005: Access violation reading location 
0x0000019EA712F320.

After about 180 Iterations, I'm getting this error! Of course, from the error description, the problem is with the pSrc pointer... But I have no idea how to resolve this!

 

I Observed that Vision DLL allocates some extra memory based on the given image width. If the image width is 2500 pixels, The pixelsPerLine returns 2560 pixels. When I tried printing, The unused pixels were filled with 0.

Kindly help me to resolve this issue... Thanks!

0 Kudos
Message 4 of 6
(4,081 Views)

Image lines include "your pixels" but also borders and padding bytes.

You will have full explanation in the NI Vision Concept manuals that is usually located in C:\Program Files (x86)\National Instruments\Vision\Help .

Below is a creenshot of the chapter dealing with image representation in memory :

SamiF_0-1632814459861.png

 

Hope this helps,

 

Sami

 

Message 5 of 6
(4,064 Views)
Solution
Accepted by topic author Achuthaperumal

@Achuthaperumal wrote:

When I run this code, I get the following Access Violation Error:

Exception thrown at 0x00007FFF9D821470 (vcruntime140.dll) in
TestApplication.exe: 0xC0000005: Access violation reading location 
0x0000019EA712F320.

After about 180 Iterations, I'm getting this error! Of course, from the error description, the problem is with the pSrc pointer... But I have no idea how to resolve this!


 Turns out, The issue is because of an invalid memory allocation! 

 

unsigned short *psrc=new unsigned short[LVWidth * LVHeight];

 Once I changed this, I was able to see the image. Also, an additional note, add imaqSetWindowThreadPolicy(IMAQ_SEPARATE_THREAD)  at the start of the function to stop your display windows from appearing to be unresponsive.

 

C++ - How to Copy raw U8 | U16 data to LabVIEW Vision Image Buffer using memcpy - Stack Overflow

0 Kudos
Message 6 of 6
(4,053 Views)