Flutter - 原生交互 - 相机Camera - 01

news2025/6/4 2:33:31

环境

Flutter 3.29

macOS Sequoia 15.4.1

Xcode 16.3

集成

Flutter提供了camera插件来拍照和录视频,它提供了一系列可用的相机,并使用特定的相机展示相机预览、拍照、录视频。

添加依赖

  • camera: 提供使用设备相机模块的工具
  • path_provider: 寻找存储图片的正确路径
  • path: 创建适配任何平台的路径
flutter pub add camera path_provider path

执行完成后iOS工程的GeneratedPluginRegistrant.m文件会自动生成对应的集成代码

#if __has_include(<camera_avfoundation/CameraPlugin.h>)
#import <camera_avfoundation/CameraPlugin.h>
#else
@import camera_avfoundation;
#endif

#if __has_include(<path_provider_foundation/PathProviderPlugin.h>)
#import <path_provider_foundation/PathProviderPlugin.h>
#else
@import path_provider_foundation;
#endif
...

[CameraPlugin registerWithRegistrar:[registry registrarForPlugin:@"CameraPlugin"]];


[PathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"PathProviderPlugin"]];

分析

[registry registrarForPlugin:@“CameraPlugin”]

AppDelegate.swfitapplication(_:didFinishLaunchingWithOptions:)中将FlutterAppDelegate的子类AppDelegate对象作为参数传入并调用该方法

GeneratedPluginRegistrant.register(with: self)

源码: FlutterAppDelegate.mm

- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {
  /// <1> 获取应用的flutterRootViewController对象
  FlutterViewController* flutterRootViewController = [self rootFlutterViewController];
  if (flutterRootViewController) {
    /// <4> 返回一个FlutterEngine对象
    return [[flutterRootViewController pluginRegistry] registrarForPlugin:pluginKey];
  }
  return nil;
}

// Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController {
  ///- (FlutterViewController*(^ rootFlutterViewControllerGetter) (void))
  /// <2> 检查是否有外部注入,有则使用自定义的回调获取FlutterViewController对象
  if (_rootFlutterViewControllerGetter != nil) {
    return _rootFlutterViewControllerGetter();
  }
  /// <3> 没有则检查window的rootViewController属性,如果是FlutterViewController则返回,否则返回nil
  UIViewController* rootViewController = _window.rootViewController;
  if ([rootViewController isKindOfClass:[FlutterViewController class]]) {
    return (FlutterViewController*)rootViewController;
  }
  return nil;
}
[flutterRootViewController pluginRegistry]

第<4>步中的方法调用在 FlutterViewController.mm

///  pluginRegistry方法获得一个遵守FlutterPluginRegistry协议的对象
- (id<FlutterPluginRegistry>)pluginRegistry {
    return self.engine;
}
...

