Background image dark or light?
Asked Answered
I

3

16

I'm doing a ODP->HTML conversion with PHP. I have problems with the following:

Use the style:use-window-font-color property to specify whether or not the window foreground color should be as used as the foreground color for a light background color and white for a dark background color.

(OpenDocument specification version 1.0, 15.4.4)

If i have a background image, how do i check, if this image is light or dark?

Do you have any ideas?

Thanks in advance, Levu

Intarsia answered 30/4, 2011 at 14:40 Comment(0)
F
38

I thought this was quite an interesting problem to solve, so i hacked up a quick script to do it. following the other suggestions provided

<?php

    // TODO supply your own filenames
    $filenames = array(
        'testpics/client-bella-vi.jpg',
        'testpics/istockphoto_8577991-concept-of-business-people-crowd.jpg',
        'testpics/medium-gray.jpg');

    // loop though each file
    foreach ($filenames as $filename) {

        echo "$filename<br/>";

        $luminance = get_avg_luminance($filename,10);
        echo "AVG LUMINANCE: $luminance<br />";

        // assume a medium gray is the threshold, #acacac or RGB(172, 172, 172)
        // this equates to a luminance of 170
        if ($luminance > 170) {
            echo "Black Text<br />";
        } else {
            echo 'White Text<br />';
        }

        echo "<br />";
    }
    exit;

    // get average luminance, by sampling $num_samples times in both x,y directions
    function get_avg_luminance($filename, $num_samples=10) {
        $img = imagecreatefromjpeg($filename);

        $width = imagesx($img);
        $height = imagesy($img);

        $x_step = intval($width/$num_samples);
        $y_step = intval($height/$num_samples);

        $total_lum = 0;

        $sample_no = 1;

        for ($x=0; $x<$width; $x+=$x_step) {
            for ($y=0; $y<$height; $y+=$y_step) {

                $rgb = imagecolorat($img, $x, $y);
                $r = ($rgb >> 16) & 0xFF;
                $g = ($rgb >> 8) & 0xFF;
                $b = $rgb & 0xFF;

                // choose a simple luminance formula from here
                // https://mcmap.net/q/20665/-formula-to-determine-perceived-brightness-of-rgb-color
                $lum = ($r+$r+$b+$g+$g+$g)/6;

                $total_lum += $lum;

                // debugging code
     //           echo "$sample_no - XY: $x,$y = $r, $g, $b = $lum<br />";
                $sample_no++;
            }
        }

        // work out the average
        $avg_lum  = $total_lum/$sample_no;

        return $avg_lum;
    }
Fewness answered 11/5, 2011 at 4:57 Comment(12)
What would you recommend for the number of samples of an images at around 600x400? I think 10 isn't really working.. PS awesome answer!!Brechtel
For example farm6.staticflickr.com/5478/14085542631_6649f0a995_b.jpg is coming as 107 and it is very light and probably wouldn't work with a white font. and farm4.staticflickr.com/3912/15197127275_74754c631f_b.jpg is coming as 97 and it pretty dark? (this is when working with 100 num samples)Brechtel
It's a bit of trial and error, but for a start your image is 1024x683 = 700,000 pixels or so, divide that by 100 and you have 1 sample per 7000 pixels. The sample would only have to land on a few of this lights in the harbour and it would throw the average out. I would bump it up a bit, try 1,000 samples and see what you get. Time it and see what is acceptable for your performance needs,Fewness
Another option, not sure if it is faster or not would be to blur the image firstFewness
Okay awesome. What about if we edit your function slightly and make two ranges 0 - (width of photo) and 0 - (height of photo) then randomly select pixels. Store the pixel and make an if statement to make sure not to use it again? Surely that will provide a more acurate result?Brechtel
Give it a blast, i would be interested to see the results, what is there works fine for me, but your suggestion of randoms pixels sounds like a valid oneFewness
I have tried the random one but I have also thought about adding a test to see whether the actual pixel is too large say nearly completely white then, that is a sign that there might be a big white patch?Brechtel
Sounds like you are starting to get quite specific to your application, you could exclude pixels with a brightness above x and below x, but then what happens if someone runs it on a white image? It would probably work better if you increase the size of each sample and took the median value, So for example rather then just checking 1 pixel, also check the 8 (or more) nearest neighbors and take the median rather then the average. Just out of curiosity if you sampled every pixel in the image do you get the expected result?Fewness
I have not actually tested that yet... Hahah! ahh that is a very good idea I will try that! The actual application is searching through a tumblr account picking all the flickr accounts from it and then testing the brightness and if it is then < 100 I set it to be blurry and upload it to my server. So that requires quite a lot of stress on the server and usually results in a time out if I set the pixel check to more than 100! And obviously it is impossible to tell how many photos it will check before it spits one out.Brechtel
Another thought, what if you try the median of the complete sample rather then the average, that way a few bright spots will no sway the result so much. If you are timingout sounds like you need to run your task as a cron job or from the cmd line, so that it can run indefinitely.Fewness
Cron will still time out? But cmd line sounds like a good idea!! Yeah I will get on it now!! Do you want me to send you the code after?Brechtel
You could post your solution here as an answer so that others can reference. cron should not timeout, it is just the system calling the php script, same as if you called it via the cmd line.Fewness
A
4

you could possibly use some image processing algorithm that would examine the pixel brightness and calculate mean image brightness.

this document will get you started:

http://www.kweii.com/site/color_theory/2007_LV/BrightnessCalculation.pdf

Ate answered 8/5, 2011 at 5:37 Comment(5)
i see there many different formulas for calculating brightness, which one should I use? Luma?Intarsia
it depends on your exact needs, but I think luma or any other can do the work for your problem.Ate
just choose and adapt the alogithm that you think is easiest to understand for you.Ate
i don't need to fully understand the algorithm but the result has to be perfect :)Intarsia
for your purpose, any brightness processing algorightms will give perfect and acurate results. I simply sugested to pick a more easily understandable algorithm for you, because that will make it easier to implement it or even modify it if you will need to.Ate
M
3

If you're looking to use GD, trying using imagecolorat to sample pixels of the image. You can determine the RGB of the color as shown on the PHP man page.

Next, take the RGB sample(s) and determine their brightness using a basic luminance formula.

Determine a threshold for what you consider light vs. dark and categorize accordingly.

Malinger answered 11/5, 2011 at 4:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.