Fast Algorithm to Determine Average Brightness of an Image

Sannyasin Brahmanathaswami brahma at hindu.org
Tue Sep 20 21:52:17 EDT 2016


@ HH

OK I will "bite" on your idea.  but I have never examined or processed the imagedata. Please scrutinize my code below.  But there is a major caveat with your original code (see below)

I think I got it correct. 

but there is a huge difference on the result between the 1 X 1 and the 12 X 9

I have a late afternoon shot of the sun setting over the ocean. your original function returns

148.981481 # which seems too low…

But if I did this correctly (I may not have)

I get 

192.333333  # which seems a lot more correct visually because this is bright image.

average across 12x 9 = 108 px = 432 bytes of image data.

did I do something wrong here. (disclaimer… this could probably be optimized…but still very fast)


function avgBrightness theImage
   --lock screen; lock messages
   
   if there is no img ii then create img ii
   set resizeQuality of img ii to "best"
   
   put the width of img 1 into tOrigWidth
   put the height of img 1 into tOrigHeight
   
   set width of img ii to tOrigWidth
   set height of img ii to tOrigHeight
   
   set imagedata of img ii to the imagedata of img theImage
   
   put 12 into tNewWidth
   
   # Scale down proportinally
   set the width of img ii to tNewWidth
   put  round ( (tOrigHeight*tNewWidth)/tOrigWidth) into tNewHeight
   set height of img ii to tNewHeight
   
   --set width of img ii to 1
   --set height of img ii to 1
   
   put the imagedata of img ii into iData
   
   put tNewWidth * tNewHeight * 4 into tNoPixelBytes
   
   delete img ii
   
   # get beyond first byte otherwise mod 4 returns bogus value

   put (byteToNum(byte 2 of iData) & "," &\
   byteToNum(byte 3 of iData) & "," &\
   byteToNum(byte 4 of iData) & ",")   into tAllPixelColorValues
   
   repeat with x = 5 to tNoPixelBytes
      if x mod 4 = 1 then next repeat # skip this one, all zeros here.
      put byteToNum(byte x of iData) &"," after tAllPixelColorValues
   end repeat

   put empty into item -1 of tAllPixelColorValues # remove last empty itm
   
  return avg (tAllPixelColorValues)
      unlock screen; unlock messages
   end avgBrightness
BR


But if you use your original code  and do not delete img ii, a different value is returned than if you uncomment that line.. if you delete img ii you get a different value.



function avgBrightness1 theImage
   --lock screen; lock messages
   
  if there is no img ii then create img ii
  set resizeQuality of img ii to "best"
  
  put the width of img 1 into tOrigWidth
  put the height of img 1 into tOrigHeight
  
  set imagedata of img ii to the imagedata of img theImage
  set width of img ii to 1
  set height of img ii to 1
 put the imagedata of img ii into iData
 --delete img ii
  return avg (byteToNum(byte 2 of iData), \
        byteToNum(byte 3 of iData), \
        byteToNum(byte 4 of iData))
  --unlock screen; unlock messages
end avgBrightness1
 

On 9/20/16, 1:31 PM, "use-livecode on behalf of hh" <use-livecode-bounces at lists.runrev.com on behalf of hh at hyperhh.de> wrote:

    There is still one option that uses a weighted grayLevel-mean
    (I use these weights in imageJIT). This would reflect more
    than simple averaging that one wants a dark/light decision.
    
    return (0.1*byteToNum(byte 2 of iData) \
          + 0.6*byteToNum(byte 3 of iData) \
          + 0.3*byteToNum(byte 4 of iData))
    
    Also, what will be still fast enough, you could think about 
    scaling down _proportional_ to 3x2 pixels (or 12x8 pixels)
    and then applying the above weighted mean on these few pixels.
    
    p.s. I checked: The one-pixel color is by LC built from the
    arithmetic mean of the color channels, nearly as fast as an external!
    
    



More information about the use-livecode mailing list