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, It works!
For the initial test, I created a Grayscale U8 type Image Buffer in LabVIEW and passed the pointer to the Image Handle:
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:
Then I tried to implement the same for Grayscale U16
by changing the following lines:
pixel.grayscale = 32000;
myImage = imaqCreateImage(IMAQ_IMAGE_U16, 3);
.
.
.
memcpy((unsigned short*)lvImageInfo.imageStart + y * lvImageInfo.pixelsPerLine,
(unsigned short*)myImageInfo.imageStart + y * myImageInfo.pixelsPerLine, LVWidth);
I get the same Blank Image as output!
UPDATE 1:
The Blank Image is due to not setting the appropriate Display mapping option. Right-click on the Image Indicator
--> 16-Bit Display Mapping
--> Most Significant Bits
. After this, Actual gray values can be seen.
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.
UPDATE 2:
Turns out the access violation error is due to invalid memory allocation.
unsigned short* pSrc = new unsigned short[LVHeight * LVWidth];
readRawFile(pSrc, LVWidth, LVHeight);
I just changed this and now I'm able to see the image in the image window. But my original requirement is to get the image in LabVIEW VI (Refer to the first VI snippet above). Now when I export the function as dll, and call it from LabVIEW, I get the blank image with pixel values of zeros. Here is my exported function,
int __stdcall copyImageToLV(IMAQ_Image *LVImage)
{
Image *lvImage;
ImageInfo lvImageInfo;
int y, LVHeight, LVWidth,handle;
lvImage = LVImage->address;
imaqGetImageSize(lvImage, &LVWidth, &LVHeight);
char* pSrc = new char[LVHeight * LVWidth * 2];
readRawFile(pSrc, LVWidth, LVHeight);
imaqGetImageInfo(lvImage, &lvImageInfo);
for (y = 0; y < LVHeight; ++y)
{
memcpy((unsigned short*)lvImageInfo.imageStart + y *
lvImageInfo.pixelsPerLine,pSrc + y*LVWidth*2, LVWidth*2);
}
delete[] pSrc;
return 0;
}
Kindly help me to resolve this issue... Thanks!