Intel® Integrated Performance Primitives
Deliberate problems developing high-performance vision, signal, security, and storage applications.

ipprResize (3D resizing)

Ken_Thornton
Beginner
693 Views

 

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 

 

0 Kudos
4 Replies
Ken_Thornton
Beginner
693 Views

I forgot to mention I am using IPP 9.0.3

0 Kudos
Ying_H_Intel
Employee
693 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: 

https://software.intel.com/sites/default/files/managed/97/ce/SubmittingSupportIssue.pdf

Our support team will work with you

​Best Regards,

​Ying

0 Kudos
Ken_Thornton
Beginner
693 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.

0 Kudos
Valentin_K_Intel
Employee
693 Views

Hi Ken,

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

Thanks,
Valentin

0 Kudos
Reply