如何将图像实例转换为具有Flutter路径的文件?



我需要拍摄一张照片,将文件转换为图像以进行裁剪,然后将图像转换回文件,然后运行到tflite模型(目前只是在另一个屏幕上显示图像)。

因为它的情况下,我使用一个简单的相机应用程序(https://flutter.dev/docs/cookbook/plugins/picture-using-camera?source=post_page---------------------------)并在预览屏幕上堆叠一个容器用作取景器。我使用rect_getter包从图像包中获取copyCrop()函数的容器坐标。

尝试将我的文件转换为图像(因此copyCrop()函数可以运行),然后返回到文件(cropSaveFile.path)稍后在tflite模型中使用会导致错误:下面的FileSystemException被抛出,解析图像编解码器:��GFD�伯父�����������������等。

final image = await _controller.takePicture();
////////////////////////////////////////////
final xpath = image.path;
final bytes = await File(xpath).readAsBytes();
final img.Image? newImage = img.decodeImage(bytes);
////////////////////////////////////////////
img.Image crop =
img.copyCrop(newImage!, _proX, _proY, _proW, _proH);
print('Crop: $crop');
final newBytes = crop.getBytes();
final File cropSaveFile = File.fromRawPath(newBytes);

我不确定我真正得到的是什么样的文件。这是不可读的。什么好主意吗?要运行的完整代码如下:

import 'dart:async';
import 'dart:io';
import 'package:universal_io/io.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rect_getter/rect_getter.dart';
import 'package:image/image.dart' as img;
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
// Ensure that plugin services are initialized so that `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();
// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();
// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;
runApp(
MaterialApp(
theme: ThemeData.dark(),
home: TakePictureScreen(
// Pass the appropriate camera to the TakePictureScreen widget.
camera: firstCamera,
),
),
);
}
// A screen that allows users to take a picture using a given camera.
class TakePictureScreen extends StatefulWidget {
const TakePictureScreen({
Key? key,
required this.camera,
}) : super(key: key);
final CameraDescription camera;
@override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
var ContainerKey = RectGetter.createGlobalKey();
// Coordinates for rectangle
late int _proX;
late int _proY;
late int _proW;
late int _proH;
@override
void initState() {
super.initState();
// To display the current output from the Camera,
// create a CameraController.
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
// Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Take a picture')),
// You must wait until the controller is initialized before displaying the
// camera preview. Use a FutureBuilder to display a loading spinner until the
// controller has finished initializing.
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
return Column(
children: [
AspectRatio(
aspectRatio: 1 / _controller.value.aspectRatio,
child: Stack(
children: [
CameraPreview(_controller),
Padding(
padding: const EdgeInsets.fromLTRB(
50.0,
8.0,
16.0,
8.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
key: ContainerKey,
height: 175,
width: 175,
decoration: BoxDecoration(
border: Border.all(
width: 10,
color: Colors.yellow,
),
borderRadius: BorderRadius.circular(10.0),
),
),
Text(
'Place Image in Box Above',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
],
);
} else {
// Otherwise, display a loading indicator.
return const Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
// Provide an onPressed callback.
onPressed: () async {
// Take the Picture in a try / catch block. If anything goes wrong,
// catch the error.
try {
// Ensure that the camera is initialized.
await _initializeControllerFuture;
_controller.setFlashMode(FlashMode.off);
///////////////////////////////////////////
Rect? imageRect = RectGetter.getRectFromKey(ContainerKey);
setState(() {
_proX = imageRect!.left.toInt();
_proY = imageRect.top.toInt();
_proW = imageRect.right.toInt();
_proH = imageRect.bottom.toInt();
});
print(_proX);
print(_proY);
print(_proW);
print(_proH);
///////////////////////////////////////////
// Attempt to take a picture and get the file `image`
// where it was saved.
final image = await _controller.takePicture();
////////////////////////////////////////////
final xpath = image.path;
final bytes = await File(xpath).readAsBytes();
final img.Image? newImage = img.decodeImage(bytes);
////////////////////////////////////////////
img.Image crop =
img.copyCrop(newImage!, _proX, _proY, _proW, _proH);
print('Crop: $crop');
final newBytes = crop.getBytes();
final File cropSaveFile = File.fromRawPath(newBytes);
// If the picture was taken, display it on a new screen.
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(
// Pass the automatically generated path to
// the DisplayPictureScreen widget.
imagePath: cropSaveFile.path,
),
),
);
} catch (e) {
// If an error occurs, log the error to the console.
print(e);
}
},
child: const Icon(Icons.camera_alt),
),
);
}
}
// A widget that displays the picture taken by the user.
class DisplayPictureScreen extends StatelessWidget {
final String imagePath;
const DisplayPictureScreen({Key? key, required this.imagePath})
: super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Display the Picture')),
// The image is stored as a file on the device. Use the `Image.file`
// constructor with the given path to display the image.
body: Image.file(File(imagePath)),
);
}
}

以下代码

final image = await _controller.takePicture();
final xpath = image.path;
//xpath store the path of the file captured by the app

只使用

final File file = File(image.path);
//which is a jpg file for verification just console print the image.path and check for the extension.

