Is it posible to know the brightness of a picture in Flutter?
There are several things wrong with your code.
First, you are getting a range error because you are attempting to access a pixel that doesn't exist. This is probably due to width
and/or height
being greater than the image's actual width or height. There are a lot of ways to try and get these values, but for this application it doesn't actually matter since the end result is to get an average value across all pixels in the image, and you don't need the width or height of the image for that.
Second, you are fetching the color values by serializing the color value into a hex string and then parsing the individual channel substrings. Your substring
is going to result in incorrect values because:
foo.substring(a, b)
takes the substring offoo
froma
tob
, exclusive. That means thata
andb
are indices, not lengths, and the resulting string will not include the character atb
. So assuminghex
is "01234567", when you dohex.substring(0, 2)
, you get "01", and then you dohex.substring(3, 5)
you get "34" whilehex.substring(6, 8)
gets you "67". You need to dohex.substring(0, 2)
followed byhex.substring(2, 4)
andhex.substring(4, 6)
to get the first three channels.- That being said, you are fetching the wrong channels. The
image
package stores its pixel values in ABGR format, meaning the first two characters in the hex string are going to be the alpha channel which is unimportant when calculating image brightness. Instead, you want the second, third, and forth channels for the blue, green, and red values respectively. - And having said all that, this is an extremely inefficient way to do this anyway when the preferred way to retrieve channel data from an integer color value is with bitwise operations on the integer itself. (Never convert a number to a string or vice versa unless you absolutely have to.)
So in summary, what you want will likely be something akin to the following;
final pixels = image.data;
double colorSum = 0;
for (int i = 0; i < pixels.length; i++) {
int pixel = pixels[i];
int b = (pixel & 0x00FF0000) >> 16;
int g = (pixel & 0x0000FF00) >> 8;
int r = (pixel & 0x000000FF);
avg = (r + g + b) / 3;
colorSum += avg;
}
return colorSum / pixels.length;
Nicolas Lucero
Updated on December 24, 2022Comments
-
Nicolas Lucero over 1 year
I am building an application which has a Camera inside.
After I take a photo, I want to analyze it to know the brightness of this picture, if it is bad I have to take again the photo.
This is my code right now, it's a javascript function that I found and writing in Dart:
Thanks to @Abion47
EDIT 1
for (int i = 0; i < pixels.length; i++) { int pixel = pixels[i]; int b = (pixel & 0x00FF0000) >> 16; int g = (pixel & 0x0000FF00) >> 8; int r = (pixel & 0x000000FF); avg = ((r + g + b) / 3).floor(); colorSum += avg; } brightness = (colorSum / (width * height)).floor(); } brightness = (colorSum / (width * height)).round(); // I tried with this other code //brightness = (colorSum / pixels.length).round(); return brightness;
But I've got less brightness on white than black, the numbers are a little bit weird.
Do you know a better way to know the brightness?
SOLUTION:
Under further investigation we found the solution, we had an error doing the image decoding, but we used a Image function to do it.
Here is our final code:
Image image = decodeImage(file.readAsBytesSync()); var data = image.getBytes(); var colorSum = 0; for(var x = 0; x < data.length; x += 4) { int r = data[x]; int g = data[x + 1]; int b = data[x + 2]; int avg = ((r + g + b) / 3).floor(); colorSum += avg; } var brightness = (colorSum / (image.width * image.height)).floor(); return brightness;
Hope it helps you.
-
Abion47 over 3 yearsWhat is the width and height of the image object and how are you getting them?
-
Abion47 over 3 yearsAlso the retrieval of the color channels by converting the int to a hex string and then parsing the substrings A) probably isn't working like you think it's working due to those weird substring ranges, and B) is an excruciatingly slow way to do that.
-
Nicolas Lucero over 3 yearsI'm calculating the picture with and height with image_size_getter.
-
Nicolas Lucero over 3 yearsYes, I know this is not the best way, but unfortunately I didn't find anything better :(
-
Abion47 over 3 yearsWhy? You are using the
image
package. Theimage
object already haswidth
andheight
properties. -
Nicolas Lucero over 3 yearsYes, but in my Image object, I get width and height in null.
-
Abion47 over 3 yearsThen something is weird in how you are loading the images.
-
Rohit almost 3 years@NicolasLucero so now do we have the same brightness level for all devices?
-
Nicolas Lucero almost 3 yearsYes, the "brightness" level will be always the same. Just FYI, we replaced this calc with computer vision and some ML models because the original calc was low accurate.
-
-
Nicolas Lucero over 3 yearsFirst of all thanks for answer. Your notes are very helpful, now I'm trying your code and it works without errors, but the brightness values are differents depends on the photo resolution. I mean, from android emulator (1280x720) I see values from 0 to 3, but with galaxy s10 I see values from 4 to 6 and iPhone xr (3840x2160) from 8 to 22. I also deleted the rounds method to see the original value.
-
Abion47 over 3 years@NicolasLucero If the inaccuracies get bigger with resolution, that could indicate a rounding error. I'd say yeah, get rid of all the rounding functions and treat the average as a floating point value. (I also mistakenly left in
colorSum / (width * height)
which should becolorSum / pixels.length
, so that might also have contributed to it.) -
Nicolas Lucero over 3 yearsNow the numbers are pretty similar in all devices. But the numbers are weird, I have a smaller number when the picture is completely white than other totally black. I'l try it to solve it and post the solution. Thank u