Hello guys:
I extract a slice from vtkImageData with vtkImageReslice filter, then display the output of vtkImageReslice in renderwindow, meanwhile i convert the output of vtkImageReslice to qimage. BUT The result of qimage is different with picture displayed in renderwindow. PICTURE BELOW:
It seems to me that the number of pixels widthwise should be greater and the scan order is upside down. I’d rewrite your scanning loop with something like this (redim arrays as needed):
for(int i = 0; i < y_dims; ++i)
{
for(int j = 0; j < x_dims-1; ++j) //dimension widthwise should ensure correct vertical alignment
{
float val = raw->GetScalarComponentAsFloat(j, i, 0, 0);
int res = (int)(((val - scalar_min) / scalar_range) * 255.0);
uchar *p = img.bits() + ( (y_dims-1-i) * x_dims + j); //vertical scan order seems to differ between Qt and VTK
*p = res;
}
}
Thanks a lot, I have try the code supplied by you, and THANKFULLY that was worked!
but i wonder why the x_dims should minus one? could you tell me the reason? THANKS!
It’s because the dimensions of vtkImageData referes to its vertices (mesh corners) and not its cells. So, to accomodate a 10x10x10 data array, you have to crate an 11x11x11 vtkImageData.
Then, how I populate it with values for rendering (notice how I allocate the values array with one dimension less for each axis):
//read sample values
values->Allocate( nX*nY*nZ );
for( int k = 0; k < nZ; ++k){
for( int j = 0; j < nY; ++j){
for( int i = 0; i < nX; ++i){
// sample value
double value = cartesianGrid->getDataValueIJK( variable_index, i, j, k );
values->InsertNextValue( value );
}
}
}
//assign the grid values to the volume cells
imageData->GetCellData()->SetScalars( values );
Edit: It’s most likely you need to use y_dims-1 too. I wonder why you don’t get a crash.
You are assuming that the scalars are associated with the cells:
For the original question, however, I am 99% certain that the scalars are associated with the points. Hence, the -1 is not needed. It should loop like this:
yes, the scalars are associated with the points. the vtkimagedata is structed point which is from ct data. for mine application, i change the function which convert vtkimagedata to qimage and i get the correct result finally. But i can’t explain the reason for that, could you tell me? thanks a lot!
the function below:
QImage convert_vtkimagedata_to_qimage(vtkImageData *raw, float scalar_min, float scalar_max, double *spacing)
{
int width = *raw->GetDimensions();
int height = *(raw->GetDimensions()+1);
float val = raw->GetScalarComponentAsFloat(j, i, 0, 0);
The index for images does not always begin at zero. It begins at the start of the extent, and if the start of the extent is not zero, then an offset is needed:
int* extent = raw->GetExtent();
int x_min = extent[0];
int x_max = extent[1];
int y_min = extent[2];
int y_max = extent[3];
for(int i = y_min; i <= y_max; ++i)
{
for(int j = x_min; j <= x_max; ++j)
{
float val = raw->GetScalarComponentAsFloat(j, i, 0, 0);
int res = (int)(((val - scalar_min) / scalar_range) * 255.0);
uchar *p = img.bits() + ((i - y_min) * x_dims + (j - x_min));
*p = res;
}
}
In this code vtkImageData index starts at x_start and the QImage index starts at 0.
Edit: Ugh! I had to fix my example code. I had an off-by-one error on the extent. Sigh…
The code is fixed now… maybe…
Edit: I actually think your new code is better than my example. The only change I recommend is this, so that you do not need to SafeDownCast() the scalars:
- short* tuple = scalarTuples+(tupleIndex++);
- int v = ((*tuple - scalar_min) / scalar_range ) *255.0;
+ double scalar_val = scalars->GetComponent(tupleIndex++, 0);
+ int v = ((scalar_val - scalar_min) / scalar_range ) * 255.0;
I don’t like to use GetScalarComponentAsFloat() because it is a very inefficient function.
We use the vtkImageDataToQImage implementation in CTK.
CTK has lots of other useful tools for implementing medical imaging applications (DICOM browser, slice and 3D viewer widgets, volume rendering transfer function editor, and many other widgets), and you can save even more time by building your application on higher-level VTK-based frameworks, such as 3D Slicer or MITK.