Flutter Camera startImageStream возвращает изображения с нулем - PullRequest
0 голосов
/ 10 ноября 2019

Я пытаюсь создать демонстрационное приложение poseNet в реальном времени с помощью Flutter и его пакета Camera. Отображение предварительного просмотра камеры работает очень хорошо, но когда я пытаюсь получить доступ к потоку изображений через controller.startImageStream, программа вылетает. Мне удалось отследить источник этой ошибки, и мне кажется, что входящие кадры в 'controller.startImageStream' возвращают значения null. Почему это так и как я могу это исправить?

Фрагмент выглядит следующим образом:

controller.startImageStream((CameraImage img) {
          controller.stopImageStream();
          if (!isPaused) {
            runPoseNetOnFrame(bytesList: img.planes.map((plane) {
              return plane.bytes;
            }).toList(),
                imageHeight: img.height,
                imageWidth: img.width,
                numResults: 1).then((recognitions) {
              setState(() {
                photo = img;
                _recognitions = recognitions;
                imageHeight = img.height;
                imageWidth = img.width;
              });
            });
          }
        });

И это переменная img для каждой итерации, состоящей только из типаnull когда он действительно должен содержать фрейм типа CameraImage

Когда приложение аварийно завершает работу, я получаю эту ошибку в консоли:

E/flutter (26077): [ERROR:flutter/shell/common/shell.cc(178)] Dart Error: Unhandled exception:
E/flutter (26077): NoSuchMethodError: The getter 'isActive' was called on null.
E/flutter (26077): Receiver: null
E/flutter (26077): Tried calling: isActive

Вот мой код для всей страницы:

import 'package:flutter/material.dart';
import 'package:tflite/tflite.dart';
import 'package:flutter/services.dart';
import 'dart:typed_data';
import 'package:camera/camera.dart';


class CoachPage extends StatefulWidget {
  @override
  _CoachPageState createState() {
    return _CoachPageState();
  }
}

class _CoachPageState extends State<CoachPage> {
  bool isPaused = true;
  CameraController controller;
  List cameras;
  int selectedCameraIdx;
  String imagePath;
  static const MethodChannel _channel = const MethodChannel('tflite');
  String model;
  List<dynamic> _recognitions;
  int imageHeight;
  int imageWidth;
  CameraImage photo;

  @override
  void initState() {
    super.initState();
    availableCameras().then((availableCameras) {

      cameras = availableCameras;

      if (cameras.length > 0) {
        setState(() {
          selectedCameraIdx = 0;
        });
        _initCameraController(cameras[selectedCameraIdx]);
        }
      else{
        print("No camera available");
      }
    }).catchError((err) {
      print('Error: $err.code\nError Message: $err.message');
    });
  }

