Flutter自拍人像分割插件learning_selfie_segmentation的使用
Flutter自拍人像分割插件 learning_selfie_segmentation
的使用
ML Selfie Segmentation 插件为开发者提供了一种简单的方式来使用 ML Kit 在 Flutter 中进行自拍照的人像分割。通过该插件,可以轻松地将背景与用户分离,并专注于重要的部分,如添加酷炫的特效或插入有趣的背景环境。
功能简介
- 输入图像:插件接受一个
InputImage
对象作为输入。 - 输出掩码:根据输入图像生成一个掩码,每个像素的值范围在 [0.0, 1.0] 之间,数值越接近 1.0 表示该像素属于前景(即人)的概率越高。
- 实时视频处理:支持静态图片和实时视频流场景,在视频流中会利用前几帧的结果来平滑分割效果。
开始使用
添加依赖
首先,在你的 pubspec.yaml
文件中添加对 learning_selfie_segmentation
的依赖:
dependencies:
learning_selfie_segmentation: ^0.0.2
然后运行以下命令获取包:
flutter pub get
导入包
在 Dart 文件中导入所需的包:
import 'package:learning_selfie_segmentation/learning_selfie_segmentation.dart';
import 'package:learning_input_image/learning_input_image.dart';
示例 Demo
下面是一个完整的示例代码,展示了如何使用 learning_selfie_segmentation
插件进行自拍人像分割。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_native_image/flutter_native_image.dart';
import 'package:learning_input_image/learning_input_image.dart';
import 'package:learning_selfie_segmentation/learning_selfie_segmentation.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.lightBlue,
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryTextTheme: TextTheme(headline6: TextStyle(color: Colors.white)),
),
home: ChangeNotifierProvider(
create: (_) => SelfieSegmentationState(),
child: SelfieSegmentationPage(),
),
);
}
}
class SelfieSegmentationPage extends StatefulWidget {
@override
_SelfieSegmentationPageState createState() => _SelfieSegmentationPageState();
}
class _SelfieSegmentationPageState extends State<SelfieSegmentationPage> {
SelfieSegmentationState get state => Provider.of(context, listen: false);
SelfieSegmenter _segmenter = SelfieSegmenter(
isStream: true,
enableRawSizeMask: false,
);
@override
void dispose() {
_segmenter.dispose();
super.dispose();
}
Future<void> _process(InputImage image) async {
if (state.isNotProcessing) {
state.startProcessing();
state.isFromLive = image.type == 'bytes';
if (!state.isFromLive) {
ImageProperties properties =
await FlutterNativeImage.getImageProperties(image.path!);
double aspectRatio = properties.width! / properties.height!;
int targetWidth = aspectRatio > 1.0 ? 360 : (360 * aspectRatio).round();
int targetHeight =
aspectRatio > 1.0 ? (360 / aspectRatio).round() : 360;
File scaledImage = await FlutterNativeImage.compressImage(
image.path!,
quality: 90,
targetWidth: aspectRatio > 1.0 ? 360 : (360 * aspectRatio).round(),
targetHeight: aspectRatio > 1.0 ? (360 / aspectRatio).round() : 360,
);
image = InputImage.fromFile(
scaledImage,
metadata: InputImageData(
size: Size(targetWidth.toDouble(), targetHeight.toDouble()),
rotation: image.metadata?.rotation ?? InputImageRotation.ROTATION_0,
),
);
}
state.image = image;
SegmentationMask? mask = await _segmenter.process(image);
state.data = mask;
state.stopProcessing();
}
}
@override
Widget build(BuildContext context) {
return InputCameraView(
mode: InputCameraMode.gallery,
cameraDefault: InputCameraType.rear,
title: 'Selfie Segmentation',
onImage: _process,
overlay: Consumer<SelfieSegmentationState>(
builder: (_, state, __) {
if (state.isEmpty) {
return Container();
}
Size originalSize = state.size!;
Size size =
state.isFromLive ? MediaQuery.of(context).size : originalSize;
return SegmentationOverlay(
size: size,
originalSize: originalSize,
rotation: state.rotation,
mask: state.data!,
);
},
),
);
}
}
class SelfieSegmentationState extends ChangeNotifier {
InputImage? _image;
SegmentationMask? _data;
bool _isProcessing = false;
bool _isFromLive = false;
InputImage? get image => _image;
SegmentationMask? get data => _data;
String? get type => _image?.type;
InputImageRotation? get rotation => _image?.metadata?.rotation;
Size? get size => _image?.metadata?.size;
bool get isNotProcessing => !_isProcessing;
bool get isEmpty => _data == null;
bool get isFromLive => _isFromLive;
bool get notFromLive => !isFromLive;
void startProcessing() {
_isProcessing = true;
notifyListeners();
}
void stopProcessing() {
_isProcessing = false;
notifyListeners();
}
set isFromLive(bool isFromLive) {
_isFromLive = isFromLive;
notifyListeners();
}
set image(InputImage? image) {
_image = image;
if (notFromLive) {
_data = null;
}
notifyListeners();
}
set data(SegmentationMask? data) {
_data = data;
notifyListeners();
}
}
关键点说明
输入图像
输入图像需要转换为 InputImage
格式。你可以使用 learning_input_image
包中的 InputCameraView
小部件来从相机或存储中获取图像并将其转换为 InputImage
。
自拍分割
创建 SelfieSegmenter
实例后,可以通过调用 process
方法处理输入图像:
SelfieSegmenter segmenter = SelfieSegmenter(isStream: true, enableRawSizeMask: false);
SegmentationMask? mask = await segmenter.process(image);
输出结果
处理后的输出是一个 SegmentationMask
对象,包含以下数据:
width
: 分割掩码的宽度height
: 分割掩码的高度confidences
: 每个像素属于前景的置信度列表
分割掩码绘制
为了方便绘制分割掩码,提供了 SegmentationOverlay
小部件,可以直接传递给 InputCameraView
的 overlay
参数。
资源清理
记得在不再使用时释放资源:
segmenter.dispose();
更多关于Flutter自拍人像分割插件learning_selfie_segmentation的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自拍人像分割插件learning_selfie_segmentation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用learning_selfie_segmentation
插件来进行自拍人像分割的示例代码。这个插件通常用于实现人像与背景的分离,以便进行背景替换或其他图像处理任务。
首先,你需要在你的pubspec.yaml
文件中添加依赖项:
dependencies:
flutter:
sdk: flutter
learning_selfie_segmentation: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来获取依赖项。
接下来,你可以在你的Flutter项目中编写代码来使用这个插件。以下是一个基本的示例,展示了如何拍摄照片、应用人像分割,并显示分割后的结果。
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:learning_selfie_segmentation/learning_selfie_segmentation.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SelfieSegmentationScreen(),
);
}
}
class SelfieSegmentationScreen extends StatefulWidget {
@override
_SelfieSegmentationScreenState createState() => _SelfieSegmentationScreenState();
}
class _SelfieSegmentationScreenState extends State<SelfieSegmentationScreen> {
final ImagePicker _picker = ImagePicker();
File? _imageFile;
File? _segmentedImageFile;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Selfie Segmentation Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
_imageFile == null
? Text('No image selected.')
: Image.file(_imageFile!),
SizedBox(height: 20),
_segmentedImageFile == null
? Text('Segmentation result will be shown here.')
: Image.file(_segmentedImageFile!),
SizedBox(height: 20),
ElevatedButton(
onPressed: _pickImage,
child: Text('Pick Image'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _segmentImage,
child: Text('Segment Image'),
isEnabled: _imageFile != null,
),
],
),
),
);
}
Future<void> _pickImage() async {
final pickedFile = await _picker.pickImage(source: ImageSource.camera);
if (pickedFile != null) {
setState(() {
_imageFile = File(pickedFile.path);
_segmentedImageFile = null;
});
}
}
Future<void> _segmentImage() async {
if (_imageFile == null) return;
final segmentor = SelfieSegmentation();
final result = await segmentor.segmentImage(_imageFile!.path);
if (result != null) {
setState(() {
_segmentedImageFile = File(result.path);
});
} else {
// Handle error
print('Segmentation failed.');
}
}
}
在这个示例中,我们使用了image_picker
插件来拍摄或选择照片。请注意,learning_selfie_segmentation
插件的API可能会根据版本有所变化,因此请参考其官方文档以获取最新的API信息。
请注意,由于learning_selfie_segmentation
插件可能需要访问设备摄像头和存储,因此你需要在AndroidManifest.xml
和Info.plist
文件中添加相应的权限。
对于Android,你需要在AndroidManifest.xml
中添加:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
对于iOS,你需要在Info.plist
中添加:
<key>NSCameraUsageDescription</key>
<string>App needs access to the camera to take photos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>App needs access to the photo library to save photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>App needs access to the photo library to pick photos.</string>
请确保在实际项目中遵循最新的权限管理和隐私政策要求。