/// engine是FlutterEngine对象
- (void)sharedSetupWithProject:(nullable FlutterDartProject*)project
                  initialRoute:(nullable NSString*)initialRoute {
...
engine = [[FlutterEngine alloc] initWithName:@"io.flutter"
                                         project:project
                          allowHeadlessExecution:self.engineAllowHeadlessExecution
                              restorationEnabled:self.restorationIdentifier != nil];
...
_engine = engine;
...              

- (instancetype)initWithEngine:(FlutterEngine*)engine
                       nibName:(nullable NSString*)nibName
                        bundle:(nullable NSBundle*)nibBundle {
...
_engine = engine;          

FlutterPluginRegistry协议的继承结构

17485097331657.png

FlutterEngine对象调用registrarForPlugin:方法

源码: FlutterEngine.mm

/// 文件: FlutterEngine.mm
...
/**
 * All registrars returned from registrarForPlugin:
 */
@property(nonatomic, readonly)
    NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* pluginRegistrars;
...

- (id<FlutterPluginRegistrar>)registrarForPlugin:(NSString*)pluginName {
  /// <5> 检查可变字典中是否已存在插件名的key
  id<FlutterPluginRegistrar> registrar = self.pluginRegistrars[pluginName];
  if (!registrar) {
    /// <6> 首次注册,生成FlutterEngineRegistrar对象并持有pluginName和弱引用FlutterEngine 对象

    /// 为什么是弱引用?
    /// 文件:FlutterViewController.m 强引入了FlutterEngine对象
    /// @property(nonatomic, readonly) FlutterEngine* engine;
    
    FlutterEngineRegistrar* registrarImpl =
        [[FlutterEngineRegistrar alloc] initWithPlugin:pluginName flutterEngine:self];
    /// 接收传入的pluginName  + self即FlutterEngine对象
    /// @interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
    /// @property(nonatomic, weak) FlutterEngine* flutterEngine;
    /// @implementation FlutterEngineRegistrar {
    ///   NSString* _pluginKey;
    /// }
    
    /// 因为FlutterViewController.m 已经强引入了FlutterEngine对象,所以这里的flutterEngine弱引用即可
    /// @property(nonatomic, readonly) FlutterEngine* engine;
    /// 
    /// <7> 添加到FlutterEngine对象的可变字典中
    self.pluginRegistrars[pluginName] = registrarImpl;
    registrar = registrarImpl;
  }
  /// <8> 返回FlutterEngineRegistrar注册对象,其中保存FlutterEngine相关的信息,负责与Flutter的iOS插件交互
  return registrar;
}
[CameraPlugin registerWithRegistrar:registrar]
/// camera插件的类定义
public final class CameraPlugin: NSObject, FlutterPlugin {
@protocol FlutterPlugin <NSObject, FlutterApplicationLifeCycleDelegate>
@required
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;

Flutter中的iOS插件遵守FlutterPlugin协议且必须实现+registerWithRegistrar:方法

以camera插件为例,CameraPlugin.swift是对外的Swift的接口包装

public static func register(with registrar: FlutterPluginRegistrar) {
    let instance = CameraPlugin(
      /// 文件: FlutterEngine.mm
      /// <9> 从FlutterEngineRegistrar对象中获取纹理的对象
      /// - (NSObject<FlutterTextureRegistry>*)textures {
      ///   return _flutterEngine.textureRegistry;
      /// }
      registry: registrar.textures(),
      /// Returns a `FlutterBinaryMessenger` for creating Dart/iOS communication
      /// channels to be used by the plugin.
      /// <10> 从FlutterEngineRegistrar返回Dart与iOS原生消息的对象
      messenger: registrar.messenger(),
      globalAPI: FCPCameraGlobalEventApi(binaryMessenger: registrar.messenger()),
      deviceDiscoverer: FLTDefaultCameraDeviceDiscoverer(),
      permissionManager: FLTCameraPermissionManager(
        permissionService: FLTDefaultPermissionService()),
      deviceFactory: { name in
        // TODO(RobertOdrowaz) Implement better error handling and remove non-null assertion
        FLTDefaultCaptureDevice(device: AVCaptureDevice(uniqueID: name)!)
      },
      captureSessionFactory: { FLTDefaultCaptureSession(captureSession: AVCaptureSession()) },
      captureDeviceInputFactory: FLTDefaultCaptureDeviceInputFactory(),
      captureSessionQueue: DispatchQueue(label: "io.flutter.camera.captureSessionQueue")
    )
    
    /// <11>设置Dart相机API的消息通道
    SetUpFCPCameraApi(registrar.messenger(), instance)
  }
registrar.messenger()

从前面可知registrar是一个FlutterEngineRegistrar

/// 文件: FlutterEngine.mm
@implementation FlutterEngineRegistrar {
...
- (NSObject<FlutterBinaryMessenger>*)messenger {
  /// 返回的是FlutterEngineRegistrar对象绑定的FlutterEngine中的binaryMessenger属性
  return _flutterEngine.binaryMessenger;
}
...

@implementation FlutterEngine {
...
FlutterBinaryMessengerRelay* _binaryMessenger;
...

/// FlutterEngine对象中的binaryMessenger属性是FlutterBinaryMessengerRelay对象
/// 且parent属性关联的是FlutterEngine对象
_binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self];
SetUpFCPCameraApi(registrar.messenger(), instance)

代码执行进入文件 message.g.m

void SetUpFCPCameraApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,
                                 NSObject<FCPCameraApi> *api, NSString *messageChannelSuffix) {
  messageChannelSuffix = messageChannelSuffix.length > 0
                             ? [NSString stringWithFormat:@".%@", messageChannelSuffix]
                             : @"";
  /// Returns the list of available cameras.
  /// 建立设备的相机可用列表API
  {
    FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
           initWithName:[NSString stringWithFormat:@"%@%@",
                                                   @"dev.flutter.pigeon.camera_avfoundation."
                                                   @"CameraApi.getAvailableCameras",
                                                   messageChannelSuffix]
        binaryMessenger:binaryMessenger
                  codec:FCPGetMessagesCodec()];
    if (api) {
      NSCAssert(
          [api respondsToSelector:@selector(availableCamerasWithCompletion:)],
          @"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)",
          api);
      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
        [api availableCamerasWithCompletion:^(
                 NSArray<FCPPlatformCameraDescription *> *_Nullable output,
                 FlutterError *_Nullable error) {
          callback(wrapResult(output, error));
        }];
      }];
    } else {
      [channel setMessageHandler:nil];
    }
  }
  ...
  /// 绑定一系列相机操作的API
                                 

FlutterBasicMessageChannel类在FlutterChannel.m中,先初始化一个FlutterBasicMessageChannel对象,实现上只是接收外界参数

- (instancetype)initWithName:(NSString*)name
             binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger
                       codec:(NSObject<FlutterMessageCodec>*)codec
                   taskQueue:(NSObject<FlutterTaskQueue>*)taskQueue {
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _name = [name copy];
  _messenger = messenger;
  _codec = codec;
  _taskQueue = taskQueue;
  return self;
}
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) ...];

