# Image resampling and resizing

This topic is 4483 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey, I have a question about resizing and resampling an image. I am currently working only in the x direction (scaling the width). My resampling function is as follows:
unsigned char* resampleX2(unsigned char* source, int newWidth, int oldWidth, int height) {
int numPixels = int(newWidth * height * 4 + newWidth); // number of pixels in resized image
unsigned char* output = new unsigned char[numPixels];

double deltaX = double(oldWidth /newWidth);
double x0 = double(-0.5 +deltaX/2);  // first sample point (in original image)
cubicFilter f;   // a mitchell-netravali cubic filter, takes in and spits out a double

for(int i =0; i < numPixels - 1; i+=4) {    // iterate through all pixels, increment by 4 for rgba
double x = x0 + i*deltaX;				// determine current sample point
double sr = 0,sg=0,sb=0,sa=0;           // sum values for rgba - use for convolution
for(double j = x - radius; j < x + radius; j++) {   // convolve
sr += source[(int)j]*f.compute(x-j);
sg += source[(int)j + 1]*f.compute(x-j);
sb += source[(int)j + 2]*f.compute(x-j);
sa += source[(int)j + 3]*f.compute(x-j);
}

// set output image to new resized values
output[i] = sr;
output[i+1] = sg;
output[i+2] = sb;
output[i+3] = sa;
}

return output;
}
The odd thing about it is that if I scale by half, I get perfect results. Anything besdies that (and 10% i think) gives me results that are either skewed or have major color issues. Any help would be appreciated. This is for a project due tomorrow and has been driving me crazy. Thanks.

##### Share on other sites
Well after a little debugging, it seems part of my problem is with overlapping 'j' values. In other words my filter is overlapping the pixels it convolves. (if that makes any sense) This thing is due in 6 hours and I'm starting to get desperate. If anyone has an idea, throw it out there.

##### Share on other sites
Lol, yeah I wish I could. I've been pounding away at this thing for too much of the day though, and thought I could at least see if anyone here (who happens to be up at this absurd hour) could offer some help. Anyway...

##### Share on other sites
It's the WORLD wide web. It's 9:30am here.

Anyway, haven't looked at your code too much but I'd take a look at your numpixels calculation.

If your getting skewed images I'd imagine you are getting the wrong line width in there somewhere.

Personally I'd use two loops (for clarity), One for X and one for Y.

##### Share on other sites
Well I programmed it with two loops (iterating through rows and columns). Here is that function.

unsigned char* resampleX(unsigned char* source, int newWidth, int oldWidth, int height) {
unsigned char* result = new unsigned char[newWidth*height*4];
float deltaX = oldWidth/newWidth;
float x0 = -0.5 + deltaX/2;
cubicFilter f;

int i = 0,iPrime = 0; // i is result image index, iprime is source image index

for(int row = 0; row < height; row++) {
for(int col = 0; col < newWidth; col++) {
float sr = 0,sg = 0,sb = 0,sa = 0;
i = index(col,row,newWidth);
iPrime = index(col,row,oldWidth);
int x = x0 + iPrime * deltaX;
sr += source[(int)j] * f.compute(x-j);
sg += source[(int)j+1] * f.compute(x-j);
sb += source[(int)j+2] * f.compute(x-j);
sa += source[(int)j+3] * f.compute(x-j);
}
result[i] = sr;
result[i+1] = sg;
result[i+2] = sb;
result[i+3] = sa;
}
}

return result;

}

Also, since you mentioned it, my index function is as follows:
int index(int x, int y, int w) {
// returns an index for an rgba image
return (y*w+x)*4;
}

It is pretty basic, just converts from x,y to row major indicie. With this implementation, I get about the exact same result as before.

##### Share on other sites
Actually, I lied. My second implementation juts cuts off the side of the image, performing no scaling...

##### Share on other sites
Take a look at what happens when your old width=100 and new =98.

Step though it with a debugger and look at the values of j, particularly at the beginning and end of each row.

