当前位置: 首页 > news >正文

Android --- CameraX讲解

预备知识

surface   surfaceView   SurfaceHolder

surface 是什么?

一句话来说: surface是一块用于填充图像数据的内存。

surfaceView 是什么?

它是一个显示surface 的View。 在app中仍在 ViewHierachy 中,但在wms 中可以理解为Server端,它与宿主窗口是分离的。(它拥有独立的绘制表面 , 它不与其它宿主窗口共享一个绘制表面,可以单独在一个线程进行绘制,并不会占用主线程的资源,这样,绘制就会比较高效,游戏、视频播放,还有最近几年比较热门的直播,都可以用surface  )

surfaceHolder 是什么?

 它是一个接口,给持有surface的对象使用。可以控制surface的大小和格式。编辑surface中的像素,以及监听surface的变化这个接口通过surfaceView获取。

CameraX

CameraX是Jetpack 支持库

特点:

1、利用的是 camera2 的功能

2、它具有生命周期的感应,使用更加简单,代码量也减少了不少。可以灵活的录制视频和拍照。

3、抹平设备兼容问题。

使用

第一步:

引入依赖

dependencies {def camerax_version = "1.2.0-alpha04"implementation "androidx.camera:camera-core:${camerax_version}"implementation "androidx.camera:camera-camera2:${camerax_version}"implementation "androidx.camera:camera-lifecycle:${camerax_version}"implementation "androidx.camera:camera-video:${camerax_version}"implementation "androidx.camera:camera-view:${camerax_version}"implementation "androidx.camera:camera-extensions:${camerax_version}"
}

使用 ViewBinding,因此请使用以下代码(在 android{} 代码块末尾)启用它:

android {buildFeatures {viewBinding true}
}

第二步:

添加布局控件。   androidx.camera.view.PreViewView

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><androidx.camera.view.PreviewViewandroid:id="@+id/viewFinder"android:layout_width="match_parent"android:layout_height="match_parent" /><Buttonandroid:id="@+id/image_capture_button"android:layout_width="110dp"android:layout_height="110dp"android:layout_marginEnd="50dp"android:layout_marginBottom="50dp"android:elevation="2dp"android:text="@string/take_photo"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@id/vertical_centerline" /><Buttonandroid:id="@+id/video_capture_button"android:layout_width="110dp"android:layout_height="110dp"android:layout_marginStart="50dp"android:layout_marginBottom="50dp"android:elevation="2dp"android:text="@string/start_capture"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toEndOf="@id/vertical_centerline" /><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/vertical_centerline"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent=".50" /></androidx.constraintlayout.widget.ConstraintLayout>

因为 build.gradle 中设置了 viewBinding = true,所以会为每个布局都生成对应的绑定类(即 activity_main.xml 自动生成 ActivityMainBinding 类)。

第三步:

设置检查相机权限:

在 MainActivity.kt 中设置检查相机权限,设置 Button 的响应事件:

package com.bignerdranch.android.cameraxappimport android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.ImageCapture
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.bignerdranch.android.cameraxapp.databinding.ActivityMainBinding
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executorstypealias LumaListener = (luma: Double) -> Unitclass MainActivity : AppCompatActivity() {private lateinit var viewBinding: ActivityMainBindingprivate var imageCapture: ImageCapture? = nullprivate var videoCapture: VideoCapture<Recorder>? = nullprivate var recording: Recording? = nullprivate lateinit var cameraExecutor: ExecutorServiceoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)viewBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(viewBinding.root)// Request camera permissionsif (allPermissionsGranted()) {startCamera()} else {ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)}// Set up the listeners for take photo and video capture buttonsviewBinding.imageCaptureButton.setOnClickListener { takePhoto() }viewBinding.videoCaptureButton.setOnClickListener { captureVideo() }cameraExecutor = Executors.newSingleThreadExecutor()}private fun takePhoto() {}private fun captureVideo() {}private fun startCamera() {}private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED}override fun onDestroy() {super.onDestroy()cameraExecutor.shutdown()}companion object {private const val TAG = "CameraXApp"private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"private const val REQUEST_CODE_PERMISSIONS = 10private val REQUIRED_PERMISSIONS =mutableListOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO).apply { }.toTypedArray()}
}

在 AndroidManifest.xml 中申请摄像头权限,其中 android.hardware.camera.any 可确保设备配有相机。指定 .any 表示它可以是前置摄像头,也可以是后置摄像头。配置如下:

<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28" />

在 MainActivity 添加如下函数,会根据用户批准的权限,执行对应的回调函数:

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)if (requestCode == REQUEST_CODE_PERMISSIONS) {if (allPermissionsGranted()) {startCamera()} else {Toast.makeText(this, "Permissions not granted by the user", Toast.LENGTH_SHORT).show()finish()}}}

第四步:

预览 摄像头、 拍照、 图片分析

初始化cameraProviderFuture 并得到cameraProvider 。

得到cameraProvider 后初始化 PreView 、ImageCapture 、ImageAnalysis。  可以看到三个单独配置的。 所以完全解耦。

 tips:

PreView: 它是相机预览的数据流图像数据通过它来传输,比如输出到surface中。

ImageCapture : 用于拍照 这里的builder 都可以设置参数,比如 大小、曝光度。

ImageAnalysis : 用于图像分析,如二维码识别、人脸等。

预览 摄像头

MainActivity 中实现 startCamera() 函数

    private fun startCamera() {// 用于将相机的生命周期绑定到生命周期所有者(MainActivity)。 这消除了打开和关闭相机的任务,因为 CameraX 具有生命周期感知能力。val cameraProviderFuture = ProcessCameraProvider.getInstance(this)// 向 cameraProviderFuture 添加监听器。添加 Runnable 作为一个参数。我们会在稍后填写它。添加 ContextCompat.getMainExecutor() 作为第二个参数。这将返回一个在主线程上运行的 Executor。cameraProviderFuture.addListener({// 将相机的生命周期绑定到应用进程中的 LifecycleOwner。val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()val preview = Preview.Builder().build().also { it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider) } // preview 作为 usecaseval cameraSelector = CameraSelector.DEFAULT_BACK_CAMERAtry {cameraProvider.unbindAll() // Unbind use cases before rebindingcameraProvider.bindToLifecycle(this, cameraSelector, preview) // Bind use cases to camera: 把 cameraSelector 和 preview 绑定} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc) // 有多种原因可能会导致此代码失败,例如应用不再获得焦点。在此记录日志。}}, ContextCompat.getMainExecutor(this))}

ImageCamera 拍照

 MainActivity 中实现 takePhoto() 函数

    private fun takePhoto() {// Get a stable reference of the modifiable image capture use caseval imageCapture = imageCapture ?: return// 存图路径和参数(时间、文件类型)val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis())val contentValues = ContentValues().apply {put(MediaStore.MediaColumns.DISPLAY_NAME, name)put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")}// 我们希望将输出保存在 MediaStore 中,以便其他应用可以显示它val outputOptions =ImageCapture.OutputFileOptions.Builder(contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build()// 拍照后的回调函数imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this),object : ImageCapture.OnImageSavedCallback {override fun onError(exc: ImageCaptureException) {Log.e(TAG, "Photo capture failed: ${exc.message}", exc)}override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {val msg = "Photo capture succeeded: ${outputFileResults.savedUri}"Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()Log.d(TAG, msg)}})}

在 MainActivity 的 startCamera() 函数中,添加如下 imageCapture = ImageCapture.Builder().build() 来初始化摄像头的 use case,并绑定到 cameraProvider.bindToLifecycle() 中,完整代码如下。

    private fun startCamera() {// 用于将相机的生命周期绑定到生命周期所有者(MainActivity)。 这消除了打开和关闭相机的任务,因为 CameraX 具有生命周期感知能力。val cameraProviderFuture = ProcessCameraProvider.getInstance(this)// 向 cameraProviderFuture 添加监听器。添加 Runnable 作为一个参数。我们会在稍后填写它。添加 ContextCompat.getMainExecutor() 作为第二个参数。这将返回一个在主线程上运行的 Executor。cameraProviderFuture.addListener({// 将相机的生命周期绑定到应用进程中的 LifecycleOwner。val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()val preview = Preview.Builder().build().also { it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider) } // preview 作为 usecaseimageCapture = ImageCapture.Builder().build()val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERAtry {cameraProvider.unbindAll() // Unbind use cases before rebindingcameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture) // Bind use cases to camera} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc) // 有多种原因可能会导致此代码失败,例如应用不再获得焦点。在此记录日志。}}, ContextCompat.getMainExecutor(this))}

用 ImageAnalysis 分析各帧

使用 ImageAnalysis 功能可让相机应用变得更加有趣。它允许定义实现 ImageAnalysis.Analyzer 接口的自定义类,并使用传入的相机帧调用该类。我们无需管理相机会话状态,甚至无需处理图像;与其他生命周期感知型组件一样,仅绑定到应用所需的生命周期就足够了。

    private class LuminosityAnalyzer(private val listener: LumaListener) : ImageAnalysis.Analyzer {private fun ByteBuffer.toByteArray(): ByteArray {rewind()    // Rewind the buffer to zeroval data = ByteArray(remaining())get(data)   // Copy the buffer into a byte arrayreturn data // Return the byte array}override fun analyze(image: ImageProxy) {val buffer = image.planes[0].bufferval data = buffer.toByteArray()val pixels = data.map { it.toInt() and 0xFF }val luma = pixels.average()listener(luma)image.close()}}

然后,在 startCamera() 函数中,实例化 imageAnalyzer 对象,通过 setAnalyzer() 设置其回调函数来打印 luma(亮度),并绑定到 cameraProvider.bindToLifecycle() 上,代码如下:

    private fun startCamera() {// 用于将相机的生命周期绑定到生命周期所有者(MainActivity)。 这消除了打开和关闭相机的任务,因为 CameraX 具有生命周期感知能力。val cameraProviderFuture = ProcessCameraProvider.getInstance(this)// 向 cameraProviderFuture 添加监听器。添加 Runnable 作为一个参数。我们会在稍后填写它。添加 ContextCompat.getMainExecutor() 作为第二个参数。这将返回一个在主线程上运行的 Executor。cameraProviderFuture.addListener({// 将相机的生命周期绑定到应用进程中的 LifecycleOwner。val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()val preview = Preview.Builder().build().also { it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider) } // preview 作为 usecaseimageCapture = ImageCapture.Builder().build()val imageAnalyzer = ImageAnalysis.Builder().build().also {it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->Log.d(TAG, "Average luminosity: $luma")})}val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERAtry {cameraProvider.unbindAll() // Unbind use cases before rebindingcameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalyzer) // Bind use cases to camera} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc) // 有多种原因可能会导致此代码失败,例如应用不再获得焦点。在此记录日志。}}, ContextCompat.getMainExecutor(this))}

其实是通过 LuminosityAnalyzer.analyze() 函数内的 listener(luma) 将 luma 参数传给 listener() 函数,然后我们通过 setAnalyzer() 自定义了 listener() 函数,其接收亮度,并通过 Logcat 打印。

用 VideoCapture 录像

 MainActivity 中实现 captureVideo() 

    private fun captureVideo() {val videoCapture = this.videoCapture ?: returnviewBinding.videoCaptureButton.isEnabled = falseval curRecording = recordingif (curRecording != null) {curRecording.stop()recording = nullreturn}// create and start a new recording sessionval name = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis())val contentValues = ContentValues().apply {put(MediaStore.MediaColumns.DISPLAY_NAME, name)put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")}val mediaStoreOutputOptions = MediaStoreOutputOptions.Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI).setContentValues(contentValues).build()recording = videoCapture.output.prepareRecording(this, mediaStoreOutputOptions).apply {if (PermissionChecker.checkSelfPermission(this@MainActivity, Manifest.permission.RECORD_AUDIO) == PermissionChecker.PERMISSION_GRANTED) {withAudioEnabled()}}.start(ContextCompat.getMainExecutor(this)) { recordEvent ->when (recordEvent) {is VideoRecordEvent.Start -> {viewBinding.videoCaptureButton.apply {text = getString(R.string.stop_capture)isEnabled = true}}is VideoRecordEvent.Finalize -> {if (!recordEvent.hasError()) {val msg = "Video capture succeeded: ${recordEvent.outputResults.outputUri}"Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()Log.d(TAG, msg)} else {recording?.close()recording = nullLog.e(TAG, "Video capture ends with error: ${recordEvent.error}")}viewBinding.videoCaptureButton.apply {text = getString(R.string.start_capture)isEnabled = true}}}}}

然后,在 MainActivity 的 startCamera() 函数中,将 videoCapture 绑定到 cameraProvider.bindToLifecycle() 函数中,因为camera 同时只能绑定3种use case,所以本节在拍照、摄像、预览、分析中,选择了前3种用途,

   private fun startCamera() {// 用于将相机的生命周期绑定到生命周期所有者(MainActivity)。 这消除了打开和关闭相机的任务,因为 CameraX 具有生命周期感知能力。val cameraProviderFuture = ProcessCameraProvider.getInstance(this)// 向 cameraProviderFuture 添加监听器。添加 Runnable 作为一个参数。我们会在稍后填写它。添加 ContextCompat.getMainExecutor() 作为第二个参数。这将返回一个在主线程上运行的 Executor。cameraProviderFuture.addListener({// 将相机的生命周期绑定到应用进程中的 LifecycleOwner。val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()val preview = Preview.Builder().build().also { it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider) } // preview 作为 use caseimageCapture = ImageCapture.Builder().build()
//            val imageAnalyzer = ImageAnalysis.Builder().build().also {
//                it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
//                    Log.d(TAG, "Average luminosity: $luma")
//                })
//            }val recorder = Recorder.Builder().setQualitySelector(QualitySelector.from(Quality.HIGHEST)).build()videoCapture = VideoCapture.withOutput(recorder)val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERAtry {cameraProvider.unbindAll() // Unbind use cases before rebindingcameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, videoCapture) // Bind use cases to camera} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc) // 有多种原因可能会导致此代码失败,例如应用不再获得焦点。在此记录日志。}}, ContextCompat.getMainExecutor(this))}

​​​​​​​

结束。

参考: 

https://juejin.cn/post/7354922285092847668

https://juejin.cn/post/7354937037391986722

使用Preview预览和自定义SurfaceView或者TextureView实现CameraX预览功能_preview.setsurfaceprovider-CSDN博客

Android之SurfaceView和TextureView的分析_surfaceview和textview的区别-CSDN博客​​​​​​​
 

在Android CameraX中,PreviewView和SurfaceView的关系主要体现在它们都可以作为相机的预览显示视图,但PreviewView提供了更多的功能和灵活性。

PreviewView和SurfaceView的区别和联系

  1. 功能差异‌:

    • PreviewView‌:这是一个专门为CameraX设计的视图,支持裁剪、缩放和旋转,确保预览的正确显示。它提供了更多的控制和灵活性,例如可以设置不同的预览分辨率和帧率‌1。
    • SurfaceView‌:是一个更传统的视图,用于展示相机预览图像。它不需要布局文件中的声明,可以直接在代码中创建和使用。SurfaceView适合简单的预览需求,但在CameraX中,PreviewView是更推荐的选择‌12。
  2. 使用场景‌:

    • PreviewView‌:适用于需要高度自定义预览显示的场景,如实时视频处理、预览画面的特殊效果等。它能够更好地与CameraX的其他组件集成,提供更好的用户体验‌1。
    • SurfaceView‌:适用于简单的预览需求,不需要复杂的预览处理。虽然SurfaceView在CameraX中不是首选,但在一些旧的项目或特定的需求中仍然可以使用‌12。

如何在CameraX中使用PreviewView

  1. 添加PreviewView到布局文件‌:

     

    xmlCopy Code

    <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.camera.view.PreviewView android:id="@+id/previewView" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>

  2. 初始化ProcessCameraProvider并绑定PreviewView‌:

     

    kotlinCopy Code

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (savedInstanceState == null) {

Android OpenGL ES 学习(一) -- 基本概念-CSDN博客

Android 音视频编解码(一) -- MediaCodec 初探_安卓音视频解码-CSDN博客

相关文章:

Android --- CameraX讲解

预备知识 surface surfaceView SurfaceHolder surface 是什么&#xff1f; 一句话来说&#xff1a; surface是一块用于填充图像数据的内存。 surfaceView 是什么&#xff1f; 它是一个显示surface 的View。 在app中仍在 ViewHierachy 中&#xff0c;但在wms 中可以理解为…...

动态分库分表

1. 动态分库分表的核心目标 解决单库性能瓶颈&#xff1a;通过水平拆分数据&#xff0c;提升并发处理能力。 支持弹性扩展&#xff1a;在不中断服务的前提下&#xff0c;实现数据分片的动态扩容/缩容。 避免跨分片操作&#xff1a;减少跨分片查询&#xff08;如JOIN、事务&am…...

shell -c

个人博客地址&#xff1a;shell -c | 一张假钞的真实世界 shell -c {string}&#xff1a;表示命令从-c后的字符串读取。在需要使用管道或者重定向需要sudo时很有用&#xff0c;如下&#xff1a; $ sudo find ../*/exportFiles -mtime 15 -name "*" | xargs -I {} r…...

Spring Boot 2 快速教程:WebFlux处理流程(五)

WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤&#xff1a; 第一步&#xff1a;发起请求到前端控制器(DispatcherServlet) 第二步&#xff1a;前端控制器请求HandlerMapping查找 Handler &#xff08;可以根据xml配置、注解进行查找&#xff09; 匹配条件包括…...

10.8 LangChain Output Parsers终极指南:从JSON解析到流式处理的规范化输出实践

LangChain Output Parsers终极指南:从JSON解析到流式处理的规范化输出实践 关键词: LangChain Output Parsers、结构化输出、JSON解析、数据校验、流式处理 一、为什么需要规范化输出?大模型输出的“荒野西部”问题 原始输出的三大痛点: 格式不可控:模型可能返回纯文本、…...

G1. Yunli‘s Subarray Queries (easy version)

题目链接&#xff1a;Problem - 2009G1 - Codeforces 题目大意&#xff1a; 给你一个长度为n的整数数组a序列&#xff0c; 然后你可以操作任何次&#xff0c; 将序列里的一个数换成其他任意数字。 后有q次询问&#xff0c; 每一次询问[L, R] 在此区间里&#xff0c; 可最少进行…...

[漏洞篇]SQL注入漏洞详解

[漏洞篇]SQL注入漏洞详解 介绍 把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串&#xff0c;最终达到欺骗服务器执行恶意的SQL命令。通过构造恶意的输入&#xff0c;使数据库执行恶意命令&#xff0c;造成数据泄露或者修改内容等&#xff0c;以达到攻击的目的。…...

【apt源】RK3588 平台ubuntu20.04更换apt源

RK3588芯片使用的是aarch64架构&#xff0c;因此在Ubuntu 20.04上更换apt源时需要使用针对aarch64架构的源地址。以下是针对RK3588芯片在Ubuntu 20.04上更换apt源到清华源的正确步骤&#xff1a; 步骤一&#xff1a;打开终端 在Ubuntu 20.04中&#xff0c;按下Ctrl Alt T打…...

Maven

什么是Maven&#xff1f; Maven是一个项目管理工具&#xff0c;基于POM&#xff08;Project Object Model&#xff0c;项目对象模型&#xff09;的概念呢&#xff0c;Maven可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 Maven包含了一个…...

软件工程概论试题五

一、多选 1.好的软件的基本属性包括()。 A. 效率 B. 可依赖性和信息安全性 C. 可维护性 D.可接受性 正答&#xff1a;ABCD 2.软件工程的三要素是什么()? A. 结构化 B. 工具 C.面向对象 D.数据流! E.方法 F.过程 正答&#xff1a;BEF 3.下面中英文术语对照哪些是正确的、且是属…...

Python量化交易助手:xtquant的安装与应用

Python量化交易助手&#xff1a;xtquant的安装与应用 技术背景和应用场景 在量化交易领域&#xff0c;Python因其强大的库支持和灵活性成为了许多开发者的首选语言。其中&#xff0c;xtquant 是迅投官方开发的一个Python包&#xff0c;专门用于与miniqmt通信&#xff0c;实现…...

opencv图像处理框架

一.课程简介与环境配置 二.图像基本操作 (1)计算机眼中的视觉 1)计算机眼中图像是由一块块组成&#xff0c;每一块又由很多很多个像素点组成&#xff0c;一个像素点的值是在0到255之间&#xff0c;值越大就越亮。 2)RGB表示彩色图像的三个颜色通道(红绿蓝)&#xff0c;一张…...

MotionLCM 部署笔记

目录 依赖项 humanml3d&#xff1a; sentence-t5-large 下载数据&#xff1a; 报错&#xff1a;No module named sentence_transformers 继续报错&#xff1a;from transformers.integrations import CodeCarbonCallback 解决方法&#xff1a; 推理相关 GitHub - Dai-W…...

BUUCTF_[安洵杯 2019]easy_web(preg_match绕过/MD5强碰撞绕过/代码审计)

打开靶场&#xff0c;出现下面的静态html页面&#xff0c;也没有找到什么有价值的信息。 查看页面源代码 在url里发现了img传参还有cmd 求img参数 这里先从img传参入手&#xff0c;这里我发现img传参好像是base64的样子 进行解码&#xff0c;解码之后还像是base64的样子再次进…...

LLM - 基于LM Studio本地部署DeepSeek-R1的蒸馏量化模型

文章目录 前言开发环境快速开始LM Studio简单设置模型下载开始对话 模型选择常见错误最后 前言 目前&#xff0c;受限于设备性能&#xff0c;在本地部署的基本都是DeepSeek-R1的蒸馏量化模型&#xff0c;这些蒸馏量化模型的表现可能并没有你想象的那么好。绝大部分人并不需要本…...

Intel 与 Yocto 项目的深度融合:全面解析与平台对比

在嵌入式 Linux 领域&#xff0c;Yocto 项目已成为构建定制化 Linux 发行版的事实标准&#xff0c;广泛应用于不同架构的 SoC 平台。Intel 作为 x86 架构的领导者&#xff0c;在 Yocto 生态中投入了大量资源&#xff0c;为其嵌入式处理器、FPGA 和 AI 加速硬件提供了完整的支持…...

2025-工具集合整理

科技趋势 github-rank &#x1f577;️Github China/Global User Ranking, Global Warehouse Star Ranking (Github Action is automatically updated daily). 科技爱好者周刊 制图工具 D2 D2 A modern diagram scripting language that turns text to diagrams 文档帮助 …...

快速提升网站收录:利用网站新闻发布功能

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/63.html 利用网站新闻发布功能快速提升网站收录是一个有效的策略。以下是一些具体的建议&#xff0c;帮助你更好地利用这一功能&#xff1a; 一、保持新闻更新频率 搜索引擎尤其重视网站的…...

wxss样式模板,全局配置window

1 wxss样式模板 1.1什么是wxss 1.2 rpx 1.3 样式导入 1.4 全局样式 1.5局部样式 2 全局配置 2.1 全局配置window 2.2 window 导航栏区域...

git多人协作

目录 一、项目克隆 二、 1、进入克隆仓库设置 2、协作处理 3、冲突处理 4、多人协作分支的推送拉取删除 1、分支推送&#xff08;2种&#xff09; 2、远程分支拉取&#xff08;2种&#xff09; 3、远程分支删除 一、项目克隆 git clone 画船听雨眠/test1 (自定义的名…...

Maven全解析:从基础到精通的实战指南

概念&#xff1a; Maven 是跨平台的项目管理工具。主要服务基于 Java 平台的构建&#xff0c;依赖管理和项目信息管理项目构建&#xff1a;高度自动化&#xff0c;跨平台&#xff0c;可重用的组件&#xff0c;标准化的流程 依赖管理&#xff1a; 对第三方依赖包的管理&#xf…...

使用Pytorch训练一个图像分类器

一、准备数据集 一般来说&#xff0c;当你不得不与图像、文本或者视频资料打交道时&#xff0c;会选择使用python的标准库将原始数据加载转化成numpy数组&#xff0c;甚至可以继续转换成torch.*Tensor。 对图片而言&#xff0c;可以使用Pillow库和OpenCV库对视频而言&#xf…...

除了成本核算,还有哪些财务分析工具可以提高工作效率?

除了成本核算&#xff0c;财务工作中还有多种分析工具可以提高工作效率&#xff0c;以下是详细介绍&#xff1a; 一、数据可视化工具 Power BI&#xff1a;这是一款强大的数据可视化工具&#xff0c;通过创建交互式报表、仪表板和图表来展示财务数据。它易于使用&#xff0c;提…...

【SSM】Spring + SpringMVC + Mybatis

SSM课程&#xff0c;以下为该课程的笔记 bean&#xff1a;IOC容器创建的对象 P12 bean的生命周期 在bean中定义init()和destroy()方法&#xff0c;然后在xml中配置方法名&#xff0c;让bean对象能找到对应的生命周期方法。 或通过实现接口的方式定义声明周期方法。 P13 sett…...

Windows图形界面(GUI)-QT-C/C++ - QT Tab Widget

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 一、概述 1.1 什么是 QTabWidget&#xff1f; 1.2 使用场景 二、常见样式 2.1 选项卡式界面 2.2 动态添加和删除选项卡 2.3 自定义选项卡标题和图标 三、属性设置 3.1 添加页面&…...

pstricks PGFTikz 在CTeX套装中绘图Transparency或Opacity失效的问题

我在CTeX中画图的时候&#xff0c;习惯用Geogebra先画好&#xff0c;然后生成pstricks或PGFTikz代码&#xff1a; 这样不用插入eps或pdf之类的图片&#xff0c;也是一种偷懒的方法。以前往arXiv.org上面传论文也是这样&#xff1a;代码出图&#xff0c;就不用另外上传一幅eps或…...

操作系统和中间件的信息收集

在浏览器中收集操作系统与中间件信息时&#xff0c;主要通过客户端JavaScript&#xff08;用于操作系统/浏览器信息&#xff09;和服务器端脚本&#xff08;用于中间件信息&#xff09;实现。以下是分步指南&#xff1a; 一、客户端操作系统信息收集&#xff08;JavaScript&am…...

Android --- handler详解

handler 理解 handler 是一套Android 消息传递机制&#xff0c;主要用于线程间通信。 tips&#xff1a; binder/socket 用于进程间通信。 参考&#xff1a; Android 进程间通信-CSDN博客 handler 就是主线程在起了一个子线程&#xff0c;子线程运行并生成message &#xff0c;l…...

C++:结构体和类

在之前的博客中已经讲过了C语言中的结构体概念了&#xff0c;重复的内容在这儿就不赘述了。C中的结构体在C语言的基础上还有些补充&#xff0c;在这里说明一下&#xff0c;顺便简单地讲一下类的概念。 一、成员函数 结构体类型声明的关键字是 struct &#xff0c;在C中结构体…...

初级数据结构:栈和队列

目录 一、栈 (一)、栈的定义 (二)、栈的功能 (三)、栈的实现 1.栈的初始化 2.动态扩容 3.压栈操作 4.出栈操作 5.获取栈顶元素 6.获取栈顶元素的有效个数 7.检查栈是否为空 8.栈的销毁 9.完整代码 二、队列 (一)、队列的定义 (二)、队列的功能 (三&#xff09…...

携程Java开发面试题及参考答案 (200道-下)

insert 一行数据的时候加的是什么锁?为什么? 在 MySQL 中,当执行 INSERT 操作插入一行数据时,加锁的情况会因存储引擎和具体的事务隔离级别而有所不同。一般来说,在 InnoDB 存储引擎下,INSERT 操作加的是行级排他锁(Row Exclusive Lock),以下详细说明原因。 行级排他…...

Python从0到100(八十六):神经网络-ShuffleNet通道混合轻量级网络的深入介绍

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…...

98,【6】 buuctf web [ISITDTU 2019]EasyPHP

进入靶场 代码 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;通常用于调试或展示代码&#xff0c;方便用户查看代码逻辑 highlight_file(__FILE__);// 从 GET 请求中获取名为 _ 的参数值&#xff0c;并赋值给变量 $_ // 符号用于抑制可能出现的错误信息&#xff…...

54【ip+端口+根目录通信】

上节课讲到&#xff0c;根目录起到定位作用&#xff0c;比如我们搭建一个php网站后&#xff0c;注册系统是由根目录的register.php文件执行&#xff0c;那么我们给这个根目录绑定域名https://127.0.0.1&#xff0c;当我们浏览器访问https://127.0.0.1/register.php时&#xff0…...

计算机网络 应用层 笔记 (电子邮件系统,SMTP,POP3,MIME,IMAP,万维网,HTTP,html)

电子邮件系统&#xff1a; SMTP协议 基本概念 工作原理 连接建立&#xff1a; 命令交互 客户端发送命令&#xff1a; 服务器响应&#xff1a; 邮件传输&#xff1a; 连接关闭&#xff1a; 主要命令 邮件发送流程 SMTP的缺点: MIME&#xff1a; POP3协议 基本概念…...

解析PHP文件路径相关常量

PHP文件路径相关常量包括以下几个常量&#xff1a; __FILE__&#xff1a;表示当前文件的绝对路径&#xff0c;包括文件名。 __DIR__&#xff1a;表示当前文件所在的目录的绝对路径&#xff0c;不包括文件名。 dirname(__FILE__)&#xff1a;等同于__DIR__&#xff0c;表示当前…...

蓝桥与力扣刷题(234 回文链表)

题目&#xff1a;给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&#xff1a; 输入&…...

【协议详解】卫星通信5G IoT NTN SIB33-NB 信令详解

一、SIB33信令概述 在5G非地面网络&#xff08;NTN&#xff09;中&#xff0c;卫星的高速移动性和广域覆盖特性使得地面设备&#xff08;UE&#xff09;需要频繁切换卫星以维持连接。SIB32提供了UE预测当前服务的卫星覆盖信息&#xff0c;SystemInformationBlockType33&#x…...

c语言练习题【数据类型、递归、双向链表快速排序】

练习1&#xff1a;数据类型 请写出以下几个数据的数据类型 整数 a a 的地址 存放a的数组 b 存放a的地址的数组 b的地址 c的地址 指向 printf 函数的指针 d 存放 d的数组 整数 a 的类型 数据类型是 int a 的地址 数据类型是 int*&#xff08;指向 int 类型的指针&#xff09; …...

SliverAppBar的功能和用法

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverGrid组件相关的内容&#xff0c;本章回中将介绍SliverAppBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverAppBar和普通的AppBar类似&#xff0c;它们的…...

deepseek 本地化部署和小模型微调

安装ollama 因为本人gpu卡的机器系统是centos 7, 直接使用ollama会报 所以ollama使用镜像方式进行部署&#xff0c; 拉取镜像ollama/ollama 启动命令 docker run -d --privileged -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama 查看ollama 是否启动…...

Heptagon 同步语言介绍

同步语言于20世纪80年代创立&#xff0c;用于建模、设计和实现实时关键反应系统。随着被控制系统的复杂性不断增加&#xff0c;执行速度成为一个重要标准。与此同时&#xff0c;处理器在核心数量上的增长超过了速度的提升。因此&#xff0c;我们正在寻求一种并行执行方式&#…...

Golang 并发机制-5:详解syn包同步原语

并发性是现代软件开发的一个基本方面&#xff0c;Go&#xff08;也称为Golang&#xff09;为并发编程提供了一组健壮的工具。Go语言中用于管理并发性的重要包之一是“sync”包。在本文中&#xff0c;我们将概述“sync”包&#xff0c;并深入研究其最重要的同步原语之一&#xf…...

数组排序算法

数组排序算法 用C语言实现的数组排序算法。 排序算法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度是否稳定适用场景QuickO(n log n)O(n)O(n log n)O(log n)不稳定大规模数据&#xff0c;通用排序BubbleO(n)O(n)O(n)O(1)稳定小规模数据&#xff0c;教学用途InsertO(n)…...

利用腾讯云cloud studio云端免费部署deepseek-R1

1. cloud studio 1.1 cloud studio介绍 Cloud Studio&#xff08;云端 IDE&#xff09;是基于浏览器的集成式开发环境&#xff0c;为开发者提供了一个稳定的云端工作站。支持CPU与GPU的访问。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器即可使用。Clo…...

Codeforces Round 1002 (Div. 2)(A-D)

题目链接&#xff1a;Dashboard - Codeforces Round 1002 (Div. 2) - Codeforces A. Milya and Two Arrays 思路 数组a中不同数的数量*数组b的&#xff0c;就是能够组成不同数的数量 代码 void solve(){int n;cin>>n;int cnt10;int cnt20;map<int,bool> mp;ma…...

半导体器件与物理篇7 微波二极管、量子效应和热电子器件

基本微波技术 微波频率&#xff1a;微波频率涵盖约从0.1GHz到3000GHz&#xff0c;相当于波长从300cm到0.01cm。 分布效应&#xff1a;电子部件在微波频率&#xff0c;与其在较低频率的工作行为不同。 输运线&#xff1a;一个由电阻、电容、电感三种等效基本电路部件所组成的…...

Hot100之图论

200岛屿数量 题目 思路解析 把访问过的格子插上棋子 思想是先污染再治理&#xff0c;我们有一个inArea&#xff08;&#xff09;函数&#xff0c;是判断是否出界了 我们先dfs&#xff08;&#xff09;放各个方向遍历&#xff0c;然后我们再把这个位置标为0 我们岛屿是连着…...

CSS 样式化表格:从基础到高级技巧

CSS 样式化表格&#xff1a;从基础到高级技巧 1. 典型的 HTML 表格结构2. 为表格添加样式2.1 间距和布局2.2 简单的排版2.3 图形和颜色2.4 斑马条纹2.5 样式化标题 3. 完整的示例代码4. 总结 在网页设计中&#xff0c;表格是展示数据的常见方式。然而&#xff0c;默认的表格样式…...

DeepSeek相关技术整理

相关介绍 2024年12月26日&#xff0c;DeepSeek V3模型发布&#xff08;用更低的训练成本&#xff0c;训练出更好的效果&#xff09;671B参数&#xff0c;激活37B。2025年1月20日&#xff0c;DeepSeek-R1模型发布&#xff08;仅需少量标注数据&#xff08;高质量长cot&#xff…...