接着判断入参的api是否不为空,api是生成的CameraPlugin对象,所以不为空,然后消息的回调

- (void)setMessageHandler:(FlutterMessageHandler)handler {
  /// 未自定义回调时,这里应该是多次调用则清空上一次的,然后再重新创建
  if (!handler) {
    if (_connection > 0) {
      [_messenger cleanUpConnection:_connection];
      _connection = 0;
    } else {
      [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil];
    }
    return;
  }

  // Grab reference to avoid retain on self.
  // `self` might be released before the block, so the block needs to retain the codec to
  // make sure it is not released with `self`
  /// 从前面的代码可以知道这个self即channel对象只有一个局部对象在持有,所以超过作用域会被回收,所以这里接收到codec
  NSObject<FlutterMessageCodec>* codec = _codec;
  FlutterBinaryMessageHandler messageHandler = ^(NSData* message, FlutterBinaryReply callback) {
    handler([codec decode:message], ^(id reply) {
      callback([codec encode:reply]);
    });
  };
  _connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
}
static FlutterBinaryMessengerConnection SetMessageHandler(
    NSObject<FlutterBinaryMessenger>* messenger,
    NSString* name,
    FlutterBinaryMessageHandler handler,
    NSObject<FlutterTaskQueue>* taskQueue) {
  /// 是否要在指定的任务队列上执行
  /// name在这里是 dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras...
  /// handler是设置的回调
  /// 发送给FlutterBinaryMessengerRelay对象
  if (taskQueue) {
    NSCAssert([messenger respondsToSelector:@selector(setMessageHandlerOnChannel:
                                                            binaryMessageHandler:taskQueue:)],
              @"");
    return [messenger setMessageHandlerOnChannel:name
                            binaryMessageHandler:handler
                                       taskQueue:taskQueue];
  } else {
    return [messenger setMessageHandlerOnChannel:name binaryMessageHandler:handler];
  }
}

进入到FlutterBinaryMessengerRelay对象的setMessageHandlerOnChannel:binaryMessageHandler:taskQueue:

文件: FlutterBinaryMessengerRelay.mm

- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel
                                          binaryMessageHandler:(FlutterBinaryMessageHandler)handler
                                                     taskQueue:
                                                         (NSObject<FlutterTaskQueue>*)taskQueue {
  /// parent就是engine对象,因此又回到engine上setMessageHandlerOnChannel:binaryMessageHandler:                                         taskQueue:
  if (self.parent) {
    return [self.parent setMessageHandlerOnChannel:channel
                              binaryMessageHandler:handler
                                         taskQueue:taskQueue];
  } else {
    FML_LOG(WARNING) << "Communicating on a dead channel.";
    return -1;
  }
}

文件: FlutterEngine.mm

- (FlutterBinaryMessengerConnection)
    setMessageHandlerOnChannel:(NSString*)channel
          binaryMessageHandler:(FlutterBinaryMessageHandler)handler
                     taskQueue:(NSObject<FlutterTaskQueue>* _Nullable)taskQueue {
  NSParameterAssert(channel);
  if (_shell && _shell->IsSetup()) {
    /// 获取原生平台的线程,并传入channel名,回调,任务队列
    self.platformView->GetPlatformMessageHandlerIos()->SetMessageHandler(channel.UTF8String,
                                                                         handler, taskQueue);
    /// std::unique_ptr<flutter::ConnectionCollection> _connections;
    /// 
    ///  文件:connection_collection.mm
    ///  ConnectionCollection::Connection   ConnectionCollection::AquireConnection(const std::string& name) {
    ///   Connection nextConnection = ++counter_;
    ///   connections_[name] = nextConnection;
    ///   return nextConnection;
    /// }
    /// FlutterEngine对象中的连接集合属性,AcquireConnection方法让connections字典中key为channel的计数加1
    return _connections->AquireConnection(channel.UTF8String);
  } else {
    NSAssert(!handler, @"Setting a message handler before the FlutterEngine has been run.");
    // Setting a handler to nil for a channel that has not yet been set up is a no-op.
    return flutter::ConnectionCollection::MakeErrorConnection(-1);
  }
}

文件: platform_view_ios.h

/// 调用GetPlatformMessageHandlerIos即返回platform_message_handler_属性
class PlatformViewIOS final : public PlatformView {
...
std::shared_ptr<PlatformMessageHandlerIos> GetPlatformMessageHandlerIos() const {
    return platform_message_handler_;
  }
...

文件: platform_view_ios.mm


PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate,
                                 const std::shared_ptr<IOSContext>& context,
                                 __weak FlutterPlatformViewsController* platform_views_controller,
                                 const flutter::TaskRunners& task_runners)
    : PlatformView(delegate, task_runners),
      ios_context_(context),
      platform_views_controller_(platform_views_controller),
      accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }),
      /// 从初始化列表中可以看出platform_message_handler_的值通过GetPlatformTaskRunner获取UI的主线程
      platform_message_handler_(
          new PlatformMessageHandlerIos(task_runners.GetPlatformTaskRunner())) {}

到这里Flutter的插件的原生代码部分已经将channel,回调,执行队列(可选)给原生平台的主线程。

获取可用相机列表

/// Dart端调用获取可用摄像头列表
final cameras = await availableCameras();

文件: camera_controller.dart

/// Completes with a list of available cameras.
///
/// May throw a [CameraException].
Future<List<CameraDescription>> availableCameras() async {
  return CameraPlatform.instance.availableCameras();
}

调用CameraPlatform对象的availableCameras方法

文件: camera_platform.dart

abstract class CameraPlatform extends PlatformInterface {
  /// Constructs a CameraPlatform.
  CameraPlatform() : super(token: _token);
  ...
  /// Completes with a list of available cameras.
  ///
  /// This method returns an empty list when no cameras are available.
  Future<List<CameraDescription>> availableCameras() {
    throw UnimplementedError('availableCameras() is not implemented.');
  }

CameraPlatform是个抽象类,要找具体的实现。找到camera插件的pubspec.yaml

flutter:
  plugin:
    implements: camera
    platforms:
      ios:
        pluginClass: CameraPlugin
        dartPluginClass: AVFoundationCamera

dartPluginClass: Optional. The Dart class that serves as the entry point for a Flutter plugin. This can be used with the Android, iOS, Linux macOS, and Windows platforms.

因此camera插件dart的入口应该是AVFoundationCamera这个类,它继承了上面的CameraPlatform抽象类

文件: avfoundation_camera.dart

class AVFoundationCamera extends CameraPlatform {
  /// Creates a new AVFoundation-based [CameraPlatform] implementation instance.
  AVFoundationCamera({ CameraApi? api})
      : _hostApi = api ?? CameraApi();
  ...
  