What do you get when you index an array with an index of -2?

##### Share on other sites
Wild guess:

float deltaX = oldWidth/newWidth;

should be

float deltaX = oldWidth/(float)newWidth;

##### Share on other sites
I'll check it, but I really don't think it is the cause of my problem. Here is an image of what I get when I try to scale an image by 70%. Anyway, I might hit the sack for a couple of hours and then see if any amazing epiphany comes to me. If that image shines any light on what is going on let me know, otherwise thanks for your help.

##### Share on other sites
Wow...that helped a lot, although my color values are still screwy. I updated the image to show my new results. Guess I'll be awake. And thanks sam.

##### Share on other sites
How does your filter function work? Does it return 1.0 when passed 0.0?

If so, then the sum of the filtered values over your 5 pixel range may be overflowing your byte range.

You would need to scale your final value to fit. I.e. sr/=sum(f.compute(-2.0 to +2.0));

##### Share on other sites
It also looks like you unintentionally "scale" y because you calculate the index before scaling:

old_index=scale(x)*old_width+y <--- what you want
old_index=scale(x*old_width+y) <--- what you do

##### Share on other sites
When passed 0, my filter returns 0.888 repeating. IT is an implementation of the mitchell-netravali filter (if that helps at all). sam I'm not quite sure I understand your lates post. If you are referring to my calculation of iPrime, I no longer do that. I changed my index function to reflect your post, but still get the same result. Here is my most recent code:

int index(int x, int y, int w) {
// returns an index for an rgba image
return ((y)*w+x)*4;
}

unsigned char* resampleX(unsigned char* source, int newWidth, int oldWidth, int height) {
unsigned char* result = new unsigned char[newWidth*height*4];
float deltaX = oldWidth/(float)newWidth;
float x0 = -0.5 + deltaX/2;
cubicFilter f;

int i = 0; // i is result image index

for(int row = 0; row < height; row++) {
for(int col = 0; col < newWidth; col++) {
float sr = 0,sg = 0,sb = 0,sa = 0;
i = index(col,row,newWidth);
int x = x0 + i * deltaX;
sr += source[(int)j] * f.compute(x-j);
sg += source[(int)j+1] * f.compute(x-j);
sb += source[(int)j+2] * f.compute(x-j);
sa += source[(int)j+3] * f.compute(x-j);
}
result[i] = sr;
result[i+1] = sg;
result[i+2] = sb;
result[i+3] = sa;
}
}

return result;

}

And thanks for your help guys, I would've gone nuts over this.

##### Share on other sites
As an aside, if your submitting this as a marked assignment, I'd tidy your code up to make it more readable. If I was marking it I'd have to mark you down for style.

Make your variable names more descriptive. e.g. Instead of sr, use fSource_Red.
Instead of i and iPrime, use iSourceIndex and iDestIndex.

If you used a basic reverse polish notation as above (i for int, f for float) it may make some of your code errors stand out much more clearly.

Personally, I don't like seeing multiple variables declared on one line, particularly if they are also initialised as well. Put them on separate lines.

The comment - '// set output image to new resized values' would make me believe that you are doing something like setting the resolution of the image rather than writing the new pixel colour.

##### Share on other sites
Yeah, I know, currently I am in "get it to work and screw readability" mode though. Hopefully I'll have some time to polish it before I submit it.

##### Share on other sites
Oh yes, another point,

float x0 = -0.5 + deltaX/2;

should really be

float x0 = -0.5f + deltaX/2.0f;

0.5 would be interpreted as a double and would have to be cast to a float by the compiler as a float. A non-optimising compiler would add in code to do this conversion producing slower larger code.

The similar thing would happen with 2. It would be interpreted by the compiler as (int)2. The compiler would then have to insert the code to convert an int 2 to floating point 2.0f.

##### Share on other sites
Quote:
 Original post by phase_vYeah, I know, currently I am in "get it to work and screw readability" mode though. Hopefully I'll have some time to polish it before I submit it.

