【问题标题】:Is it posible to know the brightness of a picture in Flutter?在 Flutter 中可以知道图片的亮度吗?
【发布时间】:2020-10-14 18:50:29
【问题描述】:

我正在构建一个内置摄像头的应用程序。

拍完照片后,我想分析一下这张照片的亮度,如果不好就重新拍照。

这是我现在的代码,它是我在 Dart 中找到并编写的一个 javascript 函数:

感谢@Abion47

编辑 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;

但我的白色亮度比黑色低,数字有点奇怪。

你知道知道亮度的更好方法吗?

解决方案:

经过进一步调查,我们找到了解决方案,我们在进行图像解码时出错,但我们使用了 Image 函数。

这是我们的最终代码:

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;

希望对你有帮助。

【问题讨论】:

  • 图像对象的宽度和高度是多少,你是如何得到它们的?
  • 此外,通过将 int 转换为十六进制字符串然后解析子字符串来检索颜色通道 A) 可能不像您认为的那样工作,因为这些奇怪的子字符串范围和 B)这是一种极其缓慢的方法。
  • 我用image_size_getter计算图片和高度。
  • 是的,我知道这不是最好的方法,但不幸的是我没有找到更好的方法:(
  • 为什么?您正在使用 image 包。 image 对象已经具有 widthheight 属性。

标签: image flutter dart camera brightness


【解决方案1】:

您的代码有几处问题。

首先,您会遇到范围错误,因为您试图访问一个不存在的像素。这可能是由于width 和/或height 大于图像的实际宽度或高度。有很多方法可以尝试获取这些值,但对于此应用程序而言,这实际上并不重要,因为最终结果是获取图像中所有像素的平均值,并且您不需要宽度或高度的图像。

其次,您通过将颜色值序列化为十六进制字符串然后解析各个通道子字符串来获取颜色值。您的 substring 将导致错误的值,因为:

  • foo.substring(a, b)foo 的子字符串从a 带到b,独占。这意味着ab 是索引,而不是长度,并且生成的字符串将不包括b 处的字符。所以假设hex是“01234567”,当你做hex.substring(0, 2),你得到“01”,然后你做hex.substring(3, 5)你得到“34”,而hex.substring(6, 8)得到“67”。您需要先执行hex.substring(0, 2),然后执行hex.substring(2, 4)hex.substring(4, 6) 才能获得前三个频道。
  • 话虽如此,您正在获取错误的频道。 image 包以 ABGR 格式存储其像素值,这意味着十六进制字符串中的前两个字符将是 alpha 通道,这在计算图像亮度时并不重要。相反,您需要第二、第三和第四通道分别用于蓝色、绿色和红色值。
  • 话虽如此,当从整数颜色值中检索通道数据的首选方法是对整数本身进行按位运算时,无论如何这是一种极其低效的方法。 (除非绝对必要,否则切勿将数字转换为字符串,反之亦然。)

总而言之,您想要的可能类似于以下内容;

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;

【讨论】:

  • 首先感谢您的回答。你的笔记很有帮助,现在我正在尝试你的代码,它可以正常工作,但亮度值不同取决于照片分辨率。我的意思是,从 android 模拟器 (1280x720) 我看到从 0 到 3 的值,但使用 Galaxy s10 我看到从 4 到 6 的值和从 8 到 22 的 iPhone xr (3840x2160)。我还删除了 rounds 方法以查看原始值.
  • @NicolasLucero 如果不准确性随着分辨率的增加而变大,则可能表示舍入错误。我会说是的,摆脱所有舍入函数并将平均值视为浮点值。 (我也错误地留在了colorSum / (width * height),应该是colorSum / pixels.length,所以这也可能促成了它。)
  • 现在所有设备中的数字都非常相似。但是数字很奇怪,当图片全白时,我的数字比其他全黑的数字要小。我会尝试解决它并发布解决方案。谢谢你
猜你喜欢
  • 1970-01-01
  • 2011-10-10
  • 2019-08-10
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 1970-01-01
  • 2011-05-19
相关资源
最近更新 更多