  Future<List<CameraDescription>> availableCameras() async {
    try {
      return (await _hostApi.getAvailableCameras())
          .map(cameraDescriptionFromPlatform)
          .toList();
    } on PlatformException catch (e) {
      throw CameraException(e.code, e.message);
    }
  }

从上面代码可知实际调用的是_hostApigetAvailableCameras方法

Future<List<PlatformCameraDescription>> getAvailableCameras() async {
    /// 前面建立channel时已经传入了,这样原生执行完相关方法后能通过channel调用对应的回调
    final String pigeonVar_channelName =
        'dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix';
    
    /// A named channel for communicating with platform plugins using asynchronous message passing.
    /// 创建异步消息
    final BasicMessageChannel<Object?> pigeonVar_channel =
        BasicMessageChannel<Object?>(
      pigeonVar_channelName,
      pigeonChannelCodec,
      binaryMessenger: pigeonVar_binaryMessenger,
    );
    /// 阻塞**发送消息**
    final List<Object?>? pigeonVar_replyList =
        await pigeonVar_channel.send(null) as List<Object?>?;
    
    /// 消息为空抛异常
    if (pigeonVar_replyList == null) {
      throw _createConnectionError(pigeonVar_channelName);
    } else if (pigeonVar_replyList.length > 1) {
      throw PlatformException(
        code: pigeonVar_replyList[0]! as String,
        message: pigeonVar_replyList[1] as String?,
        details: pigeonVar_replyList[2],
      );
    } else if (pigeonVar_replyList[0] == null) {
      throw PlatformException(
        code: 'null-error',
        message: 'Host platform returned null value for non-null return value.',
      );
    } else {
      /// 得到可用列表转换为Flutter上的摄像头描述的对象
      return (pigeonVar_replyList[0] as List<Object?>?)!
          .cast<PlatformCameraDescription>();
    }
  }
await pigeonVar_channel.send(null) as List<Object?>?;
/// Sends the specified [message] to the platform plugins on this channel.
  ///
  /// Returns a [Future] which completes to the received response, which may
  /// be null.
  Future<T?> send(T message) async {
    /// 调用binaryMessenger对象编码发送消息 && 得到返回后再解码
    return codec.decodeMessage(await binaryMessenger.send(name, codec.encodeMessage(message)));
  }

Flutter Dart端发送指定channel消息 && 调用原来添加的回调走到Flutter原生插件部分这里,比如当前走到获取可用摄像头的回调

...
[api availableCamerasWithCompletion:^(
                 NSArray<FCPPlatformCameraDescription *> *_Nullable output,
                 FlutterError *_Nullable error) {
          callback(wrapResult(output, error));
        }];

即调用api(CameraPlugin)的availableCamerasWithCompletion:方法

extension CameraPlugin: FCPCameraApi {
  public func availableCameras(
    completion: @escaping ([FCPPlatformCameraDescription]?, FlutterError?) -> Void
  ) {
    captureSessionQueue.async { [weak self] in
      guard let strongSelf = self else { return }

      var discoveryDevices: [AVCaptureDevice.DeviceType] = [
        .builtInWideAngleCamera,
        .builtInTelephotoCamera,
      ]
      ...
      /// 前置,后置等摄像头,然后统一添加到reply这个数组对象
      for device in devices {
        var lensFacing: FCPPlatformCameraLensDirection

        switch device.position {
        case .back:
          lensFacing = .back
        case .front:
          lensFacing = .front
        case .unspecified:
      ...
        }
        reply.append(cameraDescription)
      }
      
      /// 最后执行callback(wrapResult(output, error));
      /// 获取成功后,Flutter的Dart部分可以获取到可用的摄像头列表
      completion(reply, nil)
}

总结

17486664768352.jpg

  1. 原生插件将方法的channel(约定的字符串),回调设置给Flutter原生平台代码(C++ && OC)
  2. Flutter的Dart层发送消息并传递channel,Flutter根据channel找到设置的回调(Dart -> C++ && OC),然后执行原生插件提供的方法(C++ && OC)
  3. 获取执行结果并返回给Flutter的原生平台代码(C++ && OC),再发送给Dart代码(C++ && OC -> Dart)

参考

  1. camera
  2. 使用 Camera 插件实现拍照功能
  3. do-not-use-buildcontexts-across-async-gaps
  4. Flutter pubspec options
  5. 一张图理解Flutter中Dart与原生环境通信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2395616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

湖北理元理律师事务所:个人债务管理的温度与精度

湖北理元理律师事务所&#xff1a;个人债务管理的温度与精度 面对信用卡、网贷、医疗债等多重债务压力&#xff0c;普通人常陷入“拆东墙补西墙”的恶性循环。湖北理元理律师事务所通过计划集团公司服务平台&#xff0c;推出“有温度的债务优化计划”&#xff0c;其人性化设计…

Compose原理 - 整体架构与主流程

一、整体架构 在官方文档中&#xff08;Jetpack Compose 架构层 | Android Developers&#xff09;&#xff0c;对Compose的分层有所阐述&#xff1a; 其中 Runtime&#xff1a;提供Compose的基础运行能力&#xff0c;包括State、Side-effects、CompositionLocal、Compositio…

CppCon 2014 学习: C++ Test-driven Development

“Elephant in the Room”这个比喻常用来形容那些大家都知道但没人愿意讨论的重大问题。 这段内容讲的是软件质量管理的经典做法和潜在的问题&#xff1a; 经典做法&#xff1a;开发完成后才进行人工测试&#xff08;manual testing after creation&#xff09;。隐喻“Cape o…

RAGflow详解及实战指南

目录 前言 一、RAGflow核心技术解析 1. 技术原理&#xff1a;检索与生成的协同进化 2. 架构设计&#xff1a;分层模块化与高扩展性 3. 核心优势&#xff1a;精准、高效、安全 二、RAGflow实战应用场景 1. 企业知识库搭建 2. 智能客服系统 3. 投资分析报告生成 4. 制造…

[Godot] 如何导出安卓 APK 并在手机上调试

在之前的文章中&#xff0c;我们已经详细介绍了如何配置 Godot 的安卓应用开发环境&#xff0c;包括安装 Android SDK、配置 Java 环境、设置 Godot 的 Android 导出模板等。本篇文章将进一步讲解如何将 Godot 项目导出为安卓 APK 文件&#xff0c;并实现在手机上进行调试运行。…

Linux《文件系统》

在之前的系统IO当中已经了解了“内存”级别的文件操作&#xff0c;了解了文件描述符、重定向、缓冲区等概念&#xff0c;在了解了这些的知识之后还封装出了我们自己的libc库。接下来在本篇当中将会将视角从内存转向磁盘&#xff0c;研究文件在内存当中是如何进行存储的&#xf…

NLP学习路线图(十六):N-gram模型

一、为何需要语言模型&#xff1f;概率视角下的语言本质 自然语言处理的核心挑战在于让机器“理解”人类语言。这种理解的一个关键方面是处理语言的歧义性、创造性和结构性。语言模型&#xff08;Language Model, LM&#xff09;为此提供了一种强大的数学框架&#xff1a;它赋…

Python训练第四十天

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 昨天我们介绍…

InternVL2.5-多模态大模型评估专业图片

具备图像理解功能的大模型InternVL2.5&#xff0c;能有效解析大部分图片。 对于专业图片如医学细胞切片&#xff0c;从专业角度解析&#xff0c;能推动模型应用到更广泛的领域。 InternVL2.5解析示例 prompt(胸部癌变细胞图片,来自PanNuke) 请评估这个组织的风险 InternVL2.…

医疗数理范式化:从范式迁移到认知革命的深度解析

引言 在当代医疗领域,数理思维已经从辅助工具逐渐发展成为核心决策支持系统的关键组成部分。随着数字技术的迅猛发展,医疗行业正经历着前所未有的变革,而数理思维作为这一变革的核心驱动力,正在深刻重塑医疗实践的方方面面。数理思维在医疗领域的应用,本质上是将抽象的数…

图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析

现代信息检索系统和搜索引擎普遍采用两阶段检索架构&#xff0c;在人工智能应用中也被称为检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;。在初始检索阶段&#xff0c;系统采用高效的检索方法&#xff0c;包括词汇检索算法&#xff08;如BM25&…

现代数据湖架构全景解析:存储、表格式、计算引擎与元数据服务的协同生态

本文全面剖析现代数据湖架构的核心组件,深入探讨对象存储(OSS/S3)、表格式(Iceberg/Hudi/Delta Lake)、计算引擎(Spark/Flink/Presto)及元数据服务(HMS/Amoro)的协作关系,并提供企业级选型指南。 一、数据湖架构演进与核心价值 数据湖架构演进历程 现代数据湖核心价…

全志F1c200开发笔记——移植Debian文件系统

1.搭建环境 sudo apt install qemu-user-static -y sudo apt install debootstrap -y mkdir rootfs 2.拉取文件系统 这边我参照墨云大神的文档&#xff0c;但是华为镜像已经没有armel了&#xff0c;我找到了官方仓库&#xff0c;还是有的&#xff0c;拉取速度比较慢 sudo d…

支持功能安全ASIL-B的矩阵管理芯片IS32LT3365,助力ADB大灯系统轻松实现功能安全等级

随着自动驾驶技术的快速发展&#xff0c;汽车前灯智能化也越来越高。自适应远光灯 (ADB) 作为一种智能照明系统&#xff0c;在提升驾驶安全性和舒适性方面发挥着重要作用。ADB 系统通过摄像头和传感器获取前方道路信息&#xff0c;例如来车的位置、距离和速度&#xff0c;并根据…

BFS入门刷题

目录 P1746 离开中山路 P1443 马的遍历 P1747 好奇怪的游戏 P2385 [USACO07FEB] Bronze Lilypad Pond B P1746 离开中山路 #include <iostream> #include <queue> #include <cstring> using namespace std; int n; int startx, starty; int endx, endy; …

UE5 编辑器工具蓝图

文章目录 简述使用方法样例自动生成Actor&#xff0c;并根据模型的包围盒设置Actor的大小批量修改场景中Actor的属性&#xff0c;设置Actor的名字&#xff0c;设置Actor到指定的文件夹 简述 使用编辑器工具好处是可以在非运行时可以对资源或场景做一些操作&#xff0c;例如自动…

数据仓库分层 4 层模型是什么?

企业每天都在产生和收集海量数据。然而&#xff0c;面对这些数据&#xff0c;许多企业却陷入了困境&#xff1a;如何高效管理、处理和分析这些数据&#xff1f;如何从数据中提取有价值的信息来支持业务决策&#xff1f;这些问题困扰着众多数据分析师和 IT 管理者。 在众多架构…

基于亚博K210开发板——物体分类测试

开发板 亚博K210开发板 实验目的 本次测试主要学习 K210 如何物体分类&#xff0c;然后通过 LCD 显示屏实时显示当前物体的分类名称。本节采用百度出的 PaddlePaddle 平台开发。 实验元件 OV2640 摄像头/OV9655 摄像头/GC2145 摄像头、LCD 显示屏 硬件连接 K210 开发板…

什么是缺页中断(缺页中断详解)

文章目录 【操作系统】什么是缺页中断&#xff08;缺页中断详解&#xff09;一、缺页中断的本质与背景1. **虚拟内存与分页机制**2. **缺页中断的定义** 二、缺页中断的触发场景1. **首次访问新分配的虚拟页**2. **内存置换导致的页缺失**3. **访问权限冲突**4. **页表项无效**…

【echarts】仪表盘

<div style"width:50%;height:33%"><Yibiaopan echart_id"ybpChart2" :series_data"gaugeData2" title"火电" unit"MWh" :colorList"[#DFA58F,#F89061,#FF8E59]" /></div> 链接&#xff1a;ht…