Android 相机CameraX框架

news2024/10/23 14:47:34

Android 相机CameraX框架

CameraX是Jetpack 支持库,利用的是 camera2 的功能,它具有生命周期的感应,使用更加简单,代码量也减少了不少。可以灵活的录制视频和拍照
官方文档
https://developer.android.google.cn/media/camera/camerax?hl=ro
build.gradle的dependencies中引入框架

def cameraxVersion = "1.1.0-alpha05";
implementation "androidx.camera:camera-core:${cameraxVersion}"
implementation "androidx.camera:camera-camera2:${cameraxVersion}"
implementation "androidx.camera:camera-lifecycle:${cameraxVersion}"
//CameraX添加依赖
implementation "androidx.camera:camera-view:1.3.0-alpha07"
implementation 'androidx.camera:camera-video:'
implementation "androidx.lifecycle:lifecycle-common-java8:2.5.1"

配置CameraXConfig

使用 setAvailableCameraLimiter() 优化启动延迟时间。
使用 setCameraExecutor() 向 CameraX 提供应用执行器。
将默认调度器处理程序替换为 setSchedulerHandler()。
使用 setMinimumLoggingLevel() 更改日志记录级别。

图像预览PreviewView

选择相机并绑定生命周期和用例:
创建 Preview。
指定所需的相机 LensFacing 选项。
将所选相机和任意用例绑定到生命周期。
将 Preview 连接到 PreviewView。

    void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
    Preview preview = new Preview.Builder()
            .build();
            //设置缩放类型可选FIT_CENTER、FIT_START 和 FIT_END,默认缩放类型是 FILL_CENTER。
     preview .setScaleType(PreviewView.ScaleType.FIT_CENTER);
    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();
    preview.setSurfaceProvider(previewView.getSurfaceProvider());
    Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
}

图像分析ImageAnalysis

设置图片输出尺寸,输出格式,旋转角度…
输出格式:CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888。
注意:使用 ProcessCameraProvider.bindToLifecycle() 函数将 ImageAnalysis 绑定到现有的 AndroidX 生命周期

    imageAnalysis = ImageAnalysis.Builder()
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
//            .setTargetResolution(Size(1280, 720))设置实际的尺寸
            .setTargetAspectRatio(AspectRatio.RATIO_4_3) //设计宽高比
            .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
            .build()
            //创建分析器
        imageAnalysis!!.setAnalyzer(
            cameraExecutor!!,
            ImageAnalysis.Analyzer { imageProxy: ImageProxy ->
            //通过调用 ImageProxy.close() 将 ImageProxy 发布到 CameraX
                imageProxy.close()
            })
...
cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

图像拍摄输出保存

拍摄的配置参数,例如闪光灯、连续自动对焦、零快门延迟等。

        imageCapture = new ImageCapture.Builder()
                //控制闪光灯模式 FLASH_MODE_ON(拍照时,闪光灯会亮起), 
                //FLASH_MODE_OFF 闪光灯关闭,FLASH_MODE_AUTO:在弱光环境下拍摄时,自动开启闪光灯。
                .setFlashMode(ImageCapture.FLASH_MODE_ON)
                //ImageCapture.Builder.setCaptureMode() 可用于配置拍摄照片时所采用的拍摄模式:
				//CAPTURE_MODE_MINIMIZE_LATENCY:缩短图片拍摄的延迟时间。
				//CAPTURE_MODE_MAXIMIZE_QUALITY:提高图片拍摄的图片质量。
                 .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build();

