Flutter相机校准插件flutter_camera_calibration的使用

Flutter相机校准插件flutter_camera_calibration的使用

1. 简介

flutter_camera_calibration 插件项目提供了iOS和Android平台上的相机校准功能,使用了OpenCV 4.3.0库。该插件允许你获取相机的内部参数。

  • 这个功能通过将OpenCV教程中提供的C++相机校准代码适配到Flutter中实现。
  • 该项目使用FFI(外部函数接口)库来绑定这些C++函数以在Flutter中使用。
  • 在示例代码中,你可以看到file_pickerimage_picker的使用。
  • 你可以从以下链接下载配置文件和测试图像:
  • 请注意,在模拟器上不支持运行示例进行测试,你应该在实际设备上进行测试。

2. 截图

Home Config File Select Captured Images Select Camera Intrinsic Parameter Matrix
Home Config File Select Captured Images Select Camera Intrinsic Parameter Matrix

3. 设置

  • file_pickerimage_picker所需的权限设置可以在各自的插件安装文档中找到。

4. 使用

import 'package:flutter_camera_calibration/flutter_camera_calibration.dart' as flutter_camera_calibration;

// 获取OpenCV版本
var version = flutter_camera_calibration.opencvVersion();

// 获取相机内部参数开始
String? filePath = ""; 
String full_path = "";   // 配置文件路径

// 选择配置文件 'in_VID5.xml'
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
  filePath = result.files.single.path;
  full_path = filePath.toString();
  if (filePath != null) {
    // print("------------->" + filePath);
  }
} else {
  // 用户取消了选择
}

// 选择捕获的图像
final List<XFile>? images = await _picker.pickMultiImage();
final List<String> imagePaths = [];

if (images != null) {
  for (final image in images) {
    final imagePath = image?.path ?? "none";
    // print("-----------" + imagePath.toString());
    imagePaths.add(imagePath);
  }
}

// 获取相机内部参数开始
final calibration_result = await flutter_camera_calibration.cameraCalibrate(full_path, imagePaths);

var matrix = flutter_camera_calibration.CameraIntrincMatrix(
  calibration_result.rows,
  calibration_result.cols,
  calibration_result.array,
);

print(matrix);
// 获取相机内部参数结束

示例代码

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_camera_calibration/flutter_camera_calibration.dart' as flutter_camera_calibration;
import 'package:image_picker/image_picker.dart';

void main() {
  runApp(MaterialApp(
    home: const MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late String version;
  final ImagePicker _picker = ImagePicker();

  [@override](/user/override)
  void initState() {
    super.initState();
    version = flutter_camera_calibration.opencvVersion();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    const textStyle = TextStyle(fontSize: 25);
    const spacerSmall = SizedBox(height: 10);
    return Scaffold(
        appBar: AppBar(
          title: const Text('flutter_camera_calibration 示例'),
        ),
        body: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(10),
            child: Column(
              children: [
                spacerSmall,
                Text(
                  'OpenCV 版本: $version',
                  style: textStyle,
                  textAlign: TextAlign.center,
                ),
                SizedBox(height: 300,),

                Center(
                    child: ElevatedButton(
                  onPressed: () async {
                    String? filePath = "";
                    String full_path = "";

                    FilePickerResult? result = await FilePicker.platform.pickFiles();
                    if (result != null) {
                      filePath = result.files.single.path;
                      full_path = filePath.toString();
                      if (filePath != null) {
                        print("-----------------&gt;filePath: " + filePath);
                        print("-----------------&gt;full path: " + full_path);
                      }
                    } else {
                      // 用户取消了选择
                    }

                    final List<XFile>? images = await _picker.pickMultiImage();
                    final List<String> imagePaths = [];

                    if (images != null) {
                      for (final image in images) {
                        final imagePath = image?.path ?? "none";
                        print("-----------" + imagePath.toString());
                        imagePaths.add(imagePath);
                      }
                    }

                    final calibration_result = await flutter_camera_calibration.cameraCalibrate(full_path, imagePaths);

                    // 使用结果
                    print('-------------------------------------------------------------------------&gt;');
                    print('----------------------------------------&gt;rows: ' + calibration_result.rows.toString());
                    print('----------------------------------------&gt;cols: ' + calibration_result.cols.toString());
                    print('----------------------------------------&gt;length: ' + calibration_result.length.toString());

                    var matrix = flutter_camera_calibration.CameraIntrincMatrix(
                        calibration_result.rows,
                        calibration_result.cols,
                        calibration_result.array,
                      );

                    print(matrix);

                    showDialog(
                      context: context,
                      builder: (BuildContext context) {
                        return AlertDialog(
                          title: Text("相机校准结果 \n\n相机内部参数矩阵",
                            style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
                          ),
                          content: Container(
                            width: 400,
                            height: 300,
                            child: MatrixWidget(matrix),
                          ),
                          actions: <Widget>[
                            TextButton(
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                              child: Text("关闭"),
                            ),
                          ],
                        );
                      },
                    );

                  },
                  child: Text("运行相机校准"),
                )
                ),
              ],
            ),
          ),
        ),
    );
  }
}

