Flutter插件zinnia_flutter的介绍与使用
Flutter插件zinnia_flutter的介绍与使用
zinnia_flutter
是一个围绕 zinnia
库的 Dart 封装。
Zinnia
(日本语)是一个基于支持向量机的手写识别系统。它简单、可定制且便携,可用于识别手写的日文字符(漢字)。模型文件可以在 这里 找到。
示例
以下是一个简单的示例代码:
var modelByteData = await rootBundle.load('assets/joyo-kanji.model');
var recognizer = ZinniaRecognizer()
..loadFromByteData(modelByteData);
var character = ZinniaCharacter(100, 100);
character.add([const Point(10, 50), const Point(90, 50)]);
character.add([const Point(50, 10), const Point(50, 90)]);
var list = recognizer.classifyToList(character, resultsLimit: 3);
/*
list == [
ZinniaResultEntry('十', 0.5172672867774963),
ZinniaResultEntry('七', -0.3905687928199768),
ZinniaResultEntry('斗', -0.5770313143730164)
]
*/
character.dispose();
recognizer.dispose();
完整的 Flutter 应用示例可以在这个链接找到:这里
许可证
有关此封装器、zinnia 和模型文件的许可证信息,可以在 LICENSE 文件中找到。
完整示例代码
以下是一个完整的 Flutter 示例代码,展示了如何使用 zinnia_flutter
插件进行手写汉字识别:
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:zinnia_flutter/zinnia_character.dart';
import 'package:zinnia_flutter/zinnia_recognizer.dart';
import 'package:zinnia_flutter/zinnia_result_entry.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _Painter _painter = _Painter();
final ZinniaRecognizer _recognizer = ZinniaRecognizer();
final ZinniaCharacter _character = ZinniaCharacter(300, 300);
late final Future<bool> _initialized;
List<ZinniaResultEntry> _results = [];
[@override](/user/override)
void initState() {
super.initState();
_initialized = _initZinnia();
}
Future<bool> _initZinnia() async {
return _recognizer
.loadFromByteData(await rootBundle.load('assets/joyo-kanji.model'));
}
void _addPointToCurrentStroke(Offset point) {
if (point.dx < 0 || point.dx > 1 || point.dy < 0 || point.dy > 1) {
return _endStroke();
}
setState(() {
_painter.currentStroke.add(point);
});
}
void _endStroke() {
if (_painter.currentStroke.isEmpty) {
return;
}
var characterStroke = _painter.currentStroke
.map((e) =>
e.scale(_character.width.toDouble(), _character.height.toDouble()))
.map((e) => Point<int>(e.dx.round(), e.dy.round()));
_character.add(characterStroke);
_results = _recognizer.classifyToList(_character, resultsLimit: 50);
setState(() {
_painter.strokes.add(_painter.currentStroke);
_painter.currentStroke = [];
});
}
void _clear() {
setState(() {
_painter.strokes.clear();
_painter.currentStroke.clear();
_results = [];
_character.clear();
});
}
[@override](/user/override)
void dispose() {
_character.dispose();
_recognizer.dispose();
super.dispose();
}
Widget get _mainWidget {
return LayoutBuilder(builder: (context, constraints) {
var side = constraints.maxWidth;
var direction = Axis.vertical;
if (constraints.maxHeight < constraints.maxWidth) {
side = constraints.maxHeight;
direction = Axis.horizontal;
}
var size = Size(side, side);
return Flex(
direction: direction,
children: [
GestureDetector(
onPanStart: (details) {
_addPointToCurrentStroke(details.localPosition
.scale(1.0 / size.width, 1.0 / size.height));
},
onPanUpdate: (details) {
_addPointToCurrentStroke(details.localPosition
.scale(1.0 / size.width, 1.0 / size.height));
},
onPanEnd: (details) {
_endStroke();
},
child: CustomPaint(
painter: _painter,
size: size,
),
),
Expanded(
child: ListView.builder(
itemCount: _results.length,
itemBuilder: (context, index) {
var entry = _results[index];
return ListTile(
title: Text(entry.value),
subtitle: Text("Score: ${entry.score}"),
);
}),
),
],
);
});
}
Widget get _initializationWidget {
return const Text('Initialization...');
}
Widget _errorWidget(Object? error) {
return Text("Error: $error");
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: FutureBuilder(
future: _initialized,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data == true) {
return _mainWidget;
} else {
return _errorWidget("initialization failed");
}
} else if (snapshot.hasError) {
return _errorWidget(snapshot.error);
} else {
return _initializationWidget;
}
}
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.clear),
onPressed: _clear,
)
),
);
}
}
class _Painter extends CustomPainter {
List<List<Offset>> strokes = [];
List<Offset> currentStroke = [];
[@override](/user/override)
void paint(Canvas canvas, Size size) {
var borderPaint = Paint()
..style = PaintingStyle.stroke;
canvas.drawRect(Offset.zero & size, borderPaint);
var linePaint = Paint()
..strokeWidth = 5.0;
for (var stroke in strokes) {
canvas.drawPoints(PointMode.polygon,
stroke.map((e) => e.scale(size.width, size.height)).toList(), linePaint);
}
linePaint.color = Colors.red;
canvas.drawPoints(PointMode.polygon,
currentStroke.map((e) => e.scale(size.width, size.height)).toList(), linePaint);
}
[@override](/user/override)
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
更多关于Flutter插件zinnia_flutter的介绍与使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter插件zinnia_flutter的介绍与使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
zinnia_flutter
是一个用于手写文字识别的 Flutter 插件,它基于 Zinnia
手写识别引擎。Zinnia
是一个开源的在线手写识别系统,支持多种语言的手写文字识别。通过 zinnia_flutter
,你可以在 Flutter 应用中集成手写文字识别的功能。
1. 安装 zinnia_flutter
插件
首先,你需要在 pubspec.yaml
文件中添加 zinnia_flutter
插件的依赖:
dependencies:
flutter:
sdk: flutter
zinnia_flutter: ^0.0.1
然后运行 flutter pub get
来安装依赖。
2. 初始化 zinnia_flutter
在 main.dart
文件中导入 zinnia_flutter
并进行初始化:
import 'package:flutter/material.dart';
import 'package:zinnia_flutter/zinnia_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await ZinniaFlutter.init();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Zinnia Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HandwritingRecognitionScreen(),
);
}
}
3. 创建手写识别界面
接下来,创建一个手写识别界面,用户可以在屏幕上绘制文字,然后通过 zinnia_flutter
进行识别。
class HandwritingRecognitionScreen extends StatefulWidget {
[@override](/user/override)
_HandwritingRecognitionScreenState createState() => _HandwritingRecognitionScreenState();
}
class _HandwritingRecognitionScreenState extends State<HandwritingRecognitionScreen> {
List<Offset> points = [];
String recognizedText = '';
void _clearCanvas() {
setState(() {
points.clear();
recognizedText = '';
});
}
void _recognizeHandwriting() async {
if (points.isEmpty) return;
List<int> x = points.map((point) => point.dx.toInt()).toList();
List<int> y = points.map((point) => point.dy.toInt()).toList();
String result = await ZinniaFlutter.recognize(x, y);
setState(() {
recognizedText = result;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Handwriting Recognition'),
),
body: Column(
children: [
Expanded(
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
RenderBox renderBox = context.findRenderObject() as RenderBox;
points.add(renderBox.globalToLocal(details.globalPosition));
});
},
onPanEnd: (details) {
points.add(Offset(-1, -1)); // Add a separator between strokes
},
child: CustomPaint(
painter: HandwritingPainter(points),
size: Size.infinite,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Recognized Text: $recognizedText'),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _clearCanvas,
child: Text('Clear'),
),
ElevatedButton(
onPressed: _recognizeHandwriting,
child: Text('Recognize'),
),
],
),
],
),
);
}
}
class HandwritingPainter extends CustomPainter {
final List<Offset> points;
HandwritingPainter(this.points);
[@override](/user/override)
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.black
..strokeWidth = 4.0
..strokeCap = StrokeCap.round;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != Offset(-1, -1) && points[i + 1] != Offset(-1, -1)) {
canvas.drawLine(points[i], points[i + 1], paint);
}
}
}
[@override](/user/override)
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}