拍照保存图片的方式有2种,
takePicture(OutputFileOptions, Executor, OnImageSavedCallback):此方法将拍摄的图片保存到提供的文件位置。

            val name = System.currentTimeMillis().toString() + ".jpg"
            val contentValues = ContentValues()
            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name)
            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                contentValues.put(
                    MediaStore.MediaColumns.RELATIVE_PATH,
                    FileUtils.getSystemPicDataPath() //图片路径
                )
            }
            //图片输出
            val outputFileOptions = OutputFileOptions.Builder(
                contentResolver,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                contentValues
            )
                .build()
            imageCapture!!.takePicture(
                outputFileOptions,
                ContextCompat.getMainExecutor(this),
                object : ImageCapture.OnImageSavedCallback {
                    override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                        //content://media/external/images/media/125
                        //Pictures/CameraXImage
                        //aaa图片路径.jpg
                        printLog(" aaa图片路径--" + FileUtils.getSystemPicDataPath() + name)
                        CoroutineScope(Dispatchers.IO).launch {
                            val blo = FileUtils.copyFile(
                                FileUtils.getSystemPicDataPath() + name,
                                FileUtils.getAppPicDataPath() + name
                            )
                            withContext(Dispatchers.Main) {
                                printLog("文件复制成功$blo")
                                if (blo) {
                                    File(FileUtils.getAppPicDataPath() + name).delete()
                                    binding.ivCamera.visibility = View.VISIBLE
                                    FileUtils.showGlidePic(
                                        this@CameraActivity,
                                        FileUtils.getAppPicDataPath() + name,
                                        binding.ivCamera
                                    )
                                }
                            }
                        }
                        //  printLog( Objects.requireNonNull(outputFileResults.savedUri).toString())
                    }

                    override fun onError(exception: ImageCaptureException) {
                        printLog(exception.toString())
                    }
                })

另一种takePicture(Executor, OnImageCapturedCallback):此方法为拍摄的图片提供内存缓冲区。

   imageCapture!!.takePicture(ContextCompat.getMainExecutor(this), object :
                ImageCapture.OnImageCapturedCallback() {

                override fun onCaptureSuccess(image: ImageProxy) {
                    super.onCaptureSuccess(image)
                   // println(image)
                   // printLog("文件保存成功${image.format}")
                    if (image.format === ImageFormat.JPEG) {
                        val planes = image.planes
                        val buffer = planes[0].buffer
                        val size = buffer.remaining()
                        val jpeg = ByteArray(size)
                        buffer[jpeg, 0, size]
                        val bitmap: Bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.size);
                        val path=FileUtils.getAppPicDataPath() + name
                        //将bitmap保存为图片
                        val isFlag=FileUtils.bitmapToFile(bitmap,path)
                        printLog("文件保存成功$isFlag")
                        if (isFlag){
                            binding.ivCamera.visibility = View.VISIBLE
                            //存储图片成功,现实图片
                            FileUtils.showGlidePic(
                                this@CameraActivity,
                                path,
                                binding.ivCamera
                            )
                            
                        }else{
                            toast("获取图片失败")
                        
                        }
                    }
                    image.close()
                }

                override fun onError(exception: ImageCaptureException) {
                    printLog(exception.toString())
                }
            })

完整代码演示:
xml文件自定义UI

<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=".ui.activity.CameraVideo2Activity">

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

    <Button
        android:id="@+id/takeVideoBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="录像"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/takePhotoBtn"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias=".9" />

    <Button
        android:id="@+id/takePhotoBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拍照"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/takeVideoBtn"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias=".9" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity代码

