Flutter 中将 Uint8List 转换为 ByteBuffer 进行图像处理时出现 RangeError

问题描述 投票:0回答:1

我正在开发一个用于图像分割的Flutter应用程序,用户可以在其中上传或捕获照片,并且该应用程序使用TensorFlow Lite模型分析这些照片。但是,当我尝试使用图像库将像素数据(模型分析后)转换为图像时遇到了 RangeError。

以下是我的工作流程的简要概述:

    用户上传/拍摄照片。
  1. 照片大小已调整为 512x512 像素。
  2. 调整大小后的照片中的像素数据被输入 TensorFlow Lite 模型,该模型输出一个张量,指示每个像素的类别预测。
  3. 根据模型的输出,我生成一个颜色列表(List PixelData),其中每个像素的颜色为红色或绿色,具体取决于类预测。
  4. 然后,我将 PixelData 转换为 Uint8List,然后转换为 ByteBuffer,旨在创建可视化模型预测的分段图像。

这是代码有问题的部分:

List<int> pixelData = []; // Fill pixelData based on model's output // ... // Convert List<int> to Uint8List Uint8List byteData = Uint8List.fromList(pixelData); // Attempt to create ByteBuffer from byteData ByteBuffer buffer = byteData.buffer; // Try to create an image from the ByteBuffer // Don't be confused about the imgimg -- i imported the library like that // import 'package:image/image.dart' as imgimg; imgimg.Image? segmentedImage = imgimg.Image.fromBytes( width: imgWidth, height: imgHeight, bytes: buffer, );

尝试创建segmentedImage时出现错误:

RangeError (end): Invalid value: Not in inclusive range 261120..262144: 262656
pixelData 的长度正好是 262144,这对于 512x512 图像来说是正确的,其中每个像素都由单个整数颜色值表示。该错误似乎表明转换过程或 ByteBuffer 的处理方式存在问题。

任何人都可以深入了解可能导致此 RangeError 的原因以及如何将我的 PixelData 正确转换为 ByteBuffer 以进行图像创建吗?有没有更好的方法在 Flutter 中将 TensorFlow 模型的输出可视化为图像?

任何帮助或建议将不胜感激!

如果需要,这里是剩余功能的简要概述。

Future<void> _onUseImagePressed() async { if (_image == null) return; // Load and resize the image imgimg.Image? image = imgimg.decodeImage(File(_image!.path).readAsBytesSync()); imgimg.Image resizedImage = imgimg.copyResize(image!, width: 512, height: 512); // Prepare the model input var input = List.generate(1, (_) => List.generate(512, (_) => List.generate(512, (_) => List.generate(3, (_) => 0.0)))); // Populate input with normalized pixel values for (int y = 0; y < 512; y++) { for (int x = 0; x < 512; x++) { var pixel = resizedImage.getPixel(x, y); input[0][y][x][0] = pixel.r / 255.0; input[0][y][x][1] = pixel.g / 255.0; input[0][y][x][2] = pixel.b / 255.0; } } // Run the TensorFlow Lite model final interpreter = await Interpreter.fromAsset('assets/models/production_model_resnet50.tflite'); var output = List.filled(1 * 512 * 512 * 2, 0).reshape([1, 512, 512, 2]); interpreter.run(input, output); // Generate pixel data based on model output List<int> pixelData = []; for (int y = 0; y < 512; y++) { for (int x = 0; x < 512; x++) { int classIndex = output[0][y][x][0] > output[0][y][x][1] ? 0 : 1; int color = classIndex == 0 ? 0xFFFF0000 : 0xFF00FF00; pixelData.add(color); } } // Convert pixelData to Uint8List and ByteBuffer Uint8List byteData = Uint8List.fromList(pixelData); ByteBuffer buffer = byteData.buffer; // Attempt to create an image from bytes try { imgimg.Image? segmentedImage = imgimg.Image.fromBytes(512, 512, buffer); } catch (e) { print("Error processing model output: $e"); } }
    
flutter tensorflow image-processing tensorflow2.0 tensorflow-lite
1个回答
0
投票
感谢@jamesdlin 指出 Image.fromBytes 默认假定 3 个颜色通道。在没有指定图像格式和通道数的情况下,图像期望有不同的结构。

我做了以下调整:

    调整 PixelData 构造以根据模型输出分配 0 或 255
List<int> pixelData = []; for (int y = 0; y < imgHeight; y++) { for (int x = 0; x < imgWidth; x++) { int classIndex = output[0][y][x][0] > output[0][y][x][1] ? 0 : 1; int colorValue = classIndex == 0 ? 0 : 255; pixelData.add(colorValue); } }

    调用 fromBytes 时指定格式 - imgimg.Format.uint8 和 numChannels: 1 以与更新的 PixelData 结构保持一致
segmentedImage = imgimg.Image.fromBytes( width: imgWidth, height: imgHeight, bytes: buffer, format: imgimg.Format.uint8, numChannels: 1 );
    
© www.soinside.com 2019 - 2024. All rights reserved.