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

Camera2的使用【详细】

目录

1.获取权限

2. 获取指定相机ID

(1)获取相机管理者CameraManager

(2)获取相机ID列表

(3)获取相机特征CameraCharacteristics

(4)获取相机朝向

3.获取相机输出尺寸

(1)根据相机ID获取相机特征

(2)获取输出流配置StreamConfigurationMap

(3)获取输出尺寸数组(参数为输出目标类)Size[]

(4)选择输出尺寸

4. SurfaceView及其他控件的准备

(1)获取视图

(2)根据相机输出尺寸宽高比设置SurfaceView宽高比尺寸

(3)添加回调

5. 创建ImageReader用于处理捕获的图片

(1)创建ImageReader

(2)设置图片可用监听器OnImageAvailableListener

6. 创建相机设备状态回调、通道并发送循环预览请求

(1)创建相机设备状态回调CameraDevice.StateCallback

(2)创建捕获请求建造者CaptureRequest.Builder(参数:模板_预览)

(3)创建捕获请求目标集合

(4)创建捕获通道CaptureSession

(5)在捕获通道完成后要设置循环请求(预览捕获请求)

7. 启动相机

8. 拍摄照片

(1)创建捕获请求建造者CaptureRequest.Builder(参数:模板_静态捕获)

(2)捕获通道执行捕获拍照捕获请求

9.程序的停止和重启

(1)停止程序需关闭相机节省资源

(2)重启程序需再次启动相机

(3)重启程序重获取ImageReader的Surface

10. 常见报错

(1) CaptureRequest contains unconfigured Input/Output Surface!

(2)Surface was abandoned

(3) MTK零延迟的Camera机制


建议相机全部操作放在非主线程中,可以避免等待SurfaceView创建阻塞主线程ImageReader的Surface在主线程创建会在onStop()方法中被摧毁等多种情况。

1.获取权限

camera权限是必须申请的,如果需要保存图片还需要读写权限,并动态申请。

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
requestPermissions(new String[]{"android.permission.CAMERA","android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE"}, 2333);
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == 2333) {for (int i = 0; i < permissions.length; i++) {if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {requestPermissions(permissions, requestCode);break;}}}}

2. 获取指定相机ID

流程:

(1)获取相机管理者CameraManager

相机管理者中存储了相机ID列表、相机特征。

(2)获取相机ID列表

String cameraIdList[] = cameraManager.getCameraIdList();

(3)获取相机特征CameraCharacteristics

CameraCharacteristics中含有相机设备的信息。

(4)获取相机朝向

cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);

