Flutter全景相机功能插件camera_360的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter全景相机功能插件camera_360的使用

camera_360 插件允许用户通过手机摄像头拍摄360度全景图像。它利用OpenCV将多个图像拼接在一起,并提供一个简单的UI来指导用户完成整个过程。

Demo

您可以查看 Tridiar - Virtual Tours 应用程序在 iOSAndroid 上的效果。

Demo

安装

iOS

Info.plist 文件中添加以下内容:

<key>NSCameraUsageDescription</key>
<string>This application needs access to your Camera in order to capture 360 Images</string>
<key>NSMicrophoneUsageDescription</key>
<string>This application needs access to your Microphone in order to capture videos</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This application needs access to your Photo Library in order to save the captured images</string>

Android

注意事项

由于OpenCV为不同的CPU架构构建,建议在构建发布版本时运行以下命令以生成多个APK文件:

flutter build apk --split-per-abi --release

android/app/build.gradle 文件中将最低的Android SDK版本设置为21(或更高):

minSdkVersion 21

AndroidManifest.xml 文件中添加以下权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Dart

导入 camera_360 插件并使用如下代码:

import 'package:camera_360/camera_360.dart';
import 'package:image_picker/image_picker.dart';

Camera360(
  // 文本:正在准备全景图
  userLoadingText: "Preparing panorama...",
  // 文本:请将摄像头对准点
  userHelperText: "Point the camera at the dot",
  // 文本:请向左倾斜设备
  userHelperTiltLeftText: "Tilt left",
  // 文本:请向右倾斜设备
  userHelperTiltRightText: "Tilt Right",
  // iPhone >= 11 建议使用键值 2 选择广角摄像头
  // 在安卓设备上目前无法切换摄像头,因此建议使用键值 0
  userSelectedCameraKey: 2,
  // 摄像头选择器可见性
  cameraSelectorShow: true,
  // 摄像头选择器信息可见性
  cameraSelectorInfoPopUpShow: true,
  // 摄像头选择器信息小部件
  cameraSelectorInfoPopUpContent: const Text(
    "Select the camera with the widest viewing angle below.",
    textAlign: TextAlign.center,
    style: TextStyle(
      color: Color(0xffEFEFEF),
    ),
  ),
  // 自定义消息:如果摄像头未找到或未准备好
  cameraNotReadyContent: const Center(
    child: Padding(
      padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20),
      child: Text(
        "Camera not ready",
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
    ),
  ),
  // 回调函数:当360度捕捉结束时调用
  onCaptureEnded: (data) {
    if (data['success'] == true) {
      XFile panorama = data['panorama'];
      print("Final image returned ${panorama.toString()}");
    } else {
      print("Final image failed");
    }
  },
  // 回调函数:当摄像头镜头改变时调用
  onCameraChanged: (cameraKey) {
    print("Camera changed ${cameraKey.toString()}");
  },
  // 回调函数:当捕捉进度改变时调用
  onProgressChanged: (newProgressPercentage) {
    debugPrint("'Panorama360': Progress changed: $newProgressPercentage");
  },
)

示例代码

以下是一个完整的示例应用,展示了如何使用 camera_360 插件:

import 'package:camera_360/camera_360.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:gallery_saver/gallery_saver.dart';

void main() {
  runApp(const MyApp());
}

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

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

class _MyAppState extends State<MyApp> {
  [@override](/user/override)
  void initState() {
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('360 Camera App'),
        ),
        body: const CameraPage(),
      ),
    );
  }
}

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

  [@override](/user/override)
  State<CameraPage> createState() => _CameraPageState();
}

class _CameraPageState extends State<CameraPage> {
  int progressPecentage = 0;