public class CameraVideo2Activity extends AppCompatActivity {
    //按钮
    Button takePhotoButton;
    Button takeVideoButton;
    //预览
    PreviewView previewView;
    //权限
    private static final String[] REQUIRE_PERMISSIONS = new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
    public static final int REQUEST_CODE_PERMISSIONS = 10;
    //capture
    ImageCapture imageCapture;
    ListenableFuture<ProcessCameraProvider> processCameraProviderListenableFuture;
    //录像
    VideoCapture videoCapture;
    Recording recording;
    //executor & imageAnalysis
    private ExecutorService cameraExecutor;
    private ImageAnalysis imageAnalysis;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_video2);
        //绑定控件
        takePhotoButton = findViewById(R.id.takePhotoBtn);
        takeVideoButton = findViewById(R.id.takeVideoBtn);
        previewView = findViewById(R.id.preview_view);
        takePhotoButton.setOnClickListener(v -> takePhoto());
        takeVideoButton.setOnClickListener(v -> takeVideo());
        //获取权限
        if (havePermissions()) {
            initCamera();
        } else {
            ActivityCompat.requestPermissions(this, REQUIRE_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
        }
        //executor实例
        cameraExecutor = Executors.newSingleThreadExecutor();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        cameraExecutor.shutdown();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            initCamera();
        } else {
            finish();
        }
    }

    //判断权限是否获取
    private boolean havePermissions() {
        for (String permission : REQUIRE_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    //初始化Camera
    @SuppressLint("UnsafeOptInUsageError")
    private void initCamera() {
        ///实例化(可以设置许多属性)
        imageCapture = new ImageCapture.Builder()
                //控制闪光灯模式 FLASH_MODE_ON(拍照时,闪光灯会亮起), FLASH_MODE_OFF 闪光灯关闭
                .setFlashMode(ImageCapture.FLASH_MODE_ON)
                .build();
        Recorder recorder = new Recorder.Builder().build();
        videoCapture = VideoCapture.withOutput(recorder);
        processCameraProviderListenableFuture = ProcessCameraProvider.getInstance(this);
        processCameraProviderListenableFuture.addListener(() -> {
            try {
                //配置预览(https://developer.android.google.cn/training/camerax/preview?hl=zh-cn)
                previewView.setScaleType(PreviewView.ScaleType.FIT_CENTER);
                Preview preview = new Preview.Builder().build();
                preview.setSurfaceProvider(previewView.getSurfaceProvider());
                //绑定到生命周期
                ProcessCameraProvider processCameraProvider = processCameraProviderListenableFuture.get();
                //图片分析
                initImageAnalysis();
                //设置旋转
                setOrientationEventListener();
                //剪裁矩形(拍摄之后,对图片进行裁剪)
                ViewPort viewPort = null;
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
                    viewPort = new ViewPort.Builder(
                            new Rational(100, 100), getDisplay().getRotation()
                    ).build();
                } else {
                    viewPort = new ViewPort.Builder(
                            new Rational(100, 100), Surface.ROTATION_0
                    ).build();
                }
                UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
                        .addUseCase(preview)
                        .addUseCase(imageAnalysis)
                        .addUseCase(imageCapture)
                        .addUseCase(videoCapture)
                        .setViewPort(viewPort)
                        .build();
                processCameraProvider.unbindAll();
                Camera camera = processCameraProvider.bindToLifecycle(CameraVideo2Activity.this, CameraSelector.DEFAULT_BACK_CAMERA, useCaseGroup);//DEFAULT_BACK_CAMERA 后置摄像头
                //Camera
                CameraControl cameraControl = camera.getCameraControl();
                CameraInfo cameraInfo = camera.getCameraInfo();
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        }, ContextCompat.getMainExecutor(this));
    }

    //图片分析
    @SuppressLint("UnsafeOptInUsageError")
    private void initImageAnalysis() {
        imageAnalysis = new ImageAnalysis.Builder()
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build();
        imageAnalysis.setAnalyzer(cameraExecutor, imageProxy -> {
            int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
            imageProxy.close();
        });
    }

    ///旋转
    //orientation为北为0,顺时针度数0-360
    //Surface.ROTATION_270将拍摄好的图片顺时针旋转270度
    private void setOrientationEventListener() {
        OrientationEventListener orientationEventListener = new OrientationEventListener(this) {
            @Override
            public void onOrientationChanged(int orientation) {
                int rotation;
                if (orientation >= 45 && orientation < 135) {
                    rotation = Surface.ROTATION_270;
                } else if (orientation >= 135 && orientation < 225) {
                    rotation = Surface.ROTATION_180;
                } else if (orientation >= 225 && orientation < 315) {
                    rotation = Surface.ROTATION_90;
                } else {
                    rotation = Surface.ROTATION_0;
                }
                imageCapture.setTargetRotation(rotation);
            }
        };
        orientationEventListener.enable();
    }

    //拍照
    private void takePhoto() {
        if (imageCapture != null) {
            //ContentValues
            String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.SIMPLIFIED_CHINESE).format(System.currentTimeMillis());
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name);
            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/CameraXImage");
            }
            //图片输出
            ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions
                    .Builder(getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
                    .build();
            imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {
                @Override
                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                    //content://media/external/images/media/125
                    //Pictures/CameraXImage
                    //aaa图片路径5.jpg
                    System.out.println("图片路径--"+name+".jpg");
                    Log.i("camera", Objects.requireNonNull(outputFileResults.getSavedUri()).toString());
                }

                @Override
                public void onError(@NonNull ImageCaptureException exception) {
                    Log.e("camera", exception.toString());
                }
            });
        }
    }

    //录像
    private void takeVideo() {
        if (videoCapture != null) {
            takeVideoButton.setEnabled(false);
            if (recording != null) {
                recording.stop();
                recording = null;
                return;
            }
            String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.SIMPLIFIED_CHINESE).format(System.currentTimeMillis()) + ".mp4";
            ContentValues contentValues = new ContentValues();
            contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name);
            contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "Movies/CameraX-Video");
            }
            MediaStoreOutputOptions mediaStoreOutputOptions = new MediaStoreOutputOptions
                    .Builder(getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
                    .setContentValues(contentValues)
                    .build();
            Recorder recorder = (Recorder) videoCapture.getOutput();
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, REQUIRE_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
                return;
            }
            recording = recorder.prepareRecording(this, mediaStoreOutputOptions)
                    .withAudioEnabled()
                    .start(ContextCompat.getMainExecutor(this), videoRecordEvent -> {
                        if (videoRecordEvent instanceof VideoRecordEvent.Start) {
                            takeVideoButton.setText("停止");
                            takeVideoButton.setEnabled(true);
                        } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) {
                            if (((VideoRecordEvent.Finalize) videoRecordEvent).hasError()) {
                                if (recording != null) {
                                    recording.close();
                                    recording = null;
                                }
                            } else {
                                //视频为content://media/external/video/media/122
                                //Movies/CameraX-Video/name
                                String msg = "视频为" + ((VideoRecordEvent.Finalize) videoRecordEvent).getOutputResults().getOutputUri();
                                Log.i("camera", msg);
                                Log.i("camera", "视频路径为"+name);
                            }
                            takeVideoButton.setEnabled(true);
                            takeVideoButton.setText("录像");
                        }
                    });
        }
    }
}

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

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