//相机ID
String cameraId=null;
//(1)获取相机管理者
CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
//(2)获取相机ID列表
String cameraIdList[] = cameraManager.getCameraIdList();
for (int i = 0; i < cameraIdList.length; i++) {//(3)获取相机特征CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraIdList[i]);//(4)获取相机朝向---后置if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) {//使用该相机IDcameraId = cameraIdList[i];break;}}

3.获取相机输出尺寸

流程:

(1)根据相机ID获取相机特征

(2)获取输出流配置StreamConfigurationMap

(3)获取输出尺寸数组(参数为输出目标类)Size[]

输出尺寸参数建议选择ImageReader.class。

请注意部分相机不支持使用SurfaceView.class作为参数,可能会出现返回null,如果使用SurfaceView.class做参数要对此做好处理。

(4)选择输出尺寸

//获取相机支持尺寸
int output_width,output_height;
//(1)获取当前相机的特征
CameraCharacteristics cameraCharacteristics=cameraManager.getCameraCharacteristics(cameraId);
//(2)获取输出流配置
StreamConfigurationMap map=cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
//(3-1)获取输出尺寸数组(参数为输出目标类)
Size[] outputSizes = map.getOutputSizes(ImageReader.class);
//(4-1)选择输出尺寸
for(int i=0;i<outputSizes.length;i++){//获取需要的输出尺寸//因为相机常为90°,所以将横竖调转output_height=outputSizes[i].getWidth();output_width=outputSizes[i].getHeight();//判断是否使用本尺寸代码//... ...break;
}//(3-2)获取输出尺寸数组(参数为输出目标类)
Size[] outputSizes = map.getOutputSizes(SurfaceView.class);
if(outputSizes.length!=null){//(4-2)选择输出尺寸for(int i=0;i<outputSizes.length;i++){//获取需要的输出尺寸//因为相机常为90°,所以将横竖调转output_height=outputSizes[i].getWidth();output_width=outputSizes[i].getHeight();//判断是否使用本尺寸代码//... ...break;}
}
else{//输出尺寸数组为null时设置输出宽高尺寸output_height=640*30;output_width=480*30;
}
//例
//判断是否使用本尺寸代码
//即选择输出尺寸中最接近目标比例的尺寸
int output_width, output_height;//输出宽高比
double cha = 1000;// 实际宽高比与目标宽高比差值
double bili = 3 / 4;//目标宽/高
for (int i = 0; i < outputSize.length; i++) {int tempHeight = outputSize[i].getHeight();int tempWidth = outputSize[i].getWidth();double tempCha = (double) tempWidth /(double) tempHeight - bili;if (tempCha < 0) {tempCha = 0 - tempCha;}if (tempCha < cha) {cha = tempCha;output_width = tempWidth;output_height = tempHeight;}
}

4. SurfaceView及其他控件的准备

和Camera一样,Camera2也可以使用SurfaceView作为预览视图,但Camera2和Camera不同,他并不强制你拍摄前必须预览。

SurfaceView使用时请注意,一定要在SurfaceView创建完成后再进行预览的绑定,这一点和Camera、MediaPlayer等的操作是一样的。

但Camera绑定SurfaceView设置预览时使用的是SurfaceHolder,而Camera2使用的是Surface

SurfaceView用于显示捕获的图片,SurfaceView的Surface作为预览捕获请求的目标

流程:

(1)获取视图

(2)根据相机输出尺寸宽高比设置SurfaceView宽高比尺寸

(3)添加回调

surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {

请注意SurfaceView在onCreate()方法结束后创建完成并调用surfaceCreate()方法等待surfaceView创建完成的部分需要在非主线程

//(1)获取控件
SurfaceView surfaceView = findViewById(R.id.~);//(2)根据相机输出尺寸设置SurfaceView尺寸
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) surfaceView.getLayoutParams();
layoutParams.width = ~ ;
layoutParams.height = ~ ;
surfaceView.setLayoutParams(layoutParams);//Camera2绑定SurfaceView预览时使用的是Surface
Surface surface_surfaceView=null;//(3)SurfaceView回调
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {//构建成功//准备预览捕获请求的目标surface_surfaceView = surfaceHolder.getSurface();}public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder,int i,int i1,int i2) {//SurfaceView改变}public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {//构建摧毁surface_surfaceView = null;}
});//拍照按钮
Button button_takePicture=null;

5. 创建ImageReader用于处理捕获的图片

ImageReader用于处理捕获的图片,ImageReader的Surface作为拍照捕获请求的目标。

流程:

(1)创建ImageReader

创建ImageView的前两个参数为捕获图像的宽高,请设置。第三个参数是表示在 ImageReader 队列中同时最多可以有多少张图像。如果这个参数为 1,表示 ImageReader 只能容纳一张图像。当你获取一张新的图像时,如果队列已满,则会丢弃旧的图像。这有助于避免内存溢出或过多图像堆积的问题。

如果ImageReader是在主线程创建的,那么在关闭程序时,ImageReader的Surface会自动被摧毁,请在onRestart()重新获取!!!

(2)设置图片可用监听器OnImageAvailableListener

用ImageReader捕获图片后将调用其中的onImageAvailable()方法。

请注意onImageAvailable()方法的第二个参数为其使用的线程,不能为null

