Jump to content

Suggestions on how to measure general brightness of an image


therks
 Share

Recommended Posts

So I don't have any code cooked up yet as this is still in the theoretical stage. Just looking for some advice.

My current idea is to resize the image to 1x1 pixel, probably using _GDIPlus_ImageResize, and read the color of the resulting pixel to obtain an admittedly very general sense of brightness. Does anyone think this could work?

We have a CCTV system running at home using some home made cameras (raspberry pi) and we're trying to automate toggling settings for day/night time. We started with an AutoIt script that checked sunrise and sundown times for our location (calculations pulled from here) and toggled the settings based on that. Unfortunately our weather varies wildly, so it can get light/dark far outside normal sunrise/sundown times. Now we're hoping to periodically grab a still from the camera and toggle the light mode based on that.

Link to comment
Share on other sites

I would go with something like this :

#include <Constants.au3>
#include <GDIPlus.au3>

_GDIPlus_Startup ()
$hBitmap = _GDIPlus_BitmapCreateFromFile ("Image.jpg")
$hBitMapResized = _GDIPlus_ImageResize ($hBitmap, 20, 20)
$tBitmapData = _GDIPlus_BitmapLockBits ($hBitMapResized, 0, 0, 20, 20, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
$iScan0 = DllStructGetData($tBitmapData, "Scan0")
$tPixel = DllStructCreate("int[400];", $iScan0)
Local $iMean = 0, $iStdDev = 0, $r, $g, $b
For $i = 1 to 400
  Split (DllStructGetData ($tPixel, 1, $i), $r, $g, $b)
  $iMean += $r+$g+$b
Next
$iMean /= 1200
For $i = 1 to 400
  Split (DllStructGetData ($tPixel, 1, $i), $r, $g, $b)
  $iStdDev += ($r-$iMean)^2
  $iStdDev += ($g-$iMean)^2
  $iStdDev += ($b-$iMean)^2
Next
$iStdDev = Sqrt($iStdDev/1200)
MsgBox ($MB_SYSTEMMODAL,"",$iMean & "/" & $iStdDev)
_GDIPlus_BitmapUnlockBits($hBitMapResized, $tBitmapData)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_BitmapDispose($hBitMapResized)
_GDIPlus_Shutdown ()

Func Split ($c, ByRef $r, ByRef $g, ByRef $b)
  $r = bitshift(bitand ($c,0xff0000),16)
  $g = bitshift(bitand ($c,0xff00),8)
  $b = bitand ($c,0xff)
EndFunc

Where the mean should be low for darker image and Standard Deviation also low for darker. I'm applying it for each component RGB, because global color doesn't say much.  Also going with a single (or a few) value, you will loose the StdDev significance.

I don't think anyone will argue that the lower is the mean (closer to 0), it implies that the image is quite dark. 

But even with a somewhat low mean, if you got a high StdDev, it implies that there is high contrast.  I would assume there is some brightness although part of the image is black.  So StdDev must be low as well.  Of course this is untested, and you will have to adjust the threshold of those indicator to fit your requirements.

Hope that make sense.

 

Link to comment
Share on other sites

@Nine: you're skipping half the outer rim of the image (range 0-20 = 21 pixels per side = 441 squared). Also, you lose one degree of freedom in calculating the mean, so you should divide by (3x441) - 1 = 1,323 -1 = 1322.

Edited by RTFC
Link to comment
Share on other sites

@RTFC.  It is not a range, it is a width and a height.  Major difference, so my code is good.

If you are still unsure use this code :

$tBitmapData = _GDIPlus_BitmapLockBits ($hBitMapResized, 0, 0, 20, 20, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
;Global Const $tagGDIPBITMAPDATA = "uint Width;uint Height;int Stride;int Format;ptr Scan0;uint_ptr Reserved"

$iScan0 = DllStructGetData($tBitmapData, "Scan0")
$iW = DllStructGetData($tBitmapData, "Width")
$iH = DllStructGetData($tBitmapData, "Height")
$iS = DllStructGetData($tBitmapData, "Stride")
ConsoleWrite ($iW & "/" & $iH & "/" & $iS & @CRLF)

 

Link to comment
Share on other sites

Well I appreciate the code there @Nine, but I was offline for a few days and cooked this up in the meantime.

Func _GetImageBrightness($sFile) ; Return: 0 black -> 100 white
    Local $hBitmap, $hBitMapResized, $iColor, $R, $G, $B
    $hBitmap = _GDIPlus_BitmapCreateFromFile($sFile)
    $hBitMapResized = _GDIPlus_ImageResize($hBitmap, 1, 1)
    $iColor = BitAND(_GDIPlus_BitmapGetPixel($hBitMapResized, 0, 0), 0xffffff)
    $R = BitShift(BitAND($iColor, 0xff0000), 16)
    $G = BitShift(BitAND($iColor, 0xff00), 8)
    $B = BitAND($iColor, 0xff)

    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_BitmapDispose($hBitMapResized)

    Return SetExtended($iColor, Sqrt( .241 * $R ^ 2 + .691 * $G ^ 2 + .068 * $B ^ 2 ) / 2.55)
EndFunc

It's not as thorough as yours, but in a few simple tests it seems to be working out alright. I'm combining this with a set of thresholds to determine when to activate either day or night mode on our cameras. The calculation for brightness came from here.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...