• Create Account

### #ActualL. Spiro

Posted 06 October 2012 - 05:32 AM

The simplest way would be to

int weight = 0;

for each (testPixel)
{
weight += abs(originalPixel.r - testPixel.r);   // assuming each channel [0,255];
weight += abs(originalPixel.g - testPixel.g);
weight += abs(originalPixel.b - testPixel.b);
}


The lower the weight the better the match.

This is not the way to go and can in fact be very hurtful to the actual result.

What you want is to use MSE (mean squared error) if your goal is simply to compare qualities between different images, or PSNR (peak signal-to-noise-ratio) if you want to discretely quantify the differences between your images (in other words, calculating the MSE is part of determining the PSNR, and a higher MSE always results in a lower dB (the measurement for PSNR), so if your goal is simply to compare images to determine which is closer to the original than another, MSE is all that is needed, whereas if you want to quantify exactly how close using dB, you should continue on and calculate the PSNR, although even still this part is optional).

For MSE (all you probably really need), the pseudo code would be:
error = 0
for ( all Y ) {
for ( all X ) {
error += (src(X, Y) - copy(X, Y)) * (src(X, Y) - copy(X, Y))
}
}
error /= (width * height)

This is applied to each channel separately, so you would have one error value for R, one for G, and one for B.

Then you apply perceptual weights to these error values based on how humans perceive light.

Common weights are:
(0.299f, 0.587f, 0.114f)
(0.212656f, 0.715158f, 0.072186f)
(0.3086f, 0.6094f, 0.082f)

Notice how they all add up to 1, and also how green is always weighted much higher than the rest. This is also why the 565 16-bit color format exists, because green is the most important color perceptually. For example, if it was instead red that was most important to us humans, the 16-bit color format would instead have been 655.

Your final total perceptually adjusted error would be (assuming weights of (0.212656f, 0.715158f, 0.072186f)):
redError * 0.212656f + greenError * 0.715158f + blueError * 0.072186f

This gets you a properly weighted perceptually adjusted error metric that allows you to determine how close you are to the original, and is simple to implement.

L. Spiro

### #2L. Spiro

Posted 06 October 2012 - 05:31 AM

The simplest way would be to

int weight = 0;

for each (testPixel)
{
weight += abs(originalPixel.r - testPixel.r);   // assuming each channel [0,255];
weight += abs(originalPixel.g - testPixel.g);
weight += abs(originalPixel.b - testPixel.b);
}


The lower the weight the better the match.

This is not the way to go (and the weight term essentially has no meaning, since lowering it by, for example, half would result on an error value that is halved for the same image, yet the image is not actually twice as close to a real match).

What you want is to use MSE (mean squared error) if your goal is simply to compare qualities between different images, or PSNR (peak signal-to-noise-ratio) if you want to discretely quantify the differences between your images (in other words, calculating the MSE is part of determining the PSNR, and a higher MSE always results in a lower dB (the measurement for PSNR), so if your goal is simply to compare images to determine which is closer to the original than another, MSE is all that is needed, whereas if you want to quantify exactly how close using dB, you should continue on and calculate the PSNR, although even still this part is optional).

For MSE (all you probably really need), the pseudo code would be:
error = 0
for ( all Y ) {
for ( all X ) {
error += (src(X, Y) - copy(X, Y)) * (src(X, Y) - copy(X, Y))
}
}
error /= (width * height)

This is applied to each channel separately, so you would have one error value for R, one for G, and one for B.

Then you apply perceptual weights to these error values based on how humans perceive light.

Common weights are:
(0.299f, 0.587f, 0.114f)
(0.212656f, 0.715158f, 0.072186f)
(0.3086f, 0.6094f, 0.082f)

Notice how they all add up to 1, and also how green is always weighted much higher than the rest. This is also why the 565 16-bit color format exists, because green is the most important color perceptually. For example, if it was instead red that was most important to us humans, the 16-bit color format would instead have been 655.

Your final total perceptually adjusted error would be (assuming weights of (0.212656f, 0.715158f, 0.072186f)):
redError * 0.212656f + greenError * 0.715158f + blueError * 0.072186f

This gets you a properly weighted perceptually adjusted error metric that allows you to determine how close you are to the original, and is simple to implement.

L. Spiro

### #1L. Spiro

Posted 06 October 2012 - 05:29 AM

The simplest way would be to

int weight = 0;

for each (testPixel)
{
weight += abs(originalPixel.r - testPixel.r);   // assuming each channel [0,255];
weight += abs(originalPixel.g - testPixel.g);
weight += abs(originalPixel.b - testPixel.b);
}


The lower the weight the better the match.

This is not the way to go (and the weight term essentially has no meaning, since lowering it by, for example, half would result on an error value that is halved for the same image, yet the image is not actually twice as close to a real match).

What you want is to use MSE (mean squared error) if your goal is simply to compare qualities between different images, or PSNR (peak signal-to-noise-ratio) if you want to discretely quantify the differences between your images (in other words, calculating the MSE is part of determining the PSNR, and a higher MSE always results in a lower dB (the measurement for PSNR), so if your goal is simply to compare images to determine which is closer to the original than another, MSE is all that is needed, whereas if you want to quantify exactly how close using dB, you should continue on and calculate the PSNR, although even still this part is optional).

For MSE (all you probably really need), the pseudo code would be:
error = 0
for ( all Y ) {
for ( all X ) {
error += (src(X, Y) - copy(X, Y)) * (src(X, Y) - copy(X, Y))
}
}
error /= (width * height)

This is applied to each channel separately, so you would have one error value for R, one for G, and one for B.

Then you apply perceptual weights to these error values based on how humans perceive light.

Common weights are:
(0.299f, 0.587f, 0.114f)
(0.212656f, 0.715158f, 0.072186f)
(0.3086f, 0.6094f, 0.082f)

Notice how they all add up to 1, and also how green is always weighted much higher than the rest. This is also why the 565 16-bit color format exists, because green is the most important color perceptually. For example, if it was instead red that was most important to us humans, the 16-bit color format would instead have been 655.

Your final total perceptually adjusted error would be (assuming weights of (0.212656f, 0.715158f, 0.072186f)):
redError * 0.212656f + greenError * 0.715158f + blueError * 0.072186f

This gets you a properly weighted perceptually adjusted error metric that allows you to determine how close you are to the original.

L. Spiro

PARTNERS