ITK Importing Image Data from a Buffer - c++

I have coded a method to create an Itk image from a buffer (in my case it's a Cimg image type). This is the algorithme :
void Cimg_To_ITK (CImg<uchar> img)
{
const unsigned int Dimension = 2;
typedef itk::RGBPixel< unsigned char > RGBPixelType;
typedef itk::Image< RGBPixelType, Dimension > RGBImageType;
typedef itk::ImportImageFilter< RGBPixelType, Dimension > ImportFilterType;
ImportFilterType::Pointer importFilter = ImportFilterType::New();
typedef itk::ImageFileWriter< RGBImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
RGBImageType::SizeType imsize;
imsize[0] = img.width();
imsize[1] = img.height();
ImportFilterType::IndexType start;
start.Fill( 0 );
ImportFilterType::RegionType region;
region.SetIndex( start );
region.SetSize( imsize );
importFilter->SetRegion( region );
const itk::SpacePrecisionType origin[ Dimension ] = { 0.0, 0.0 };
importFilter->SetOrigin( origin );
const itk::SpacePrecisionType spacing[ Dimension ] = { 1.0, 1.0 };
importFilter->SetSpacing( spacing );
const unsigned int numberOfPixels = imsize[0] * imsize[1];
const bool importImageFilterWillOwnTheBuffer = true;
RGBPixelType * localBuffer = new RGBPixelType[ numberOfPixels ];
memcpy(localBuffer->GetDataPointer(), img.data(), numberOfPixels);
importFilter->SetImportPointer( localBuffer, numberOfPixels,importImageFilterWillOwnTheBuffer );
writer->SetInput( importFilter->GetOutput() );
writer->SetFileName( "output.png" );
writer->Update();
}
I dont have what i want as a output :
input :
output :

CImg stores different RGB Pixels as separate componentes
You must prepare an RGBPixel buffer and iterate over the image and save to the buffer:
RGBPixelType *buffer=new RGBPixelType[img.width()*img.height()];
cimg_for(img,x,y)
{
// Now allign three colors
buffer[x+y*img.width()]= RGBPixelType({img(x,y,0,0),img(x,y,0,1),img(x,y,0,2)});
}
importImageFilterWillOwnTheBuffer=true; // To avoid leaks

Might be also good idea to check how the Cimg stores the pixels for image and if it differs from the RGBPixelType. I suspect that the RGBPixelType array has pixels stored in rgbrgbrgbrgb while the other may have them in some rrrrggggbbbb style format. Or, as already hinted, if the input is a gray-scale image with single channel you have to replicate the value for each rgb value (or if both are rgb you have to copy data from all the three channels)...

This is probably because you just copy one byte per pixel. Each RGBPixelType is likely several bytes in size:
memcpy(localBuffer->GetDataPointer(), img.data(), numberOfPixels * sizeof(RGBPixelType));

Related

ITK: CannyEdgeDetectionFilter issues

I'm trying to use the CannyEdgeDetectionImageFilter but the GetPixel() method doesn't seem to be properly referencing the filtered image. I've tried a lot of different tactics to attempt to resolve the issue, but the only thing that seems to work is writing and reading the image to/from the disk (which is not ideal). My code is below:
typedef itk::Image<unsigned char, 2> ImageType;
typedef itk::Image<float, 2> floatImageType;
...
floatImageType::Pointer to_float(ImageType::Pointer image){
typedef itk::CastImageFilter <ImageType, floatImageType> CastFilterType;
CastFilterType::Pointer castToFloat = CastFilterType::New();
castToFloat->SetInput( image );
castToFloat->Update();
return castToFloat->GetOutput();
}
...
ImageType::Pointer check(ImageType::Pointer image){
typedef itk::ImageDuplicator <ImageType> ImageDuplicatorType;
typedef itk::RescaleIntensityImageFilter
<floatImageType, ImageType> RescaleFilter;
typedef itk::CannyEdgeDetectionImageFilter
<floatImageType, floatImageType> CannyFilter;
RescaleFilter::Pointer Rescale = RescaleFilter::New();
CannyFilter::Pointer Canny = CannyFilter::New();
ImageDuplicatorType::Pointer Duplicator = ImageDuplicatorType::New();
ImageType::Pointer cannyImage;
Canny->SetVariance( 20 );
Canny->SetUpperThreshold( 2 );
Canny->SetLowerThreshold( 20 );
Rescale->SetOutputMinimum( 0 );
Rescale->SetOutputMaximum( 255 );
Duplicator->SetInputImage(image);
Duplicator->Update();
ImageType::Pointer img_copy = Duplicator->GetOutput();
floatImageType::Pointer floatImage = to_float(img_copy);
Canny->SetInput(floatImage);
Rescale->SetInput( Canny->GetOutput() );
Rescale->Update();
cannyImage = Rescale->GetOutput();
/* Insert odd work-around here */
const ImageType::SizeType img_size = cannyImage->GetLargestPossibleRegion().GetSize();
itk::Index<2> loc = {{img_size[0]/2, 0}};
int top_edge = 0;
bool contin = true;
for (int i = 0; ((i < img_size[1]) && contin); i++){
loc[1] = i;
if (cannyImage->GetPixel(loc) != 0){
top_edge = i;
contin = false;
}
}
...
}
When a pixel value of cannyImage later on, the value should be either 0, or (if an edge) 255. However, it produces values that appear to belong to a gray-scale image.
However, if I include the following code in he section above, it works as one should expect:
std::string fname = "/tmp/canny_" + to_string(getpid()) + ".tmp";
writeImage(cannyImage, fname);
cannyImage = readImage(fname);
(Methods writeImage(ImageType::Pointer image, std::string filename) and ImageType::Pointer readImage(std::string filename) were defined earlier the program.)
Anyone know what's going wrong with my program? Why does pushing it through the disk IO cause it to work?

Get Cimg image buffer [duplicate]

I'm trying to convert a Cimg image to itk image to use it for registration algorithm. The Cimg is a RGB image and i want to convert it to RGB itk image. Her is my code :
void Cimg_To_ITK (CImg<uchar> img)
{
const unsigned int Dimension = 2;
typedef itk::RGBPixel< unsigned char > RGBPixelType;
typedef itk::Image< RGBPixelType, Dimension > RGBImageType;
typedef itk::ImportImageFilter< RGBPixelType, Dimension > ImportFilterType;
ImportFilterType::Pointer importFilter = ImportFilterType::New();
typedef itk::ImageFileWriter< RGBImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
RGBImageType::SizeType imsize;
imsize[0] = img.width();
imsize[1] = img.height();
ImportFilterType::IndexType start;
start.Fill( 0 );
ImportFilterType::RegionType region;
region.SetIndex( start );
region.SetSize( imsize );
importFilter->SetRegion( region );
const itk::SpacePrecisionType origin[ Dimension ] = { 0.0, 0.0 };
importFilter->SetOrigin( origin );
const itk::SpacePrecisionType spacing[ Dimension ] = { 1.0, 1.0 };
importFilter->SetSpacing( spacing );
const unsigned int numberOfPixels = imsize[0] * imsize[1];
const bool importImageFilterWillOwnTheBuffer = true;
RGBPixelType * localBuffer = new RGBPixelType[ numberOfPixels ];
RGBPixelType * it = localBuffer;
memcpy(*it, img.data(), numberOfPixels);
importFilter->SetImportPointer( localBuffer, numberOfPixels,importImageFilterWillOwnTheBuffer );
writer->SetFileName( "output.png" );
}
I get this error at compilation :
error: cannot convert 'RGBPixelType {aka itk::RGBPixel}' to 'void*' for argument '1' to 'void* memcpy(void*, const void*, size_t)
What is wrong??
*it is a RGBPixelType, it can't be converted to a void pointer and memcpy() can't handle it. memcpy() needs pointers to values, such as img.data() or it. According to the documentation of CImg :
T* data () Return a pointer to the first pixel value.
An example of how to import an image from a buffer of values is provided by ITK here . My guess is that it is your starting point.
The other issue that you will soon face is the size of the image : RBG is 3 bytes per pixel, so it should be
memcpy(it, img.data(), numberOfPixels*3);
Here is an example of how to import a buffer of unsigned char as an ITK RGB Image, starting from your code. Feel free to edit this answer and add the function to handle a CImg !
#include <iostream>
#include <itkImage.h>
using namespace itk;
using namespace std;
#include <itkImportImageFilter.h>
#include <itkImageFileWriter.h>
void Cimg_To_ITK (unsigned char* data)
{
const unsigned int Dimension = 2;
typedef itk::RGBPixel< unsigned char > RGBPixelType;
typedef itk::Image< RGBPixelType, Dimension > RGBImageType;
typedef itk::ImportImageFilter< RGBPixelType, Dimension > ImportFilterType;
ImportFilterType::Pointer importFilter = ImportFilterType::New();
typedef itk::ImageFileWriter< RGBImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
RGBImageType::SizeType imsize;
// imsize[0] = img.width();
// imsize[1] = img.height();
imsize[0] = 100;
imsize[1] = 200;
ImportFilterType::IndexType start;
start.Fill( 0 );
ImportFilterType::RegionType region;
region.SetIndex( start );
region.SetSize( imsize );
importFilter->SetRegion( region );
const itk::SpacePrecisionType origin[ Dimension ] = { 0.0, 0.0 };
importFilter->SetOrigin( origin );
const itk::SpacePrecisionType spacing[ Dimension ] = { 1.0, 1.0 };
importFilter->SetSpacing( spacing );
const unsigned int numberOfPixels = imsize[0] * imsize[1];
const bool importImageFilterWillOwnTheBuffer = true;
RGBPixelType * localBuffer = new RGBPixelType[ numberOfPixels ];
RGBPixelType * it = localBuffer;
memcpy(it, data, numberOfPixels*3);
// no need to delete localBuffer : itk will care since importImageFilterWillOwnTheBuffer=true
importFilter->SetImportPointer( localBuffer, numberOfPixels,importImageFilterWillOwnTheBuffer );
writer->SetFileName( "output.png" );
writer->SetInput(importFilter->GetOutput() );
writer->Update();
}
int main()
{
unsigned char* data=new unsigned char[100*200*3];
for(int i=0;i<200;i++){
for(int j=0;j<100;j++){
data[(i*100+j)*3]=i;
data[(i*100+j)*3+1]=0;
data[(i*100+j)*3+2]=j;
}
}
Cimg_To_ITK (data);
delete[] data;
cout<<"running fine"<<endl;
return 0;
}
The file CMakeLists.txt :
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(ItkTest)
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
add_executable(MyTest main.cpp)
target_link_libraries(MyTest ${ITK_LIBRARIES})
After installing ITK and setting the environment variable ITK_DIR, type cmake . and make to build this example.

FreeImage: Pixel data accessed by FreeImage_GetBits is not correct (data + size)

I'm using the FreeImage 3.15.4 library to analyze PNG images. I'm basically trying to build a simple data structure of consisting of a palette of all colors as well as an array version of the image per-pixel data consisting of indexes into the palette.
The thing is that FreeImage_GetBits seems to be returning a pointer to invalid data and I'm not sure why. I am able to read the width and height of the PNG file correctly, but the data pointed to by FreeImage_GetBits is just garbage data, and appears to be of an odd size. No matter how many times I run the program, it consistently dies in the same place, when iPix in the code below is equal to 131740. I get a C0000005 error accessing bits[131740] in the std::find call. The actual and reported PNG image size is 524288.
Furthermore, I've tried this code with smaller images that I myself have built and they work fine. The PNG I'm using is provided my a third party, and does not appear to be corrupt in anyway (Photoshop opens it, and DirectX can process and use it normally)
Any ideas?
Here's the data declarations:
struct Color
{
char b; // Blue
char g; // Green
char r; // Red
char a; // Alpha value
bool operator==( const Color& comp )
{
if ( a == comp.a &&
r == comp.r &&
g == comp.g &&
b == comp.b )
return TRUE;
else
return FALSE;
}
};
typedef std::vector<Color> ColorPalette; // Array of colors forming a palette
And here's the code that does the color indexing:
// Read image data with FreeImage
unsigned int imageSize = FreeImage_GetWidth( hImage ) * FreeImage_GetHeight( hImage );
unsigned char* pData = new unsigned char[imageSize];
// Access bits via FreeImage
FREE_IMAGE_FORMAT fif;
FIBITMAP* hImage;
fif = FreeImage_GetFIFFromFilename( fileEntry.name.c_str() );
if( fif == FIF_UNKNOWN )
{
return false;
}
hImage = FreeImage_Load( fif, filename );
BYTE* pPixelData = NULL;
pPixelData = FreeImage_GetBits( hImage );
if ( pPixelData == NULL )
{
return false;
}
Color* bits = (Color*)pPixelData;
ColorPalette palette;
for ( unsigned int iPix = 0; iPix < imageSize; ++iPix )
{
ColorPalette::iterator it;
if( ( it = std::find( palette.begin(), palette.end(), bits[iPix] ) ) == palette.end() )
{
pData[iPix] = palette.size();
palette.push_back( bits[iPix] );
}
else
{
unsigned int index = it - palette.begin();
pData[iPix] = index;
}
}
The PNG images that were problematic were using indexed color modes and the raw pixel data was indeed being returned as 8bpp. The correct course of action was to treat this data as 8 bits per pixel, and treat each 8-bit value as an index into a palette of colors that can be retrieved using FreeImage_GetPalette. The alternative, which is the choice I ultimately made, was to call FreeImage_ConvertTo32Bits on these indexed color mode PNG images, and then pass everything through the same code path as the same 32-bit image format.
Pretty simple conversion, but here it is:
// Convert non-32 bit images
if ( FreeImage_GetBPP( hImage ) != 32 )
{
FIBITMAP* hOldImage = hImage;
hImage = FreeImage_ConvertTo32Bits( hOldImage );
FreeImage_Unload( hOldImage );
}

reading TGA files in OpenGl to create a 3d ouse

I have a TGA file and a library that allready has everything that I need to read TGA and use them.
This class has a method called pixels(), that returns a pointer that is pointed to the memory area where pixel are stored as RGBRGBRGB...
My question is, how can I take the pixel value?
Cause if I make something like this:
img.load("foo.tga");
printf ("%i", img.pixels());
It gives back to me what is proprably the address.
I've found this code on this site:
struct Pixel2d
{
static const int SIZE = 50;
unsigned char& operator()( int nCol, int nRow, int RGB)
{
return pixels[ ( nCol* SIZE + nRow) * 3 + RGB];
}
unsigned char pixels[SIZE * SIZE * 3 ];
};
int main()
{
Pixel2d p2darray;
glReadPixels(50,50, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &p.pixels);
for( int i = 0; i < Pixel2d::SIZE ; ++i )
{
for( int j = 0; j < Pixel2d::SIZE ; ++j )
{
unsigned char rpixel = p2darray(i , j , 0);
unsigned char gpixel = p2darray(i , j , 1);
unsigned char bpixel = p2darray(i , j , 2);
}
}
}
I think that It can work great for me, but how can I tell the program to read from my img?
Tga supports different pixel depths. And we don't know what library you're using. But generally speaking pixels() should return a pointer to a buffer containing pixels. Say for sake of argument it unpacks the pixels into 8-bit per channel subpixels, then each pixel is represented by 3 bytes.
So to access a pixel at a given offset in the buffer:
const u8* pixelBuffer = img.pixels():
u8 red = pixelBuffer[(offset*3)+0];
u8 green = pixelBuffer[(offset*3)+1];
u8 blue = pixelBuffer[(offset*3)+2];
If you know the width of the image buffer then you can get a pixel by its x and y coordinates:
u8 red = pixelBuffer[((x+(y*width))*3)+0];

convert a uint16 dicom image to qimage

i tried to convert a dicom image read from a gdcm image reader which has photometric interpretation as 'monochrome2' and pixel format as unsigned int 16 or uint16, i tried the following code over it, but is not giving the required image, please help.
QVector<QRgb> table(2);
for(int c=0;c<256;c++)
{
table.append(qRgb(c,c,c));
}
std::cout << "this is the format UINT16" << std::endl;
int size = dimX*dimY*2; // length of data in buffer, in bytes
quint8 * output = reinterpret_cast<quint8*>(buffer);
const quint16 * input = reinterpret_cast<const quint16*>(buffer);
do {
*output++ = (*input) >> 8;
} while (size -= 2);
imageQt = new QImage(output, dimX, dimY, QImage::Format_Indexed8);
imageQt->setColorTable(table);
regards
I think I see your problem. You are writing the data to output and incrementing the pointer to output as you go along.
You then create the QImage pointing to the end of the bitmap.
You need to do the following:
imageQt = new QImage( reinterpret_cast< uchar* >( buffer ), dimX, dimY, QImage::Format_Indexed8);
Edit: Also you don't advance the input pointer.
You need to change your inner loop to the following:
*output++ = (*input++) >> 8;