From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

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,153 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,099 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,074 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,065 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,048 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,037 Views)