09-21-2021 12:27 PM - edited 09-21-2021 12:50 PM
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:
The Parameter Configuration
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);
.
.
.
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!
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:
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!
09-22-2021 10:25 AM
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
09-26-2021 04:16 AM
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 Mapping
option. Once I chose theMost Significant Bit
option. I was able to see the actual pixels with the appropriate gray values.
09-26-2021 02:00 PM
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!
09-28-2021 02:34 AM
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 :
Hope this helps,
Sami
09-29-2021 02:16 AM
@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