That's a bad way to write code. If you write it correctly the first time you will save yourself a lot of time by avoiding writing errors, and save your hair when it comes to debugging.

I know you are learning, but it's best to learn the right way to do things now before the bad habits become your normal way of working.

Good luck with the assignment and the rest of your course.

##### Share on other sites
Thanks for the tips, and I'll check out that book. Considering my color problem, though, it seems to only occur in ceartain parts of the image. This can best be seen when I scale it down to about 1/3 the original size. Here is an image. I feel like this should indicate something, but my brain just isn't functioning (5am and all that)

##### Share on other sites
Quote:
 Original post by phase_vThanks for the tips, and I'll check out that book. Considering my color problem, though, it seems to only occur in ceartain parts of the image. This can best be seen when I scale it down to about 1/3 the original size. Here is an image. I feel like this should indicate something, but my brain just isn't functioning (5am and all that)

sr += source[(int)j] * f.compute(x-j);
sg += source[(int)j+1] * f.compute(x-j);
sb += source[(int)j+2] * f.compute(x-j);
sa += source[(int)j+3] * f.compute(x-j);

should be

sr += source[(int)(j*4)] * f.compute(x-j);
sg += source[(int)(j*4)+1] * f.compute(x-j);
sb += source[(int)(j*4)+2] * f.compute(x-j);
sa += source[(int)(j*4)+3] * f.compute(x-j);

##### Share on other sites
Hmmm, I don't think so. I believe that j already accounts for the rgba because of it's relation to x and i. i is the index value which is multiplied by 4. Correct me if I'm wrong, however when I implement this I get overflows and if I check against them only the bottom row of the image is drawn and things in that row aren't correct either. Any other ideas?

##### Share on other sites
Source is a char*.

Each pixel is 4 bytes wide. Therefore pixel 0 is at index 0, pixel 1 is at index 4, pixel 2 at index 8, etc. Therefore when you index individual pixels in your source image they should be 4 bytes apart. You increment j by one each loop, not 4.

You have another problem which I've also hinted at earlier. On the left hand side, x is 0. When you add subtract your radius from this (in yout inner loop) you get -2.

Really, the outer 2 (or radius) pixels are undefined. You need a way of dealing with this.

##### Share on other sites
Oops. My bad, I was 1/2 right anyway.

{
sr += source[(j*4)+x] * f.compute(x-j);
sg += source[(j*4)+x+1] * f.compute(x-j);
sb += source[(j*4)+x+2] * f.compute(x-j);
sa += source[(j*4)+x+3] * f.compute(x-j);
}

##### Share on other sites
What I meant was:

i = index(col,row,newWidth);
int x = x0 + i * deltaX;

The first line calculates the index, the second scales the index. This is wrong. What you want is to first scale the col, then calculate the index:

newIndex = index(col,row,newWidth);
oldIndex = index(col * deltaX,row,oldWidth)
int x = x0 + oldIndex;

##### Share on other sites
Ok, I edited my loops so it now looks like this:

for(int row = 0; row < height; row++) {
for(int col = 0; col < newWidth; col++) {
float sr = 0,sg = 0,sb = 0,sa = 0;
i = index(col,row,newWidth);
int x = x0 + i * deltaX;
if((j*4)>0 && (j*4)+3 < oldWidth * height * 4) {
sr += source[(int)(j*4)] * f.compute(x-j);
sg += source[(int)(j*4)+1] * (float)f.compute(x-j);
sb += source[(int)(j*4)+2] * (float)f.compute(x-j);
sa += source[(int)(j*4)+3] * (float)f.compute(x-j);
}
}

result[i] = (int)sr;
result[i+1] = (int)sg;
result[i+2] = (int)sb;
result[i+3] = (int)sa;
}
}

My result is this. The colors are right, but my scaling is odd to say the least. Actually, I guess I do have a scaled x,y image in there...