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
(一)Bloom介绍 Bloom(辉光、光晕、泛光)是一种常见的摄像机后处理(PostProcessing)效果,用于再现真实世界相机的成像伪影。这种效果会产生从图像中明亮区域边界延伸的光条纹(或羽毛…...
GCC 学习
GCC Resource Center for GCC Internalshttps://www.cse.iitb.ac.in/grc/这是个不错资料网站,有兴趣的可以了解下...
2023数维杯数学建模C题完整版本
已经完成全部版本,获取请查看文末下方名片 摘要 随着人工智能在多个领域的快速发展,其在文本生成上的应用引起了广泛关注。本研究聚焦于辨识人工智能(AI)生成文本的基本规则,并探究AI文本的检测及其与人类文本的区分…...
快速解密PPT幻灯片密码,让PPT重见天日
最简单的办法解密、找回和去除PPT幻灯片密码,具体步骤如下:1.百度搜索【密码帝官网】,2.点击“立即开始”在用户中心上传要解密的文件稍等片刻,就能找回密码。不用下载软件,手机电脑都可用。而且还支持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作为一个领域为基础模型开辟了道路。虽然这些模型在标准基准测试中占据主导地位,但这些模型目前获得的能力与那些将语言描述为人类交流和思维的复杂系统的能力之间存在明显的差距。针对这一点,我们强调语言变异的全部范围(例如,…...
直播岗位认知篇
一、直播岗位概述 直播岗位,也称为直播主播或直播运营,是指在互联网直播平台上进行直播活动的工作岗位。该岗位的主要职责是通过直播形式,向观众展示自己的才艺、分享生活、销售产品或服务,并引导观众互动和参与。直播主播需要具…...
后端技术知识点内容-全部内容-面试宝典-后端面试知识点
文章目录 -2 flink-1 linux of viewlinux查看占用cup最高的10个进程的命令; 〇、分布式锁 & 分布式事务0-1分布式锁--包含CAP理论模型概述分布式锁:分布式锁应该具备哪些条件:分布式锁的业务场景: 分布式锁的实现方式有&#…...
3.ubuntu20.04环境的ros搭建
ros搭建比较简单,主要步骤如下: 1.配置ros软件源: 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亿美元
米诺地尔市场规模庞大,不仅包括消费品市场和服务行业,还涵盖了创新科技领域。随着经济的发展和市场需求的不断增长,米诺地尔市场的规模将继续扩大,各行各业都将面临更多机遇和挑战。 随着社会经济发展和城市化进程的推进ÿ…...
在Spring Boot中使用Thymeleaf开发Web页面
引言: 为啥写这篇文章呢?我明明就没怎么用过这个Thymeleaf进行web开发,用JSP也行,三剑客也行,或者Vue,React,PHP等等,不好吗? 那我为啥写这篇博客呢?这个写了…...
2023年亚太杯数学建模思路 - 案例:感知机原理剖析及实现
文章目录 1 感知机的直观理解2 感知机的数学角度3 代码实现 4 建模资料 # 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法,其…...
linux高级篇基础理论五(用户安全,口令设置,JR暴力破解用户密码,NMAP端口扫描)
♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏:云计算技…...
鸿蒙原生应用/元服务开发-AGC分发如何配置版本信息(上)
1.配置HarmonyOS应用的“发布国家或地区”。 2.设置是否为开放式测试版本。 注意:HarmonyOS应用开放式测试当前仅支持手机、平板、智能手表。如开发者想发布为开放式测试版本,选择“是”。正式发布的版本请选择“否”。 3.在“软件版本”下点击“软件包…...
探索Scrapy中间件:自定义Selenium中间件实例解析
简介 Scrapy是一个强大的Python爬虫框架,可用于从网站上抓取数据。本教程将指导你创建自己的Scrapy爬虫。其中,中间件是其重要特性之一,允许开发者在爬取过程中拦截和处理请求与响应,实现个性化的爬虫行为。 本篇博客将深入探讨…...
渗透测试--3.中间人攻击
渗透测试--3.中间人攻击 一 .中间人攻击arp欺骗DNS欺骗无线局域网漏洞利用使用 Ettercap 执行欺骗攻击arp欺骗实例1、首先查看欺骗之前靶机ip以及默认网关,2、查看kali的IP地址(192.168.76.134),MAC:000c294079903、使用Ettercap,将A主机和B主机加入到target中4、点击右上…...
nginx/html关闭网页缓存方法
【问题】 通常代理服务器默认是有缓存的,即用户访问网址的时候默认获取到的是缓存,只有刷新之后才能得到服务器端的最新文件 【解决】 以nginx为例,找到配置文件nginx.conf,找到http {},在其花括号之内添加命令&…...
华为防火墙 Radius认证
实现的功能:本地内网用户上网时必须要进行Radius验证,通过后才能上网 前置工作请按这个配置:华为防火墙 DMZ 设置-CSDN博客 Windows 服务器安装 Radius 实现上网认证 拓扑图如下: 一、服务器配置 WinRadius 1、安装WinRadius …...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