处理图像代码详解:

  • acquireNextImage() 方法用于从 ImageReader 中获取下一个可用的图像。acquireNextImage() 方法获取最新可用的图像,该图像会被移除并返回。如果没有可用的图像,此方法将会阻塞,直到有图像可用或者超时。返回的是一个 Image 对象,代表捕获到的图像数据。
  • Image 对象通过 getPlanes() 方法返回一个 Image.Plane[] 数组,每个平面包含了图像的一个通道(例如:红色、绿色、蓝色、透明度等)。通常,对于 JPEG 格式的图像,这里的数组中只有一个平面,即索引为 0 的平面。
  • ByteBuffer 是用来存储图像数据的容器。通过 getBuffer() 方法获取的 ByteBuffer 包含了图像数据。remaining() 方法返回当前位置与限制之间的元素数量,这里指的是剩余的可读取的字节数。
  • get(bytes) 方法从 ByteBuffer 中读取数据并将其存储到 bytes 数组中。
//(1)创建ImageReader,请注意宽高
ImageReader imageReader = ImageReader.newInstance(output_width, output_height, ImageFormat.JPEG, 1);
//准备拍照捕获请求的目标
Surface surface_imageReader=imageReader.getSurface();
//(2)设置图片可用监听器
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {public void onImageAvailable(ImageReader reader) {// 处理图像数据Image image = reader.acquireNextImage();ByteBuffer byteBuffer=image.getPlanes()[0].getBuffer();byte[] bytes=new byte[byteBuffer.remaining()];byteBuffer.get(bytes);//存储File file = new File(Environment.getExternalStorageDirectory() + "/picture.jpg");try (OutputStream output = new FileOutputStream(file)) {output.write(bytes);} catch (IOException e) {e.printStackTrace();}// 处理完后记得释放资源image.close();}
}, handler_ui);

6. 创建相机设备状态回调、通道并发送循环预览请求

流程:

(1)创建相机设备状态回调CameraDevice.StateCallback

CameraDevice是指具体相体设备

(2)创建捕获请求建造者CaptureRequest.Builder(参数:模板_预览)

捕获请求需要在相机启动成功后创建,即CameraDevice创建成功后。

添加目标为SurfaceView的Surface,需要确定此时的SurfaceView已经创建完成并已执行回调。

请注意SurfaceView在onCreate()方法结束后创建完成并调用surfaceCreate()方法等待surfaceView创建完成的部分需要在非主线程

(3)创建捕获请求目标集合

创建捕获通道的第一个参数为所有捕获请求的目标Surface集合,包括用于预览的SurfaceView的Surface和用于拍照的ImageReader的Surface,不能将捕获请求的目标设为不在本集合中的Surface,否则会报错。

请确保创建通道的全部Surface保持存活!!!

如果在关闭应用时销毁了surface资源,请在重启时重新获取。

如果ImageReader是在主线程创建的,那么在关闭程序时,ImageReader的Surface会自动被摧毁,请在onRestart()重新获取。

(4)创建捕获通道CaptureSession

捕获通道需要在相机启动成功后创建,即CameraDevice创建成功后。

(5)在捕获通道完成后要设置循环请求(预览捕获请求)

cameraCaptureSession.setRepeatingRequest(captureRequestBuilder_preview.build(), null, null);