  void _initCameraController(CameraDescription cameraDescription) {
    controller = CameraController(cameraDescription, ResolutionPreset.medium);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      controller.addListener(() {});
      controller.startImageStream((CameraImage img) {
        controller.stopImageStream();
        if (!isPaused) {
          runPoseNetOnFrame(bytesList: img.planes.map((plane) {
            return plane.bytes;
          }).toList(),
              imageHeight: img.height,
              imageWidth: img.width,
              numResults: 1).then((recognitions) {
            setState(() {
              photo = img;
              _recognitions = recognitions;
              imageHeight = img.height;
              imageWidth = img.width;
            });
          });
        }

    });

      setState(() {});
  });}

  @override
  void dispose() {
  controller?.dispose();
  super.dispose();
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: SafeArea(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Expanded(
                flex: 1,
                child: isPaused ? _cameraPreviewWidget()
                    : _renderKeypoints(),
              ),
              SizedBox(height: 10.0),
              Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  _cameraTogglesRowWidget(),
                  _captureControlRowWidget(context),
                  Spacer(),
                  Text(photo.toString())
                ],
              ),
              SizedBox(height: 20.0)
            ],
          ),
        ),
      ),
    );
  }

  /// Display Camera preview.
  Widget _cameraPreviewWidget() {
    if (controller == null || !controller.value.isInitialized) {
      return const Text(
        'Loading',
        style: TextStyle(
          color: Colors.white,
          fontSize: 20.0,
          fontWeight: FontWeight.w900,
        ),
      );
    }

    return AspectRatio(
      aspectRatio: controller.value.aspectRatio,
      child: CameraPreview(controller),
    );
  }

  /// Display the control bar with buttons to take pictures
  Widget _captureControlRowWidget(context) {
    return Expanded(
      child: Align(
        alignment: Alignment.center,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          mainAxisSize: MainAxisSize.max,
          children: [
            FloatingActionButton(
                child:(isPaused) ? Icon(Icons.play_arrow)
                    : Icon(Icons.pause),
                backgroundColor: Colors.blueGrey,
                onPressed: () {
                  setState(() {
                    isPaused = !isPaused;
                  });
                })
          ],
        ),
      ),
    );
  }

  /// Display a row of toggle to select the camera (or a message if no camera is available).
  Widget _cameraTogglesRowWidget() {
    if (cameras == null || cameras.isEmpty) {
      return Spacer();
    }

    CameraDescription selectedCamera = cameras[selectedCameraIdx];
    CameraLensDirection lensDirection = selectedCamera.lensDirection;

    return Expanded(
      child: Align(
        alignment: Alignment.centerLeft,
        child: FlatButton.icon(
            onPressed: _onSwitchCamera,
            icon: Icon(_getCameraLensIcon(lensDirection)),
            label: Text(
                "${lensDirection.toString().substring(lensDirection.toString().indexOf('.') + 1)}")),
      ),
    );
  }

  IconData _getCameraLensIcon(CameraLensDirection direction) {
    switch (direction) {
      case CameraLensDirection.back:
        return Icons.camera_rear;
      case CameraLensDirection.front:
        return Icons.camera_front;
      case CameraLensDirection.external:
        return Icons.camera;
      default:
        return Icons.device_unknown;
    }
  }

  void _onSwitchCamera() {
    selectedCameraIdx =
    selectedCameraIdx < cameras.length - 1 ? selectedCameraIdx + 1 : 0;
    CameraDescription selectedCamera = cameras[selectedCameraIdx];
    _initCameraController(selectedCamera);
  }

  void _showCameraException(CameraException e) {
    String errorText = 'Error: ${e.code}\nError Message: ${e.description}';
    print(errorText);

    print('Error: ${e.code}\n${e.description}');
  }

  Future loadModel() async {
    Tflite.close();

      String res = await Tflite.loadModel(
          model: "assets/posenet_mv1_075_float_from_checkpoints.tflite");
      model = res;
  }
  Future<List> runPoseNetOnFrame(
      {@required List<Uint8List> bytesList,
        int imageHeight = 1280,
        int imageWidth = 720,
        double imageMean = 127.5,
        double imageStd = 127.5,
        int rotation: 90, // Android only
        int numResults = 1,
        double threshold = 0.5,
        int nmsRadius = 20,
        bool asynch = true}) async {
    return await _channel.invokeMethod(
      'runPoseNetOnFrame',
      {
        "bytesList": bytesList,
        "imageHeight": imageHeight,
        "imageWidth": imageWidth,
        "imageMean": imageMean,
        "imageStd": imageStd,
        "rotation": rotation,
        "numResults": numResults,
        "threshold": threshold,
        "nmsRadius": nmsRadius,
        "asynch": asynch,
      },
    );
  }

  List<Widget> _renderKeypoints() {
    var lists = <Widget>[];
    _recognitions.forEach((re) {
      var list = re["keypoints"].values.map<Widget>((k) {
        var x = k["x"];
        var y = k["y"];

        return Positioned(
          left: x - 6,
          top: y - 6,
          width: 100,
          height: 12,
          child: Container(
            child: Text(
              "● ${k["part"]}",
              style: TextStyle(
                color: Color.fromRGBO(37, 213, 253, 1.0),
                fontSize: 12.0,
              ),
            ),
          ),
        );
      }).toList();

      lists.addAll(list);
    });

    return lists;
  }
}

Заранее спасибо! ;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...