class MatrixWidget extends StatelessWidget {
  final flutter_camera_calibration.CameraIntrincMatrix matrix;

  MatrixWidget(this.matrix);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: matrix.cols,
      ),
      itemBuilder: (context, index) {
        final row = index ~/ matrix.cols;
        final col = index % matrix.cols;
        final value = matrix.get(row, col);

        return Center(
          child: Text(
            value.toStringAsFixed(2),
            style: TextStyle(fontSize: 18.0),
          ),
        );
      },
      itemCount: matrix.rows * matrix.cols,
    );
  }
}

更多关于Flutter相机校准插件flutter_camera_calibration的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter相机校准插件flutter_camera_calibration的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_camera_calibration 是一个用于相机校准的 Flutter 插件。相机校准是计算机视觉中的一个重要步骤,用于估计相机的内在参数(如焦距、主点、畸变系数等),以便进行更精确的图像处理或三维重建。

以下是如何使用 flutter_camera_calibration 插件的基本步骤:

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 flutter_camera_calibration 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_camera_calibration: ^latest_version

然后运行 flutter pub get 来获取依赖。

2. 导入插件

在你的 Dart 文件中导入插件:

import 'package:flutter_camera_calibration/flutter_camera_calibration.dart';

3. 初始化相机校准

接下来,你需要初始化相机校准。通常,你会使用一个棋盘格图像来进行校准。你可以使用 CameraCalibration 类来执行校准。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化相机校准
  final cameraCalibration = CameraCalibration();

  // 设置棋盘格的尺寸(例如:9x6)
  final patternSize = Size(9, 6);

  // 加载棋盘格图像
  final imageFile = File('path_to_your_checkerboard_image.jpg');
  final imageBytes = await imageFile.readAsBytes();

  // 进行相机校准
  final calibrationResult = await cameraCalibration.calibrate(
    imageBytes,
    patternSize,
  );

  // 打印校准结果
  print('Camera Matrix: ${calibrationResult.cameraMatrix}');
  print('Distortion Coefficients: ${calibrationResult.distortionCoefficients}');
}

4. 使用校准结果

校准完成后,你将获得相机的内参矩阵和畸变系数。这些参数可以用于后续的图像处理任务,例如去畸变、三维重建等。

// 使用校准结果进行图像去畸变
final undistortedImageBytes = await cameraCalibration.undistort(
  imageBytes,
  calibrationResult.cameraMatrix,
  calibrationResult.distortionCoefficients,
);

// 保存去畸变后的图像
final undistortedImageFile = File('path_to_save_undistorted_image.jpg');
await undistortedImageFile.writeAsBytes(undistortedImageBytes);

5. 处理错误

在实际应用中,你可能会遇到各种错误,例如图像中没有检测到棋盘格。你可以使用 try-catch 块来捕获并处理这些错误。

try {
  final calibrationResult = await cameraCalibration.calibrate(
    imageBytes,
    patternSize,
  );
  print('Camera Matrix: ${calibrationResult.cameraMatrix}');
} catch (e) {
  print('Calibration failed: $e');
}
回到顶部