//捕获通道
CameraCaptureSession captureSession;// (1) 创建相机设备状态回调-CameraDevice是指具体相体设备
CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {public void onOpened(@NonNull CameraDevice cameraDevice) {//相机设备打开myCameraDevice=cameraDevice;//捕获请求建造者CaptureRequest.Builder captureRequestBuilder_preview;try {// (2) 创建捕获请求建设者,参数:模板_预览captureRequestBuilder_preview = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);//等待SurfaceView创建完成并回调后将它的Surface设为目标while (true) {if (surface != null) {//添加目标captureRequestBuilder_preview.addTarget(surface_surfaceView);break;}Thread.sleep(40);}} catch (CameraAccessException e) {throw new RuntimeException(e);} catch (InterruptedException e) {throw new RuntimeException(e);}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {try {// (3) 创建目标合集List<Surface> list=new ArrayList();list.add(surface_surfaceView);list.add(surface_imageReader);// (4) 创建捕获通道 - 捕获通道需要在相机启动后再创建cameraDevice.createCaptureSession(list, new CameraCaptureSession.StateCallback() {public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {//捕获通道配置完成captureSession=cameraCaptureSession;// (5) 配置完成,可以开始预览 - 设置循环请求try {cameraCaptureSession.setRepeatingRequest(captureRequestBuilder_preview.build(), null, null);} catch (CameraAccessException e) {throw new RuntimeException(e);}}public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {//配置失败}}, null);} catch (CameraAccessException e) {throw new RuntimeException(e);}}}public void onDisconnected(@NonNull CameraDevice cameraDevice) {//相机设备断开if (myCameraDevice != null) {myCameraDevice.close();myCameraDevice = null;}}public void onError(@NonNull CameraDevice cameraDevice, int i) {//相机设备错误if (myCameraDevice != null) {myCameraDevice.close();myCameraDevice = null;}}
};

7. 启动相机

使用相机管理者CameraManager的openCamera()方法启动指定相机,参数为相机ID、相机状态回调、Handler。请注意第三个参数Handler用于指定回调方法在哪个线程上执行。通常情况下,相机相关的操作需要在主线程(UI 线程)执行,以确保与 UI 的交互是安全的。该参数不能为null

因启动相机会调用stateCallback中的onOpened()方法,如果该方法中存在等待surfaceView创建完成的部分,需要将openCamera()放在非主线程

//Handler
Handler handler_ui = new Handler() {public void handleMessage(@NonNull Message msg) {}
};//启动相机
cameraManager.openCamera(cameraId, stateCallback, handler_ui);//关闭相机可使用如下代码
if (myCameraDevice != null) {myCameraDevice.close();myCameraDevice = null;
}

8. 拍摄照片

流程:

(1)创建捕获请求建造者CaptureRequest.Builder(参数:模板_静态捕获)

捕获请求需要在相机启动成功后创建,即CameraDevice创建成功后。

(2)捕获通道执行捕获拍照捕获请求

button_take.setOnClickListener(new View.OnClickListener() {public void onClick(View view) {try {//(1)创建拍照的捕获请求,参数:模板_静态_捕获CaptureRequest.Builder captureRequestBuilder = myCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);//用于保存拍照的Surface(在通道创建时已在目标集合中)captureRequestBuilder.addTarget(surface_imageReader);//(2)捕获通道执行捕获请求captureSession.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() {public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {super.onCaptureStarted(session, request, timestamp, frameNumber);}},null);} catch (CameraAccessException e) {throw new RuntimeException(e);}}
});

9.程序的停止和重启

(1)停止程序需关闭相机节省资源

protected void onStop() {if (myCameraDevice != null) {myCameraDevice.close();myCameraDevice = null;}super.onStop();
}

(2)重启程序需再次启动相机

程序onStop()时相机关闭,在onRestart()中请重新openCamera()。

 protected void onRestart() {try {cameraManager.openCamera(cameraId, stateCallback, handler_ui);} catch (CameraAccessException e) {throw new RuntimeException(e);}super.onRestart();
}

(3)重启程序重获取ImageReader的Surface

 如果ImageReader是在主线程创建的,那么在关闭程序时,ImageReader的Surface会自动被摧毁,请在onRestart()重新获取!!!

 protected void onRestart() {surface_imageReader = imageReader.getSurface();try {cameraManager.openCamera(cameraId, stateCallback, handler_ui);} catch (CameraAccessException e) {throw new RuntimeException(e);}super.onRestart();
}

10. 常见报错

(1) CaptureRequest contains unconfigured Input/Output Surface!

出现这个错误的原因是我们在一次捕获capture(也就是拍照的时候),cameraCaptureSession.capture(captureRequestBuilder.build(),CaptureCallback,Handler);这个captureRequestBuilder的目标Surface必须在创建通道时,是创建通道的第一个参数(目标List<Surface>集合)中的子集,否则就报异常了。

(2)Surface was abandoned

这个异常表明在使用相机API时,一个Surface对象被放弃(abandoned)。在Camera2 API中,Surface通常用于显示相机预览或保存照片。如果在关闭应用时销毁了surface资源,请在重启时重新获取。如果ImageReader是在主线程创建的,那么在关闭程序时,ImageReader的Surface会自动被摧毁,请在onRestart()重新获取。

(3) MTK零延迟的Camera机制

预览与拍照模式传给hal层的metadata键值对的key必须保持同步,也就是说,在同一次session会话中,你给预览传了什么样的metadata键值对的key,在拍照时同样也要传这个key,哪怕你不用这个metadata去调用底层工作,value可以传0或者任何底层不接受的值,切记这个key是必须传,否则打开相机的回调函数CameraDevice.StateCallback中onError就会被底层调用,从而导致相机无法打开。

相关文章:

Camera2的使用【详细】

目录 1.获取权限 2. 获取指定相机ID (1)获取相机管理者CameraManager (2)获取相机ID列表 (3)获取相机特征CameraCharacteristics (4)获取相机朝向 3.获取相机输出尺寸 (1)根据相机ID获取相机特征 (2)获取输出流配置StreamConfigurationMap (3)获取输出尺寸数组(参数为…...

Playcanvas后处理-辉光bloom

&#xff08;一&#xff09;Bloom介绍 Bloom&#xff08;辉光、光晕、泛光&#xff09;是一种常见的摄像机后处理&#xff08;PostProcessing&#xff09;效果&#xff0c;用于再现真实世界相机的成像伪影。这种效果会产生从图像中明亮区域边界延伸的光条纹&#xff08;或羽毛…...

GCC 学习

GCC Resource Center for GCC Internalshttps://www.cse.iitb.ac.in/grc/这是个不错资料网站&#xff0c;有兴趣的可以了解下...

2023数维杯数学建模C题完整版本

已经完成全部版本&#xff0c;获取请查看文末下方名片 摘要 随着人工智能在多个领域的快速发展&#xff0c;其在文本生成上的应用引起了广泛关注。本研究聚焦于辨识人工智能&#xff08;AI&#xff09;生成文本的基本规则&#xff0c;并探究AI文本的检测及其与人类文本的区分…...

快速解密PPT幻灯片密码,让PPT重见天日

最简单的办法解密、找回和去除PPT幻灯片密码&#xff0c;具体步骤如下&#xff1a;1.百度搜索【密码帝官网】&#xff0c;2.点击“立即开始”在用户中心上传要解密的文件稍等片刻&#xff0c;就能找回密码。不用下载软件&#xff0c;手机电脑都可用。而且还支持Word、Excel、PD…...

十六、RabbitMQ快速入门

目录 一、在centos上下载MQ镜像 二、安装运行容器 三、登录进入MQ 1、添加一个新的用户 2、新建虚拟机 3、 为用户分配权限 四、RabbitMQ的基本概念 RabbitMQ中的几个概念: 五、常见消息模型 六、简单的消息生产与消费 1、消费者类 2、生产者类 3、基本消息队列的消…...

C#WPF用户控件及自定义控件实例

本文演示C#WPF自定义控件实例 用户控件(UserControl)和自定义控件(CustomControl)都是对UI控件的一种封装方式,目的都是实现封装后控件的重用。 只不过各自封装的实现方式和使用的场景上存在差异。 1 基于UserControl 创建 创建控件最简单一个方法就是基于UserControl …...

大模型的语言能力

NLP作为一个领域为基础模型开辟了道路。虽然这些模型在标准基准测试中占据主导地位&#xff0c;但这些模型目前获得的能力与那些将语言描述为人类交流和思维的复杂系统的能力之间存在明显的差距。针对这一点&#xff0c;我们强调语言变异的全部范围&#xff08;例如&#xff0c…...

直播岗位认知篇

一、直播岗位概述 直播岗位&#xff0c;也称为直播主播或直播运营&#xff0c;是指在互联网直播平台上进行直播活动的工作岗位。该岗位的主要职责是通过直播形式&#xff0c;向观众展示自己的才艺、分享生活、销售产品或服务&#xff0c;并引导观众互动和参与。直播主播需要具…...

后端技术知识点内容-全部内容-面试宝典-后端面试知识点

文章目录 -2 flink-1 linux of viewlinux查看占用cup最高的10个进程的命令&#xff1b; 〇、分布式锁 & 分布式事务0-1分布式锁--包含CAP理论模型概述分布式锁&#xff1a;分布式锁应该具备哪些条件&#xff1a;分布式锁的业务场景&#xff1a; 分布式锁的实现方式有&#…...

3.ubuntu20.04环境的ros搭建

ros搭建比较简单&#xff0c;主要步骤如下&#xff1a; 1.配置ros软件源&#xff1a; sudo sh -c echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list 2.配置密钥 sudo apt-key adv --keyser…...

米诺地尔行业分析:预计2029年将达到14亿美元

米诺地尔市场规模庞大&#xff0c;不仅包括消费品市场和服务行业&#xff0c;还涵盖了创新科技领域。随着经济的发展和市场需求的不断增长&#xff0c;米诺地尔市场的规模将继续扩大&#xff0c;各行各业都将面临更多机遇和挑战。 随着社会经济发展和城市化进程的推进&#xff…...

在Spring Boot中使用Thymeleaf开发Web页面

引言&#xff1a; 为啥写这篇文章呢&#xff1f;我明明就没怎么用过这个Thymeleaf进行web开发&#xff0c;用JSP也行&#xff0c;三剑客也行&#xff0c;或者Vue&#xff0c;React&#xff0c;PHP等等&#xff0c;不好吗&#xff1f; 那我为啥写这篇博客呢&#xff1f;这个写了…...

2023年亚太杯数学建模思路 - 案例:感知机原理剖析及实现

文章目录 1 感知机的直观理解2 感知机的数学角度3 代码实现 4 建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法&#xff0c;其…...

linux高级篇基础理论五(用户安全,口令设置,JR暴力破解用户密码,NMAP端口扫描)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…...

鸿蒙原生应用/元服务开发-AGC分发如何配置版本信息(上)

1.配置HarmonyOS应用的“发布国家或地区”。 2.设置是否为开放式测试版本。 注意&#xff1a;HarmonyOS应用开放式测试当前仅支持手机、平板、智能手表。如开发者想发布为开放式测试版本&#xff0c;选择“是”。正式发布的版本请选择“否”。 3.在“软件版本”下点击“软件包…...

探索Scrapy中间件:自定义Selenium中间件实例解析

简介 Scrapy是一个强大的Python爬虫框架&#xff0c;可用于从网站上抓取数据。本教程将指导你创建自己的Scrapy爬虫。其中&#xff0c;中间件是其重要特性之一&#xff0c;允许开发者在爬取过程中拦截和处理请求与响应&#xff0c;实现个性化的爬虫行为。 本篇博客将深入探讨…...

渗透测试--3.中间人攻击

渗透测试--3.中间人攻击 一 .中间人攻击arp欺骗DNS欺骗无线局域网漏洞利用使用 Ettercap 执行欺骗攻击arp欺骗实例1、首先查看欺骗之前靶机ip以及默认网关,2、查看kali的IP地址(192.168.76.134),MAC:000c294079903、使用Ettercap,将A主机和B主机加入到target中4、点击右上…...

nginx/html关闭网页缓存方法

【问题】 通常代理服务器默认是有缓存的&#xff0c;即用户访问网址的时候默认获取到的是缓存&#xff0c;只有刷新之后才能得到服务器端的最新文件 【解决】 以nginx为例&#xff0c;找到配置文件nginx.conf&#xff0c;找到http {}&#xff0c;在其花括号之内添加命令&…...

华为防火墙 Radius认证

实现的功能&#xff1a;本地内网用户上网时必须要进行Radius验证&#xff0c;通过后才能上网 前置工作请按这个配置&#xff1a;华为防火墙 DMZ 设置-CSDN博客 Windows 服务器安装 Radius 实现上网认证 拓扑图如下&#xff1a; 一、服务器配置 WinRadius 1、安装WinRadius …...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...