Discussion:
Imresize (rounding vs. Floor function)
(too old to reply)
Mk
2004-11-23 18:42:11 UTC
Permalink
Does anyone know why Imresize was implemented such that prior to
rounding (after quantization occurs) why is the floor function used
instead of a simple rounding of pixel values?
Steve Eddins
2004-11-23 21:45:35 UTC
Permalink
Post by Mk
Does anyone know why Imresize was implemented such that prior to
rounding (after quantization occurs) why is the floor function used
instead of a simple rounding of pixel values?
I see three uses of floor in imresize.m:

* computation of output image size

* computation of filter length for antialiasing filter

* computation of index vectors in the nearest neighbor interpolation code

I don't see any places where floor is applied to pixel values.

Can you say more specifically which use of floor bothers you and why?
--
Steve Eddins

Development Manager, Image Processing Group
The MathWorks, Inc.
mk
2004-11-24 03:37:24 UTC
Permalink
Well, its not directly in the imresize function...

After the image has been altered...if the class of the input image
has changed, it has to be chnaged back...

A = changeclass(inputClass, A);

Within this function, take for example that an grayscale image has to
be converted back to uint8. Im2uint8.m gets called, which contains
the private mex file (grayto8.c).

It is within this grayto8 function in which quantization occurs.

Now I can't find the actual call to the floor function, but I
modified the imresize function to call my own im2uint8 file in which
I incorporate the gray28 mex file within the matlab code.

to make a long story short, I then did a floor of these unrounded
values and compared it to matlab's built in function, and it came out
exact.

I guess I don't understand where the floor is coming from. Here is
the "quantization" code from grayto8.c

for (k = 0; k < numElements; k++)
{
val = *pr++;
if (mxIsNaN(val)) {
*qr++ = 0;
}
else {
val = val * 255.0 + 0.5;
if (val > 255.0) val = 255.0;
if (val < 0.0) val = 0.0;
*qr++ = val;
}
}

Could the floor be performed because the value .5 is being added to
each quantized pixel value? (val = val * 255.0 + 0.5;)
Steve Eddins
2004-11-24 13:14:53 UTC
Permalink
Post by mk
Could the floor be performed because the value .5 is being added to
each quantized pixel value? (val = val * 255.0 + 0.5;)
Yes. floor(x + 0.5) is the same as round(x), assuming that 0.5 rounds up.
--
Steve Eddins

Development Manager, Image Processing Group
The MathWorks, Inc.
Peter Boettcher
2004-11-24 15:14:30 UTC
Permalink
Post by mk
Well, its not directly in the imresize function...
[...]
Post by mk
to make a long story short, I then did a floor of these unrounded
values and compared it to matlab's built in function, and it came out
exact.
I guess I don't understand where the floor is coming from. Here is
the "quantization" code from grayto8.c
for (k = 0; k < numElements; k++)
{
val = *pr++;
if (mxIsNaN(val)) {
*qr++ = 0;
}
else {
val = val * 255.0 + 0.5;
if (val > 255.0) val = 255.0;
if (val < 0.0) val = 0.0;
*qr++ = val;
}
}
Could the floor be performed because the value .5 is being added to
each quantized pixel value? (val = val * 255.0 + 0.5;)
It is precisely this 0.5 which makes the operation round INSTEAD of
floor. In C, casting from a floating-point to an integer is always a
truncation (towards zero). Adding 0.5 before truncating is equivalent
to rounding (at least for positive values).

What code do you use for converting [0,1] image data to 8-bit
representation?


Now on second thought, something seems funny about this conversion.
The *255 means that half as many floats around 0.0 map to uint8 0, and
half as many around 1.0 map to uint8 255, compared to all the other
integers.

[0 , .5/255] => 0
[0.5/255, 1.5/255] => 1
[1.5/255, 2.5/255] => 2
...
[254.5/255, 1] => 255

That's a range of .5/255 for results 0 and 255, and 1/255 for all the
others. Plot this to see what I'm talking about:
x=linspace(0,1,1e5); v=floor(255*x+0.5); plot(x,v);

I think I'd rather map [0,1/256] => 0, up to [255/256,256] => 255,
which is more uniform.

Can anyone explain the preference for the code above?
--
Peter Boettcher <***@ll.mit.edu>
MIT Lincoln Laboratory
MATLAB FAQ: http://www.mit.edu/~pwb/cssm/
Steve Eddins
2004-12-01 17:29:40 UTC
Permalink
Peter Boettcher <***@ll.mit.edu> writes:

[snip]
Post by Peter Boettcher
Now on second thought, something seems funny about this conversion.
The *255 means that half as many floats around 0.0 map to uint8 0, and
half as many around 1.0 map to uint8 255, compared to all the other
integers.
[0 , .5/255] => 0
[0.5/255, 1.5/255] => 1
[1.5/255, 2.5/255] => 2
...
[254.5/255, 1] => 255
That's a range of .5/255 for results 0 and 255, and 1/255 for all the
x=linspace(0,1,1e5); v=floor(255*x+0.5); plot(x,v);
I think I'd rather map [0,1/256] => 0, up to [255/256,256] => 255,
which is more uniform.
Can anyone explain the preference for the code above?
There's nothing nonuniform about the round operation. It's just that the
top and bottom bins are different than what you describe.

[-.5/255, .5/255) => 0

...

[254.5/255, 255.5/255) => 255

The bins resulting from the posted code actually extend down to -inf and up
to +inf, but that's from the saturation step, not the rounding step.
--
Steve Eddins

Development Manager, Image Processing Group
The MathWorks, Inc.
Peter Boettcher
2004-12-01 19:02:18 UTC
Permalink
Post by Steve Eddins
[snip]
Post by Peter Boettcher
Now on second thought, something seems funny about this conversion.
The *255 means that half as many floats around 0.0 map to uint8 0, and
half as many around 1.0 map to uint8 255, compared to all the other
integers.
[0 , .5/255] => 0
[0.5/255, 1.5/255] => 1
[1.5/255, 2.5/255] => 2
...
[254.5/255, 1] => 255
That's a range of .5/255 for results 0 and 255, and 1/255 for all the
x=linspace(0,1,1e5); v=floor(255*x+0.5); plot(x,v);
I think I'd rather map [0,1/256] => 0, up to [255/256,256] => 255,
which is more uniform.
There's nothing nonuniform about the round operation. It's just that the
top and bottom bins are different than what you describe.
[-.5/255, .5/255) => 0
...
[254.5/255, 255.5/255) => 255
The bins resulting from the posted code actually extend down to -inf and up
to +inf, but that's from the saturation step, not the rounding step.
Exactly. The [-.5/255, 0) part of the interval is never used by valid
MATLAB images.

I'm talking about the valid domain of MATLAB images specified using
doubles. Consider an intensity image with pixels uniformly
distributed between 0 and 1. After converting to bytes, the number of
0 and 255 pixels will be about half as many as all the others.

x=im2uint8(rand(1000,1000));
hist(double(x(:)), 0:255)
--
Peter Boettcher <***@ll.mit.edu>
MIT Lincoln Laboratory
MATLAB FAQ: http://www.mit.edu/~pwb/cssm/
Steve Eddins
2004-12-20 16:21:52 UTC
Permalink
Post by Peter Boettcher
Post by Steve Eddins
[snip]
Post by Peter Boettcher
Now on second thought, something seems funny about this conversion.
The *255 means that half as many floats around 0.0 map to uint8 0, and
half as many around 1.0 map to uint8 255, compared to all the other
integers.
[0 , .5/255] => 0
[0.5/255, 1.5/255] => 1
[1.5/255, 2.5/255] => 2
...
[254.5/255, 1] => 255
That's a range of .5/255 for results 0 and 255, and 1/255 for all the
x=linspace(0,1,1e5); v=floor(255*x+0.5); plot(x,v);
I think I'd rather map [0,1/256] => 0, up to [255/256,256] => 255,
which is more uniform.
There's nothing nonuniform about the round operation. It's just that the
top and bottom bins are different than what you describe.
[-.5/255, .5/255) => 0
...
[254.5/255, 255.5/255) => 255
The bins resulting from the posted code actually extend down to -inf and up
to +inf, but that's from the saturation step, not the rounding step.
Exactly. The [-.5/255, 0) part of the interval is never used by valid
MATLAB images.
I'm talking about the valid domain of MATLAB images specified using
doubles. Consider an intensity image with pixels uniformly
distributed between 0 and 1. After converting to bytes, the number of
0 and 255 pixels will be about half as many as all the others.
x=im2uint8(rand(1000,1000));
hist(double(x(:)), 0:255)
Would engineering be any fun if you didn't have to make tradeoffs?

If you start with a double value, convert to uint8 using your procedure,
and then convert back to double using a 1.0/255.0 scale factor, you get a
maximum absolute error of 1/256. Using the IPT conversion conventions, you
get a maximum absolute error that's half as big.

I guess you could make the double -> uint8 conversion rule more complicated
in order to compensate, but I question the benefit.
--
Steve Eddins

Development Manager, Image Processing Group
The MathWorks, Inc.
Himesh Raja
2020-11-26 07:04:11 UTC
Permalink
Best Sexologist in Delhi NCR and All Time Answer to better result https://bit.ly/389gXml
Loading...