Community
cancel
Showing results for
Did you mean:
Beginner
178 Views

## ipprResize (3D resizing)

Please explain the difference between the coordinate systems used by ipprWarpAffine and ipprResize.

In the ipprResize documentation, it says “The right coordinate system (RCS) is used here.”. What is meant by that?

Consider a 2x2x2 volume.

Plane 0 has (x,y,z) coordinates:

000 100

010 110

Plane 1 has (x,y,z) coordinates:

001 101

011 111

If I use ipprWarpAffine with (x,y,z) scale factors of 5 (and no translation), I get a 6x6x6 volume since the coordinates above trivially get mapped to {000 500 050 550} in output plane 0 and  {005 505 055 555} in output plane 5 (the rest are interpolated).

If I use ipprResize with (x,y,z) scale factors of 5 (and no translation), it wants me to have an output volume size of (10,10,10).

```bool IntelFuncs::TestResizeImage()
{
int i, x, y, z;
const int dim = 2;
const int dimNew = 10;

std::vector<unsigned short> src ={100, 100, 100, 100, 200, 200, 200, 200};
std::vector<unsigned short> dst(dimNew*dimNew*dimNew);

ASSERT(static_cast<int>(src.size()) == dim*dim*dim);

i = 0;
for (z=0; z<dim; z++) {
TRACE(_T("#################### Original Slice %d\n"), z);

for (y=0; y<dim; y++) {
for (x=0; x<dim; x++, i++) {
TRACE(_T("%d "), src);
}
TRACE(_T("\n"));
}
}

IppStatus status;

IpprVolume srcVol ={dim, dim, dim};
IpprCuboid srcVOI ={0, 0, 0, dim, dim, dim};

int srcStep = dim*sizeof(unsigned short);
int srcPlaneStep = dim*dim*sizeof(unsigned short);

int dstStep = dimNew*sizeof(unsigned short);
int dstPlaneStep = dimNew*dimNew*sizeof(unsigned short);

double xFactor=5.0, yFactor=5.0, zFactor=5.0, xShift=0.0, yShift=0.0, zShift=0.0;
int nInterp = IPPI_INTER_LINEAR;

IpprCuboid dstVOI ={0, 0, 0, 0, 0, 0};
status = ipprGetResizeCuboid(srcVOI, &dstVOI, xFactor, yFactor, zFactor, xShift, yShift, zShift, nInterp);
ASSERT(dstVOI.width == dimNew && dstVOI.height == dimNew && dstVOI.depth == dimNew); //It wants me to have a dstVOI of size (10,10,10)

int bufSize = 0;
status = ipprResizeGetBufSize(srcVOI, dstVOI, 1, nInterp, &bufSize);

Ipp8u* pBuffer = ippsMalloc_8u(bufSize);

status = ipprResize_16u_C1V(src.data(), srcVol, srcStep, srcPlaneStep, srcVOI, dst.data(), dstStep, dstPlaneStep, dstVOI, xFactor, yFactor, zFactor, xShift, yShift, zShift, nInterp, pBuffer);

i = 0;
for (z=0; z<dimNew; z++) {
TRACE(_T("#################### New Slice %d\n"), z);

for (y=0; y<dimNew; y++) {
for (x=0; x<dimNew; x++, i++) {
TRACE(_T("%d "), dst);
}
TRACE(_T("\n"));
}
}

ippsFree(pBuffer);

return false;
}```

This gives output:

#################### Original Slice 0
100 100
100 100
#################### Original Slice 1
200 200
200 200
#################### New Slice 0
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
#################### New Slice 1
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
#################### New Slice 2
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
100 100 100 100 100 100 100 100 100 100
#################### New Slice 3
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
120 120 120 120 120 120 120 120 120 120
#################### New Slice 4
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
140 140 140 140 140 140 140 140 140 140
#################### New Slice 5
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
160 160 160 160 160 160 160 160 160 160
#################### New Slice 6
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
180 180 180 180 180 180 180 180 180 180
#################### New Slice 7
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
#################### New Slice 8
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
#################### New Slice 9
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200
200 200 200 200 200 200 200 200 200 200

4 Replies
Beginner
178 Views

I forgot to mention I am using IPP 9.0.3

Employee
178 Views

Hi Ken,

Please see the detail from our developers:

The function ipprResize considers an image as set of cubic pixels. Each pixel is a cube with unit volume (1x1x1). So the function works with center points of pixels. The transformation that maps a source image to the destination one can be expressed by the following formula:

|X'+0.5|   |xFactor    0       0   |   |X+0.5|   |xShift|

|Y'+0.5| = |   0    yFactor    0   | * |Y+0.5| + |yShift|

|Z'+0.5|   |   0       0    zFactor|   |Z+0.5|   |zShift|

Where

(X', Y', Z') – destination point coordinates

(X, Y, Z) – source point coordinates

(xShift, yShift, zShift) shift values provided by the user

+0.5 is used to get the center of the pixel

Change the formula to get the normalized form

|X'|   |xFactor    0       0   |   |X|   |xShift|   |xFactor*0.5 - 0.5|

|Y'| = |   0    yFactor    0   | * |Y| + |yShift| + |yFactor*0.5 - 0.5|

|Z'|   |   0       0    zFactor|   |Z|   |zShift|   |zFactor*0.5 - 0.5|

The function ipprWarpAffine considers an image as set of point pixels. Each pixel is a point with zero volume, the distance between neighbor pixels is 1 along each dimension. So the function just works with points. The transformation that maps a source image to the destination one can be expressed by the following formula:

|X'|   | A11  A12  A13 |   |X|   |xShift|

|Y'| = | A21  A22  A23 | * |Y| + |yShift|

|Z'|   | A31  A32  A33 |   |Z|   |zShift|

Where A** matrix of coefficients

And for the scale case, when A11 := xFactor, A22 := yFactor, A33 := zFactor

|X'|   |xFactor    0       0   |   |X|   |xShift|

|Y'| = |   0    yFactor    0   | * |Y| + |yShift|

|Z'|   |   0       0    zFactor|   |Z|   |zShift|

If this is still a issue, could you summit a ticket to our support site: https://www.intel.com/supporttickets?  Here are some detail steps:

Our support team will work with you

​Best Regards,

​Ying

Beginner
178 Views

Ying,

So in ipprResize, the center of integer voxel (x,y,z) has coordinates (x+0.5,y+0.5,z+0.5) but in ipprWarpAffine, the center of integer voxel (x,y,z) has coordinates (x,y,z). That seems to be the essential difference between the 2 methods.

In ipprResize, if dimInZ is the number of input image slices, it would seem to me that ipprGetResizeCuboid calculates the number of output slices as 1 + zFactor(dimInZ-1) so long as zFactor is an integer >= 1.

It would be nice if the documentation was more explicit about these differences.

Employee
178 Views

Hi Ken,

Thank you for the feedback. We will correct the documentation in future releases.

Thanks,
Valentin