New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Regression test for color distance #5
Comments
Example code (https://jsbin.com/xujizi/edit?js,console): var gray30 = [0.3, 0.3, 0.3, 255];
var gray50 = [0.5, 0.5, 0.5, 255];
var gray60 = [0.6, 0.6, 0.6, 255];
var gray100 = [1.0, 1.0, 1.0, 255];
console.log(Math.abs(colorDelta(gray30, gray60, 0, 0, true))); // 0.3...
console.log(Math.abs(colorDelta(gray50, gray100, 0, 0, true))); // 0.499...
console.log(Math.sqrt(colorDelta(gray30, gray60, 0, 0, false))); // 0.3...
console.log(Math.sqrt(colorDelta(gray50, gray100, 0, 0, false))); // 0.499... |
Just to be clear, this is working correctly, just needs a test, right? |
Also, RGB values are also 0-255. |
For the comparison with // maximum acceptable square YUV distance between two colors
var maxDelta = 255 * 255 * 3 * threshold * threshold I've ported the code to Java/Kotlin and changed the RGB values to be within 0..1, used a more computational intensive // pixels are similar; draw background as grayscale image blended with white
var val = 255 - 0.1 * (255 - grayPixel(img1, pos)) * img1[pos + 3] / 255; My version (basically a // factor = 0.0 leaves the luma unchanged. factor = 1.0 changes luma to total white.
fun blendToWhite(luma: Double,
factor: Double): Double {
//return 1.0 - ((1.0 - luma) * factor) // similar to the javascript implementation
return ((1.0 - factor) * luma) + (factor * 1.0)
} Before that the diff images were equal to the images from |
Another example (https://jsbin.com/nulode/edit?js,console): var white = [255, 255, 255, 255];
var gray50 = [0.5 * 255, 0.5 * 255, 0.5 * 255, 255];
var gray60 = [0.6 * 255, 0.6 * 255, 0.6 * 255, 255];
console.log(Math.abs(colorDelta(gray50, gray60, 0, 0, true)) / 255); // 0.1
console.log(Math.sqrt(colorDelta(gray50, gray60, 0, 0, false)) / 255); // 0.1
console.log(pixelmatch(gray50, gray60, white, 1, 1, {threshold: 0.1})); // 0
console.log(pixelmatch(gray50, gray60, white, 1, 1, {threshold: 0.057})); // 1
console.log(pixelmatch(gray50, gray60, white, 1, 1, {threshold: 0.058})); // 0 Here the color delta is exactly |
But maybe I missed something. It also doesn't work with |
You need to understand what a color distance is. Distance is Closing as this is not an issue and I don't think the |
Ahh, thanks, I see. The gray example colors caused the color distance to be 0.1, because gray colors only use the Y luma channel in Y'UV, that means calculated distance was There is a small thing I wanted to point out as a side note: For RGB the maximum distance is
If you use RGB values with a range from 0 to 255 (instead of 0 to 1) you have to multiply them with 255. You see that the V difference of red (-0.615 * 255) and cyan (0.615 * 255) is bigger than So the real max distance for Y'UV colors calculated using RGB colors might be a bit smaller than the max distance we use. But well, I think even if we have distances that a bigger than max distance it doesn't matter much in practice for the test cases. |
Hmm, yeah, you're probably right. We need to figure out the max and adjust. |
The naive approach would be to go through all 255 * 255 * 255 RGB colors convert them to Y'UV and store min and max values of Y', U and V. I wonder what literature says about maximum color distance for the |
Calculated — the max seems to be just a little bit bigger: Math.sqrt(Math.pow(255 * 0.436 * 2, 2) + Math.pow(255 * 0.615 * 2, 2) + Math.pow(255, 2))
461.3515927142768
Math.sqrt(255 * 255 * 3)
441.6729559300637 |
Yeah. So this is the maximum distance for Y'UV colors. Seems to be a better value for max distance. As noted We could go even further with calculations for the max distance, but I think 461.35... is quite good. |
Interesting, I'd be up to looping through all RGB values and determining the max distance, just out of curiousity. |
I'd be interested which pair of RGB color triples give us the max distance. This could be computational intensive to loop through all pairs of RGB values. |
@hastebrot no, we'd just calculate the max once and then insert that as a constant. |
I get following results (https://github.com/hastebrot/notebooks/blob/master/ipython/yuv-color-range.ipynb): Max distance between two Y'UV colors (which were converted from RGB colors) is between red and cyan: min_yuv = (0, -U_MAX * 255, -V_MAX * 255)
max_yuv = (255, U_MAX * 255, V_MAX * 255)
red_yuv = to_yuv(255, 0, 0)
cyan_yuv = to_yuv(0, 255, 255)
print("dist(min, max):", yuv_dist(min_yuv, max_yuv) ** 0.5)
print("dist(red, cyan):", yuv_dist(red_yuv, cyan_yuv) ** 0.5)
# dist(min, max): 461.3515927142768
# dist(red, cyan): 338.2928543947083 I've used 5832 evenly distributed RGB triples, within a distance of 15 per channel. print("num of colors:", len(colors))
print("color steps:", range(0, 255 + 1, color_step))
# num of colors: 5832
# color steps: range(0, 256, 15) Max color distances sorted in descending order (we see a clear trend here, so I think my calculations are correct):
|
Hmm, there are some doublets, but with different color distances. Maybe a rounding error. 😕 |
Cool, thanks! Actually I'm starting to think that YUV distance is not the best metric of human-perceived color difference. CIEDE2000 is considered the best metric (https://en.wikipedia.org/wiki/Color_difference), but it's very computationally expensive: https://github.com/markusn/color-diff. I still want to try it out. |
Found this excellent paper that describes a color difference algorithm that's close to CIEDE2000 but very fast to compute: http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf |
From the abstract of Kotsarenko et. al.:
This sounds great. |
…dd-examples-and-gifs-to-readme to master * commit '0e63081c2a8dd51b42f8bc8edf7e94fc5916719b': docs(README): adding gifs to illustrate example usage
feat(matcher): add noColors options
To ensure the color distance is correctly compared to the comparison threshold.
The text fixture could be an image with gray background
rgb(0.5, 0.5, 0.5)
and an image that contains gray tones with different color offsets (e.g. withrgb(0.6, 0.6, 0.6)
, which should return a color difference of 0.1).The text was updated successfully, but these errors were encountered: