10

In a certain area of an educational website, students scan and submit their homework.

Problem: When students use pencil, the scans end up being very light and hard to read.

Can PHP be used to some how detect if a scan is too light? I'm wondering if something like Detecting colors for an Image using PHP or maybe How to detect "light" colors with PHP could be used, but I'm not sure. Thus the question.

I'm not asking for code necessarily, just seeing if it's possible and if there's some kind of function that already exists for this sort of thing.

UPDATE BASED ON h2ooooooo's ACCEPTED ANSWER

I'm wondering if PNG bit depth is causing a problem here. Using his (her?) solution, consider the following...

This image ("1.png") returns 97.8456638355 and has a bit depth of 32...

However, this image ("2.png") returns 98.4853859241 and has a bit depth of 24...

This is a difference of less than 1% and it seems like the 1.png should return with a lower number as it is significantly "crisper" and overall is darker than 2.png.

Does anyone have an idea if bit depth is causing the script to not work correctly?

Community
  • 1
  • 1
gtilflm
  • 1,389
  • 1
  • 21
  • 51
  • What is the problem if they write their homework in a file ? – php_nub_qq Feb 05 '14 at 14:38
  • Yes, you could easily convert to greyscale and calculate the average intensity, though with even a correct image having a lot of white, i imagin the margins could be quick small – Steve Feb 05 '14 at 14:38
  • Rather than light/dark your purpose could be better served by checking for contrast or better still presence of sharp edges. All are possible with image GD or ImageMagic. – Majid Fouladpour Feb 05 '14 at 14:38
  • [this way you determine if it is "dark"](http://stackoverflow.com/questions/7935814/how-to-determine-if-image-is-dark-high-contrast-low-brightness), so you just switch logic to your case ^^ You have got ImageMagick bindings inside PHP, or you can just call it via `system()` or `exec()`. – moonwave99 Feb 05 '14 at 14:39
  • Alternatly you could threshold the image and check black pixels > predifined value, though one again scale and other factors apply – Steve Feb 05 '14 at 14:40
  • Why not use a c++ library like opencv. You can call c++ code in php. Image processing is pretty cpu/gpu intensive so it might be better to do it with c++ and call it from php – SamFisher83 Feb 05 '14 at 15:16

4 Answers4

13

Something as simple as the following should work, simply going through every pixel and using the HSL algorithm in the thread you linked. For your purpose, you can simply take the value and compare it to a threshold (test various documents!).

Code:

<?php
    function getBrightness($gdHandle) {
        $width = imagesx($gdHandle);
        $height = imagesy($gdHandle);

        $totalBrightness = 0;

        for ($x = 0; $x < $width; $x++) {
            for ($y = 0; $y < $height; $y++) {
                $rgb = imagecolorat($gdHandle, $x, $y);

                $red = ($rgb >> 16) & 0xFF;
                $green = ($rgb >> 8) & 0xFF;
                $blue = $rgb & 0xFF;

                $totalBrightness += (max($red, $green, $blue) + min($red, $green, $blue)) / 2;
            }
        }

        imagedestroy($gdHandle);

        return ($totalBrightness / ($width * $height)) / 2.55;
    }
?>

Usage:

<?php
    var_dump( getBrightness( imagecreatefrompng('pic1.png') ) ); 
    // 22.626517105341

    var_dump( getBrightness( imagecreatefrompng('pic2.png') ) ); 
    // 60.289981746452

    var_dump( getBrightness( imagecreatefrompng('pic3.png') ) ); 
    // 77.183088971324
?>

Results:

pic1.png (22.62% bright):

enter image description here

pic2.png (60.28% bright):

enter image description here

pic3.png (77.18% bright):

enter image description here

NOTE:

This will take a very long time if the document is huge (it'll iterate through EVERY pixel). If you wish for it to be quicker, you can always pass a resized GD resource to the function instead.

Community
  • 1
  • 1
h2ooooooo
  • 39,111
  • 8
  • 68
  • 102
  • Could a PNG's bit depth be an issue here? I just updated the original post with two files and their values from your script. The one that returns 97.8456638355 should be lower, I believe. Thoughts? – gtilflm Feb 12 '14 at 03:23
0

Well given your explanation this is indeed the way to go. You are in the field of image processing now. PHP might not be the best solution here but generally it dumbs down on detecting contrast in an image.

You can actually enhance the contrast too. Here is one paper about that: http://www.cs.utexas.edu/~bajaj/cs384R10/lectures/2010_11_10_GeoModViz-Lec19a.pdf

Edit: ImageMagick can help you doing that.

Samuel
  • 6,126
  • 35
  • 70
0

You could use the code from the first example and find the 'peak' color used (the darkest). If it's not dark enough, you could then throw back a warning. You could also cut out the whites and really light greys (assuming those are the paper color) and then find the average of the colours, and if that's not dark enough, throw back a warning. PHP wouldn't really be the best language though; I've seen solutions that use ASP.NET and Javascript to perform such actions and also improve the contrast automatically when detecting 'bad' images.

DrewMunn
  • 1
  • 1
0

I made a small adjustment, added the precise option. Even with precise=10, checking every 10th pixel, the results did not much differ.

function getBrightness($gdHandle) {
    $width = imagesx($gdHandle);
    $height = imagesy($gdHandle);

    $totalBrightness = 0;
    $precise=5; //lower is more precise but slower
    
    for ($x = 0; $x < $width; $x+=$precise) {
        for ($y = 0; $y < $height; $y+=$precise) {
            $rgb = imagecolorat($gdHandle, $x, $y);

            
            
            $red = ($rgb >> 16) & 0xFF;
            $green = ($rgb >> 8) & 0xFF;
            $blue = $rgb & 0xFF;
            
            $totalBrightness += (max($red, $green, $blue) + min($red, $green, $blue)) / 2;
        }
    }

    imagedestroy($gdHandle);
    return ($totalBrightness / (($width/$precise) * ($height/$precise))) / 2.55;

 // USAGE $var=getBrightness(imagecreatefromjpeg('pic1.jpg')); 
Baz
  • 41
  • 3