相关文章

RHCE——例行性工作 at、crontab

一.单一执行的列行型工作&#xff1a;仅处理执行一次就结束了 1.at命令的工作过程 &#xff08;1&#xff09;/etc/at.allow&#xff0c;写在该文件的人可以使用at命令 &#xff08;2&#xff09;/etc/at.deny&#xff0c;黑名单 &#xff08;3&#xff09;两个文件如果都…

【Spring篇】Spring的Aop详解

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】【Mybatis篇】【Spring篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;初始Sprig AOP及…

SVM(支持向量机)

SVM&#xff08;支持向量机&#xff09; 引言 支持向量机(Support Vector Machine,SVM)&#xff0c;可以用来解答二分类问题。支持向量(Support Vector)&#xff1a;把划分数据的决策边界叫做超平面&#xff0c;点到超平面的距离叫做间隔。在SVM中&#xff0c;距离超平面最近…

京东笔试题

和谐敏感词 &#x1f517; 题目地址 &#x1f389; 模拟 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();String s scanner.next();String[] words new String[…

Mapbox GL 加载GeoServer底图服务器的WMS source

貌似加载有点慢啊&#xff01;&#xff01; 1 这是底图 2 这是加载geoserver中的地图效果 3源码 3.1 geoserver中的网络请求 http://192.168.10.10:8080/geoserver/ne/wms?SERVICEWMS&VERSION1.1.1&REQUESTGetMap&formatimage/png&TRANSPARENTtrue&STYL…

Linux--epoll(ET)实现Reactor模式

Linux–多路转接之epoll Reactor反应堆模式 Reactor反应堆模式是一种事件驱动的设计模式&#xff0c;通常用于处理高并发的I/O操作&#xff0c;尤其是在服务器或网络编程中。 基本概念 Reactor模式又称之为响应器模式&#xff0c;基于事件多路复用机制&#xff0c;使得单个…

网络与信息安全工程师最新报考介绍(工信部教育与考试中心)

文章目录 前言 网络与信息安全工程师职业介绍主要的工作内容职业技能要求网络与信息安全工程师职业前景怎么样网络与信息安全工程师工作方向网络与信息安全工程师适学人群 如何入门学习网络安全 【----帮助网安学习&#xff0c;以下所有学习资料文末免费领取&#xff01;----】…

solidworks(sw)右侧资源栏变成英文,无法点击

sw右侧资源栏变成英文&#xff0c;无法点击&#xff0c;如图 使用xxclean 的扩展功能 SW右侧栏是英文 toolbox配置无效 这个按钮 修复完成之后重新打开软件查看是否变成中文。

[linux]快速入门