顺便说一句,我不明白为什么你需要一个jpeg文件,因为在你共享的代码片段下,你已经在一个jpeg文件上工作了,唯一的区别是你正在从设备内存中读取它作为ByteString来处理它来裁剪,然后再为ByteString生成一个文件。

编辑:未来的我发现下面的包比下面的代码好得多…https://pub.dev/packages/mask_for_camera_view

这个适合我。

////////////////////////////////////////////
final xpath = image.path;
final bytes = await File(xpath).readAsBytes();
final img.Image? newImage = img.decodeImage(bytes);
////////////////////////////////////////////
img.Image crop = img.copyCrop(newImage!, _proY, _proY, 175, 175);
final jpg = img.encodeJpg(crop);
File cropSaveFile = File(xpath);
cropSaveFile.writeAsBytes(jpg);

如果有人对基于取景器容器从相机中裁剪图像的完整代码感兴趣,它在下面。

import 'dart:io';
import 'package:universal_io/io.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:rect_getter/rect_getter.dart';
import 'package:image/image.dart' as img;
Future<void> main() async {
// Ensure that plugin services are initialized so that `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();
// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();
// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;
runApp(
MaterialApp(
theme: ThemeData.dark(),
home: TakePictureScreen(
// Pass the appropriate camera to the TakePictureScreen widget.
camera: firstCamera,
),
),
);
}
// A screen that allows users to take a picture using a given camera.
class TakePictureScreen extends StatefulWidget {
const TakePictureScreen({
Key? key,
required this.camera,
}) : super(key: key);
final CameraDescription camera;
@override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> {
late CameraController _controller;
late Future<void> _initializeControllerFuture;
var ContainerKey = RectGetter.createGlobalKey();
// Coordinates for rectangle
late int _proY;
@override
void initState() {
super.initState();
// To display the current output from the Camera,
// create a CameraController.
_controller = CameraController(
// Get a specific camera from the list of available cameras.
widget.camera,
// Define the resolution to use.
ResolutionPreset.medium,
);
// Next, initialize the controller. This returns a Future.
_initializeControllerFuture = _controller.initialize();
}
@override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
Future<File> writeImageWidgetToFile(
img.Image crop, String croppedImagePath) async {
final imgByteData = await crop.getBytes();
final buffer = imgByteData.buffer;
return File(croppedImagePath).writeAsBytes(buffer.asUint8List(
imgByteData.offsetInBytes, imgByteData.lengthInBytes));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Take a picture')),
// You must wait until the controller is initialized before displaying the
// camera preview. Use a FutureBuilder to display a loading spinner until the
// controller has finished initializing.
body: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
return Column(
children: [
AspectRatio(
aspectRatio: 1 / _controller.value.aspectRatio,
child: Stack(
children: [
CameraPreview(_controller),
Padding(
padding: const EdgeInsets.fromLTRB(
16.0,
8.0,
16.0,
8.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
key: ContainerKey,
height: 175,
width: 175,
decoration: BoxDecoration(
border: Border.all(
width: 10,
color: Colors.yellow,
),
borderRadius: BorderRadius.circular(10.0),
),
),
Text(
'Place Image in Box Above',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
],
);
} else {
// Otherwise, display a loading indicator.
return const Center(child: CircularProgressIndicator());
}
},
),
floatingActionButton: FloatingActionButton(
// Provide an onPressed callback.
onPressed: () async {
// Take the Picture in a try / catch block. If anything goes wrong,
// catch the error.
try {
// Ensure that the camera is initialized.
await _initializeControllerFuture;
_controller.setFlashMode(FlashMode.off);
///////////////////////////////////////////
Rect? imageRect = RectGetter.getRectFromKey(ContainerKey);
setState(() {
_proY = imageRect!.top.toInt();
});
print('Top Left Corner of Rect: $_proY');
///////////////////////////////////////////
// Attempt to take a picture and get the file `image`
// where it was saved.
final image = await _controller.takePicture();
////////////////////////////////////////////
final xpath = image.path;
final bytes = await File(xpath).readAsBytes();
final img.Image? newImage = img.decodeImage(bytes);
////////////////////////////////////////////
img.Image crop = img.copyCrop(newImage!, _proY, _proY, 175, 175);
final jpg = img.encodeJpg(crop);
File cropSaveFile = File(xpath);
cropSaveFile.writeAsBytes(jpg);
// If the picture was taken, display it on a new screen.
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(
// Pass the automatically generated path to
// the DisplayPictureScreen widget.
imagePath: cropSaveFile.path,
),
),
);
} catch (e) {
// If an error occurs, log the error to the console.
print(e);
}
},
child: const Icon(Icons.camera_alt),
),
);
}
}
// A widget that displays the picture taken by the user.
class DisplayPictureScreen extends StatelessWidget {
final String imagePath;
const DisplayPictureScreen({Key? key, required this.imagePath})
: super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Display the Picture')),
// The image is stored as a file on the device. Use the `Image.file`
// constructor with the given path to display the image.
body: Image.file(File(imagePath)),
);
}
}

相关内容

  • 没有找到相关文章

最新更新