  [@override](/user/override)
  Widget build(BuildContext context) {
    void displayPanoramaMessage(context, String message) {
      final snackBar = SnackBar(
        content: Text(message),
      );
      ScaffoldMessenger.of(context).showSnackBar(snackBar);
    }

    return Stack(
      children: [
        Camera360(
          // 文本:正在准备全景图
          userLoadingText: "Preparing panorama...",
          // 文本:请将摄像头对准点
          userHelperText: "Point the camera at the dot",
          // 文本:请向左倾斜设备
          userHelperTiltLeftText: "Tilt left",
          // 文本:请向右倾斜设备
          userHelperTiltRightText: "Tilt Right",
          // iPhone >= 11 建议使用键值 2 选择广角摄像头
          // 在安卓设备上目前无法切换摄像头,因此建议使用键值 0
          userSelectedCameraKey: 2,
          // 摄像头选择器可见性
          cameraSelectorShow: true,
          // 摄像头选择器信息可见性
          cameraSelectorInfoPopUpShow: true,
          // 摄像头选择器信息小部件
          cameraSelectorInfoPopUpContent: const Column(
            children: [
              Padding(
                padding: EdgeInsets.only(bottom: 10),
                child: Text(
                  "Notice: This feature only works if your phone has a wide angle camera.",
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Color(0xffDB4A3C),
                  ),
                ),
              ),
              Text(
                "Select the camera with the widest viewing angle below.",
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Color(0xffEFEFEF),
                ),
              ),
            ],
          ),
          // 回调函数:当360度捕捉结束时调用
          onCaptureEnded: (data) {
            if (data['success'] == true) {
              // 将图像保存到相册
              XFile panorama = data['panorama'];
              GallerySaver.saveImage(panorama.path);
              displayPanoramaMessage(context, 'Panorama saved!');
            } else {
              displayPanoramaMessage(context, 'Panorama failed!');
            }
            print(data);
          },
          // 回调函数:当摄像头镜头改变时调用
          onCameraChanged: (cameraKey) {
            displayPanoramaMessage(
                context, "Camera changed ${cameraKey.toString()}");
          },
          // 回调函数:当捕捉进度改变时调用
          onProgressChanged: (newProgressPercentage) {
            debugPrint(
                "'Panorama360': Progress changed: $newProgressPercentage");
            setState(() {
              progressPecentage = newProgressPercentage;
            });
          },
        ),
        Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Text(
              "Progress: $progressPecentage",
              style: const TextStyle(
                  color: Colors.white, backgroundColor: Colors.black),
            )
          ],
        ),
      ],
    );
  }
}

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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用camera_360插件来实现全景相机功能的代码示例。请注意,camera_360这个具体的插件名称可能是一个假设名称,因为Flutter生态系统中并没有一个直接叫做camera_360的官方插件。不过,我们可以基于类似的原理来编写一个示例代码,假设有一个支持全景拍摄的插件。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加这个假设的camera_360插件依赖。如果真实存在,你应该找到它的正确名称和版本。

dependencies:
  flutter:
    sdk: flutter
  camera_360: ^x.y.z  # 替换为实际插件的版本号

2. 导入插件并请求权限

在你的Flutter应用的main.dart文件或者相应的页面文件中,导入插件并请求必要的权限(如相机权限)。

import 'package:flutter/material.dart';
import 'package:camera_360/camera_360.dart';  // 假设插件的导入路径
import 'package:permission_handler/permission_handler.dart';  // 用于请求权限

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Camera360Page(),
    );
  }
}

class Camera360Page extends StatefulWidget {
  @override
  _Camera360PageState createState() => _Camera360PageState();
}

class _Camera360PageState extends State<Camera360Page> {
  late Camera360Controller cameraController;
  bool hasPermission = false;

  @override
  void initState() {
    super.initState();
    _requestCameraPermission();
  }

  Future<void> _requestCameraPermission() async {
    try {
      bool result = await Permission.camera.request();
      if (!result) {
        throw new Exception('Camera permission is required.');
      }
      setState(() {
        hasPermission = result;
      });
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (!hasPermission) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Camera Permission Required'),
        ),
        body: Center(
          child: Text('You need to grant camera permission to use this feature.'),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        title: Text('360 Camera'),
      ),
      body: CameraPreview(cameraController: cameraController),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          // 假设有一个方法来捕获全景图片
          try {
            File imageFile = await cameraController.capturePanorama();
            print('Panorama image saved to: ${imageFile.path}');
          } catch (e) {
            print(e);
          }
        },
        tooltip: 'Capture Panorama',
        child: Icon(Icons.camera),
      ),
    );
  }
}

3. 初始化Camera360Controller

由于假设的Camera360Controller并没有具体的初始化方法,以下是一个假设的初始化方法,你需要根据实际的插件文档来替换。

@override
void initState() {
  super.initState();
  _requestCameraPermission();
  
  // 假设有一个异步方法来初始化Camera360Controller
  _initializeCameraController().then((controller) {
    setState(() {
      cameraController = controller;
    });
  });
}

Future<Camera360Controller> _initializeCameraController() async {
  // 这里应该是插件提供的初始化方法
  // 例如: Camera360Controller.init()
  return Camera360Controller();  // 这是一个假设的返回值
}

注意事项

  1. 插件可用性:请确保有一个支持全景拍摄的Flutter插件可用,并查阅其官方文档以获取正确的初始化方法和API调用。
  2. 权限处理:使用相机功能时,务必处理相机权限请求,并确保用户已经授予权限。
  3. 错误处理:在实际应用中,添加更多的错误处理和用户反馈,以提升用户体验。

由于camera_360插件是假设的,以上代码需要根据实际插件的API进行调整。如果有一个具体的全景相机插件,你应该查阅其官方文档以获取详细的实现方法。

回到顶部