学习目标 通过学习能够掌握以下的linux操作 操作系统 按照应用领域的不同, 操作系统可以分为几类 桌面操作系统服务器操作系统移动设备操作系统嵌入式操作系统 不同领域的主流操作系统 桌面操作系统 Windows(用户数量最多)MacOS(操作体验好&#xff0c;办公人士首选)Linux…

Spring AI : Java写人工智能(LLM)的应用框架

Spring AI&#xff1a;为Java开发者提供高效集成大模型能力的框架 当前Java调用大模型时&#xff0c;面临缺乏优质AI应用框架的挑战。Spring作为资深的Java应用框架提供者&#xff0c;通过推出Spring AI来解决这一问题。它借鉴了langchain的核心理念&#xff0c;并结合了Java面…

解密 Redis:如何通过 IO 多路复用征服高并发挑战!

文章目录 一、什么是 IO 多路复用&#xff1f;二、为什么 Redis 要使用 IO 多路复用&#xff1f;三、Redis 如何实现 IO 多路复用&#xff1f;四、IO 多路复用的核心机制&#xff1a;epoll五、IO 多路复用在 Redis 中的工作流程六、IO 多路复用的优点七、IO 多路复用使用中的注…

安装buildkit,并使用buildkit构建containerd镜像

背景 因为K8s抛弃Docker了,所以就只装了个containerd,这样就需要一个单独的镜像构建工具了,就用了buildkit,这也是Docker公司扶持的,他们公司的人出来搞的开源工具,官网在 https://github.com/moby/buildkit 简介 服务端为buildkitd,负责和runc或containerd后端连接干活,目前…

w~自动驾驶合集6

我自己的原文哦~ https://blog.51cto.com/whaosoft/12286744 #自动驾驶的技术发展路线 端到端自动驾驶 Recent Advancements in End-to-End Autonomous Driving using Deep Learning: A SurveyEnd-to-end Autonomous Driving: Challenges and Frontiers 在线高精地图 HDMa…

windows文件拷贝给wsl2的Ubuntu

参考&#xff1a; windows文件如何直接拖拽到wsl中_win 移到文件到wsl-CSDN博客 cp -r /mnt/盘名/目标文件 要复制到wsl中的位置e.g.cp -r /mnt/d/byt5 /home Linux文件复制、移动、删除等操作命令_linux移动命令-CSDN博客 Linux 文件、文件夹的复制、移动、删除 - Be-myse…

构建后端为etcd的CoreDNS的容器集群(二)、下载最新的etcd容器镜像

在尝试获取etcd的容器的最新版本镜像时&#xff0c;使用latest作为tag取到的并非最新版本&#xff0c;本文尝试用实际最新版本的版本号进行pull&#xff0c;从而取到想的最新版etcd容器镜像。 一、用latest作为tag尝试下载最新etcd的镜像 1、下载镜像 [rootlocalhost opt]# …

多品牌摄像机视频平台EasyCVR海康大华宇视视频平台如何接入多样化设备

在实际的工程项目里&#xff0c;我们常常会面临这样的情况&#xff1a;项目管理者可能会决定使用多个品牌的视频监控摄像头&#xff0c;或者有需求将现有的、多种类型的监控系统进行整合。现在&#xff0c;让我们来探讨一下如何实现不同品牌摄像头的连接和使用。 1、GB/T281协议…

2024版最新148款CTF工具整理大全(附下载安装包)含基础环境、Web 安全、加密解密、密码爆破、文件、隐写、逆向、PWN

经常会有大学生粉丝朋友私信小强&#xff0c;想通过打CTF比赛镀金&#xff0c;作为进入一线互联网大厂的门票。 但是在CTF做题很多的时候都会用到工具&#xff0c;所以在全网苦寻CTF比赛工具安装包&#xff01; 关于我 有不少阅读过我文章的伙伴都知道&#xff0c;我曾就职于…

SSM框架实战小项目:打造高效用户管理系统 day3

前言 在前两篇博客中&#xff0c;后台已经搭建完毕&#xff0c;现在需要设计一下前端页面 webapp下的项目结构图 创建ftl文件夹&#xff0c;导入css和js 因为我们在后台的视图解析器中&#xff0c;设置了页面解析器&#xff0c;跳转路径为/ftl/*.ftl&#xff0c;所以需要ftl文件…

JAVA开源项目 网上订餐系统 计算机毕业设计

本文项目编号 T 018 &#xff0c;文末自助获取源码 \color{red}{T018&#xff0c;文末自助获取源码} T018&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 新…

Pycharm通过ssh远程docker容器搭建开发环境

本地pycharm通过ssh方式远程连接服务器&#xff08;Ubuntu&#xff09;上的docker容器&#xff0c;搭建开发环境。实现功能&#xff1a;将环境依赖打包成docker镜像&#xff0c;并在远程服务器中启动容器&#xff08;启动时做好端口映射和文件夹挂载&#xff09;&#xff0c;通…