安卓触摸对焦

1. 相机坐标说明

触摸对焦需要通过setFocusAreas()设置对焦区域,而该方法的参数的坐标,与屏幕坐标并不相同,需要做一个转换。

Camera(旧版相机API)来说,相机的坐标区域是一个2000*2000,原点在中心区域,该区域与相机预览画面的边界重合,如下图所示:

相机坐标与屏幕坐标

谷歌的文档对getFocusAreas()方法的描述如下(文档连接):

Gets the current focus areas. Camera driver uses the areas to decide focus.

Before using this API or setFocusAreas(java.util.List), apps should call getMaxNumFocusAreas() to know the maximum
number of focus areas first. If the value is 0, focus area is not supported.

Each focus area is a rectangle with specified weight. The direction is relative to the sensor orientation, that is,
what the sensor sees. The direction is not affected by the rotation or mirroring of Camera.setDisplayOrientation(int).
Coordinates of the rectangle range from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000) is the lower
right point. The width and height of focus areas cannot be 0 or negative.

The weight must range from 1 to 1000. The weight should be interpreted as a per-pixel weight - all pixels in the area
have the specified weight. This means a small area with the same weight as a larger area will have less influence on the
focusing than the larger area. Focus areas can partially overlap and the driver will add the weights in the overlap
region.

A special case of a null focus area list means the driver is free to select focus targets as it wants. For example,
the driver may use more signals to select focus areas and change them dynamically. Apps can set the focus area list to
null if they want the driver to completely control focusing.

Focus areas are relative to the current field of view (getZoom()). No matter what the zoom level is, (-1000,-1000)
represents the top of the currently visible camera frame. The focus area cannot be set to be outside the current field
of view, even when using zoom.

Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO, FOCUS_MODE_MACRO,
FOCUS_MODE_CONTINUOUS_VIDEO, or FOCUS_MODE_CONTINUOUS_PICTURE.

同时,设置测光区域setMeteringAreas()的方法参数的坐标,跟对焦区域的坐标是一样的,文档对getMeteringAreas()的描述如下(文档连接):

Gets the current metering areas. Camera driver uses these areas to decide exposure.

Before using this API or setMeteringAreas(java.util.List), apps should call getMaxNumMeteringAreas() to know the
maximum number of metering areas first. If the value is 0, metering area is not supported.

Each metering area is a rectangle with specified weight. The direction is relative to the sensor orientation, that is,
what the sensor sees. The direction is not affected by the rotation or mirroring of Camera.setDisplayOrientation(int).
Coordinates of the rectangle range from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000) is the lower
right point. The width and height of metering areas cannot be 0 or negative.

The weight must range from 1 to 1000, and represents a weight for every pixel in the area. This means that a large
metering area with the same weight as a smaller area will have more effect in the metering result. Metering areas can
partially overlap and the driver will add the weights in the overlap region.

A special case of a null metering area list means the driver is free to meter as it chooses. For example, the driver
may use more signals to select metering areas and change them dynamically. Apps can set the metering area list to null
if they want the driver to completely control metering.

Metering areas are relative to the current field of view (getZoom()). No matter what the zoom level is, (-1000,-1000)
represents the top of the currently visible camera frame. The metering area cannot be set to be outside the current
field of view, even when using zoom.

No matter what metering areas are, the final exposure are compensated by setExposureCompensation(int).

2. 坐标转换

根据前面对相机坐标的说明,对坐标进行转换就很简单了。

我采用的方法是:计算坐标到左上角的x、y方向的距离,与x、y轴长度的百分比,然后乘以新坐标的x、y轴长度,再根据原点与左上角的位置计算坐标。核心代码如下:

transX = (x / xMax) * 2000 - 1000
trnasY = (y / yMax) * 2000 - 1000

如果设置了预览画面的旋转角度(camera.setDisplayOrientation(orientation)),由于触摸事件中MotionEvent对象传递的是屏幕坐标,所以需要旋转。为了方便,选择在相机坐标下旋转,代码如下:

Matrix matrix = new Matrix();
matrix.setRotate(orientation);
matrix.mapRect(rectF); // rectF是相机坐标下的矩形

完整的工具类CameraAreaUtils.java代码如下:

package com.example.study.utils;import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;import com.example.study.entities.CameraAreaEntity;public class CameraAreaUtils {/*** 相机坐标区域是2000*2000,坐标原点在最中心*/private static final int CAMERA_COORDINATE_SIZE = 2000;/*** 原点到边界的距离*/private static final int CAMERA_COORDINATE_HALF_SIZE = CAMERA_COORDINATE_SIZE >> 1;/*** 根据中心点、边框边长、边框长度系数创建矩形区域** @param areaEntity 矩形区域信息* @return 矩形*/public static Rect createRect(CameraAreaEntity areaEntity) {float x = areaEntity.getX();float y = areaEntity.getY();int previewWidth = areaEntity.getPreviewWidth();int previewHeight = areaEntity.getPreviewHeight();int sideSize = (int) (areaEntity.getAreaSide() * areaEntity.getCoefficient());int left = clamp(x - sideSize / 2, 0, previewWidth);int top = clamp(y - sideSize / 2, 0, previewHeight);int right = clamp(x + sideSize / 2, 0, previewWidth);int bottom = clamp(y + sideSize / 2, 0, previewHeight);if (right - left < sideSize) {if (left == 0) {right = Math.min(sideSize, previewWidth);}if (right == previewWidth) {left = Math.max(previewWidth - sideSize, 0);}}if (bottom - top < sideSize) {if (top == 0) {bottom = Math.min(sideSize, previewHeight);}if (bottom == previewHeight) {top = Math.max(previewHeight - sideSize, 0);}}return new Rect(left, top, right, bottom);}/*** 防止坐标越界** @param position 坐标* @param min      最小值* @param max      最大值* @return 坐标*/private static int clamp(float position, int min, int max) {int pos = Math.round(position);return pos < min ? min : pos > max ? max : pos;}/*** 屏幕矩形区域转为相机矩形区域** @param areaEntity 矩形区域信息* @return 相机矩形区域*/public static Rect transToCamera(CameraAreaEntity areaEntity) {Rect rect = createRect(areaEntity);return rectFToRect(transToCamera(new RectF(rect), areaEntity));}/*** 屏幕矩形区域转为相机矩形区域** @param rectF      屏幕矩形区域* @param areaEntity 矩形区域信息* @return 相机矩形区域*/public static RectF transToCamera(RectF rectF, CameraAreaEntity areaEntity) {int previewWidth = areaEntity.getPreviewWidth();int previewHeight = areaEntity.getPreviewHeight();RectF cameraRectF = new RectF(transPositionToCameraCoordinate(rectF.left, previewWidth),transPositionToCameraCoordinate(rectF.top, previewHeight),transPositionToCameraCoordinate(rectF.right, previewWidth),transPositionToCameraCoordinate(rectF.bottom, previewHeight));// 预览画面如果有旋转,映射到相机坐标后,需要把旋转取消,才能对应真正的相机坐标Matrix matrix = new Matrix();matrix.setRotate(-1 * areaEntity.getOrientation());matrix.mapRect(cameraRectF);return cameraRectF;}/*** 将屏幕坐标转换为相机坐标** @param position 屏幕坐标某个方向的坐标值(如x)* @param srcSize  屏幕坐标对应方向的尺寸(如width)* @return 相机坐标下该方向的坐标值*/private static float transPositionToCameraCoordinate(float position, int srcSize) {return (position / srcSize) * CAMERA_COORDINATE_SIZE - CAMERA_COORDINATE_HALF_SIZE;}/*** 相机矩形区域转为屏幕矩形区域** @param rect       相机矩形区域* @param areaEntity 矩形区域信息* @return 屏幕矩形区域*/public static Rect transToScreen(Rect rect, CameraAreaEntity areaEntity) {return rectFToRect(transToScreen(new RectF(rect), areaEntity));}/*** 相机矩形区域转为屏幕矩形区域** @param rectF      相机矩形区域* @param areaEntity 矩形区域信息* @return 屏幕矩形区域*/public static RectF transToScreen(RectF rectF, CameraAreaEntity areaEntity) {int previewWidth = areaEntity.getPreviewWidth();int previewHeight = areaEntity.getPreviewHeight();// 先把相机坐标按预览的旋转角度进行旋转Matrix matrix = new Matrix();matrix.setRotate(areaEntity.getOrientation());matrix.mapRect(rectF);RectF screenRect = new RectF(transPositionToScreenCoordinate(rectF.left, previewWidth),transPositionToScreenCoordinate(rectF.top, previewHeight),transPositionToScreenCoordinate(rectF.right, previewWidth),transPositionToScreenCoordinate(rectF.bottom, previewHeight));return screenRect;}/*** 将相机坐标转换为屏幕坐标** @param position 相机坐标某个方向的坐标值(如x)* @param srcSize  相机坐标对应方向的尺寸(如width)* @return 屏幕坐标下该方向的坐标值*/private static float transPositionToScreenCoordinate(float position, int srcSize) {return ((position + CAMERA_COORDINATE_HALF_SIZE) / CAMERA_COORDINATE_SIZE) * srcSize;}/*** RectF转为Rect** @param rectF rectF对象* @return rect对象*/private static Rect rectFToRect(RectF rectF) {if (rectF == null) {return new Rect(0, 0, 0, 0);}Rect rect = new Rect();rect.left = (int) rectF.left;rect.top = (int) rectF.top;rect.right = (int) rectF.right;rect.bottom = (int) rectF.bottom;return rect;}
}

矩形区域信息类CameraAreaEntity.java:

package com.example.study.entities;public class CameraAreaEntity {/*** x轴坐标*/private float x;/*** y轴坐标*/private float y;/*** 矩形区域边长*/private int areaSide;/*** 矩形区域边长长度系数*/private float coefficient;/*** 预览画面的旋转角度*/private int orientation;/*** 屏幕宽,也就是屏幕坐标轴的x轴*/private int previewWidth;/*** 屏幕高,也就是屏幕坐标轴的y轴*/private int previewHeight;public float getX() {return x;}public void setX(float x) {this.x = x;}public float getY() {return y;}public void setY(float y) {this.y = y;}public int getAreaSide() {return areaSide;}public void setAreaSide(int areaSide) {this.areaSide = areaSide;}public float getCoefficient() {return coefficient;}public void setCoefficient(float coefficient) {this.coefficient = coefficient;}public int getOrientation() {return orientation;}public void setOrientation(int orientation) {this.orientation = orientation;}public int getPreviewWidth() {return previewWidth;}public void setPreviewWidth(int previewWidth) {this.previewWidth = previewWidth;}public int getPreviewHeight() {return previewHeight;}public void setPreviewHeight(int previewHeight) {this.previewHeight = previewHeight;}
}

3. 应用于相机

布局文件activity_camera_demo.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><SurfaceViewandroid:id="@+id/camera_preview"android:layout_width="match_parent"android:layout_height="match_parent" /><com.example.study.views.DrawViewandroid:id="@+id/camera_preview_draw"android:layout_width="match_parent"android:layout_height="match_parent" />
</FrameLayout>

绘制对焦框的DrawView.java:

package com.example.study.views;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;import java.util.ArrayList;
import java.util.List;public class DrawView extends View {private final Object lock = new Object();protected Paint paint;protected int color;private final List<Rect> rects = new ArrayList<>();private final List<float[]> dots = new ArrayList<>();public DrawView(Context context) {super(context);}public DrawView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public void clear() {synchronized (lock) {rects.clear();dots.clear();}postInvalidate();}public void addRect(Rect rect) {synchronized (lock) {rects.add(rect);}}public void addPoint(float x, float y) {synchronized (lock) {dots.add(new float[]{x, y});}}public void setColor(int color) {this.color = color;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);synchronized (lock) {paint = new Paint();paint.setStyle(Paint.Style.STROKE);paint.setColor(color);for (Rect rect : rects) {paint.setStrokeWidth(4);canvas.drawRect(rect, paint);}for (float[] dot : dots) {paint.setStrokeWidth(10);canvas.drawPoint(dot[0], dot[1], paint);}}}
}

触摸监听类TouchListener.java:

package com.example.study.listeners;import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;import com.example.study.entities.CameraAreaEntity;
import com.example.study.utils.CameraAreaUtils;
import com.example.study.views.DrawView;import java.util.ArrayList;
import java.util.List;public class TouchListener implements View.OnTouchListener {private static final String TAG = "TouchListener";private static final int AREA_SIDE = 210;private int orientation;private int leftMargin;private int topMargin;private Camera camera;private DrawView drawView;public TouchListener(Camera camera, int orientation, DrawView drawView, int leftMargin, int topMargin) {this.camera = camera;this.orientation = orientation;this.drawView = drawView;this.leftMargin = leftMargin;this.topMargin = topMargin;}@Overridepublic boolean onTouch(View view, MotionEvent event) {try {handlerFocusAndMetering(event);} catch (Exception exception) {Log.i(TAG, exception.getMessage());}return true;}private void handlerFocusAndMetering(MotionEvent event) {// 只有一根手指且按下时,才设置对焦区域if (event.getPointerCount() != 1 || event.getActionMasked() != MotionEvent.ACTION_DOWN) {return;}drawView.clear();drawView.setColor(Color.WHITE);boolean supportSetArea = false;CameraAreaEntity areaEntity = createAreaEntity(event);drawView.addPoint(areaEntity.getX(), areaEntity.getY());Camera.Parameters parameters = camera.getParameters();// 检查是否支持设置对焦区域if (parameters.getMaxNumFocusAreas() > 0) {areaEntity.setCoefficient(1.0f);parameters.setFocusAreas(getAreas(areaEntity));// 绘制对焦区域drawView.addRect(CameraAreaUtils.createRect(areaEntity));supportSetArea = true;}// 检查是否支持设置测光区域if (parameters.getMaxNumMeteringAreas() > 0) {areaEntity.setCoefficient(1.5f);parameters.setMeteringAreas(getAreas(areaEntity));// 绘制测光区域drawView.addRect(CameraAreaUtils.createRect(areaEntity));supportSetArea = true;}drawView.setBackgroundColor(Color.TRANSPARENT);drawView.postInvalidate();if (!supportSetArea) {return;}String currentFocusMode = parameters.getFocusMode();parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);camera.cancelAutoFocus();camera.setParameters(parameters);camera.autoFocus((success, camera) -> {drawRealArea(camera, areaEntity);Camera.Parameters params = camera.getParameters();params.setFocusMode(currentFocusMode);camera.setParameters(params);});}private CameraAreaEntity createAreaEntity(MotionEvent event) {// adjustSurface调整过左、上边距,所以需要加上边距float x = event.getX() + leftMargin;float y = event.getY() + topMargin;Camera.Parameters parameters = camera.getParameters();Camera.Size previewSize = parameters.getPreviewSize();CameraAreaEntity areaEntity = new CameraAreaEntity();areaEntity.setX(x);areaEntity.setY(y);areaEntity.setAreaSide(AREA_SIDE);areaEntity.setOrientation(orientation);areaEntity.setPreviewWidth(previewSize.height);areaEntity.setPreviewHeight(previewSize.width);return areaEntity;}private void drawRealArea(Camera camera, CameraAreaEntity areaEntity) {List<Camera.Area> focusAreas = camera.getParameters().getFocusAreas();if (focusAreas == null) {return;}drawView.clear();drawView.setColor(Color.BLUE);for (Camera.Area focusArea : focusAreas) {// previewSize的width和height正好相反Rect rect = CameraAreaUtils.transToScreen(focusArea.rect, areaEntity);drawView.addRect(rect);}drawView.setBackgroundColor(Color.TRANSPARENT);drawView.postInvalidate();}private List<Camera.Area> getAreas(CameraAreaEntity areaEntity) {List<Camera.Area> areas = new ArrayList<>();// weight:权重,取值范围为1-1000areas.add(new Camera.Area(CameraAreaUtils.transToCamera(areaEntity), 800));return areas;}
}

activity类:

package com.example.study.activities;import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.FrameLayout;import androidx.activity.ComponentActivity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;import com.example.study.R;
import com.example.study.listeners.TouchListener;
import com.example.study.views.DrawView;public class CameraDemoActivity extends ComponentActivity implements Camera.PreviewCallback, SurfaceHolder.Callback {private static final String TAG = "CameraDemoActivity";private static final int REQUEST_CAMERA = 1000;private static final int HEIGHT = 1920;private static final int WIDTH = 1080;private static final int ORIENTATION = 90;private int leftMargin = 0;private int topMargin = 0;private SurfaceView preview;private DrawView drawView;private Camera camera;private Camera.Parameters parameters;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setContentView(R.layout.activity_camera_demo);preview = findViewById(R.id.camera_preview);drawView = findViewById(R.id.camera_preview_draw);adjustSurface(preview);// 检查权限if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA);} else {preview.getHolder().addCallback(this);}}private void adjustSurface(SurfaceView cameraPreview) {FrameLayout.LayoutParams paramSurface = (FrameLayout.LayoutParams) cameraPreview.getLayoutParams();if (getSystemService(Context.WINDOW_SERVICE) != null) {WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);Display defaultDisplay = windowManager.getDefaultDisplay();Point outPoint = new Point();defaultDisplay.getRealSize(outPoint);float screenWidth = outPoint.x;float screenHeight = outPoint.y;float rate;if (screenWidth / (float) WIDTH > screenHeight / (float) HEIGHT) {rate = screenWidth / (float) WIDTH;int targetHeight = (int) (HEIGHT * rate);paramSurface.width = FrameLayout.LayoutParams.MATCH_PARENT;paramSurface.height = targetHeight;topMargin = (int) (-(targetHeight - screenHeight) / 2);if (topMargin < 0) {paramSurface.topMargin = topMargin;}} else {rate = screenHeight / (float) HEIGHT;int targetWidth = (int) (WIDTH * rate);paramSurface.width = targetWidth;paramSurface.height = FrameLayout.LayoutParams.MATCH_PARENT;leftMargin = (int) (-(targetWidth - screenWidth) / 2);if (leftMargin < 0) {paramSurface.leftMargin = leftMargin;}}}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_CAMERA && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {preview.getHolder().addCallback(this);surfaceCreated(preview.getHolder());camera.setPreviewCallback(this);camera.startPreview();}}@Overridepublic void onPreviewFrame(byte[] data, Camera camera) {Log.i(TAG, "接收到一帧图片");}@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {try {camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);parameters = camera.getParameters();// 旋转了90度,所以height、width互换parameters.setPictureSize(HEIGHT, WIDTH);parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);parameters.setPictureFormat(ImageFormat.NV21);camera.setPreviewDisplay(holder);camera.setDisplayOrientation(ORIENTATION);camera.setParameters(parameters);preview.setOnTouchListener(new TouchListener(camera, ORIENTATION, drawView, leftMargin, topMargin));} catch (Exception exception) {Log.i(TAG, exception.getMessage());}}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {if (camera != null) {camera.stopPreview();camera.setPreviewCallback(null);camera.startPreview();camera.setPreviewCallback(this);}}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {if (camera != null) {camera.stopPreview();camera.setPreviewCallback(null);camera.release();}}
}

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

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

相关文章

湖南引力:低代码技术助力军工企业实现设备管理系统创新

背景介绍 在核工业相关生产领域&#xff0c;随着技术的持续进步&#xff0c;生产活动对设备的依赖性日益增强。随着企业规模的不断扩大&#xff0c;所涉及的设备数量和种类也在急剧增长&#xff0c;这使得传统的设备管理模式逐渐显得力不从心。企业当前的设备管理主要依赖人工…

【701. 二叉搜索树中的插入操作 中等】

题目&#xff1a; 给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 &#xff0c;新值和原始二叉搜索树中的任意节点值都不同。 注意&#xff0c;可能存在多…

VR+智慧消防一体化决策平台

随着科技的飞速发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术与智慧城市建设的结合越来越紧密。在消防安全领域&#xff0c;VR技术的应用不仅能够提升消防训练的效率和安全性&#xff0c;还能在智慧消防一体化决策平台中发挥重要作用。本文将探讨“VR智慧消防一体化…

nginx http反向代理

系统&#xff1a;Ubuntu_24.0.4 1、安装nginx sudo apt-get update sudo apt-get install nginx sudo systemctl start nginx 2、配置nginx.conf文件 /etc/nginx/nginx.conf&#xff0c;但可以在 /etc/nginx/sites-available/ 目录下创建一个新的配置文件&#xff0c;并在…

arcgisPro加载CGCS2000天地图后,如何转成米单位

1、导入加载的天地图影像服务&#xff0c;一开始是经纬度显示的。 2、右键地图&#xff0c;选择需要调整的投影坐标&#xff0c;这里选择坐标如下&#xff1a; 3、点击确定后&#xff0c;就可以调整成米单位的了。 4、切换后结果如下&#xff1a; 如有需要&#xff0c;可调整成…

计算机的错误计算(二百零四)

摘要 利用两个大模型判断&#xff1a;在(0, ) 范围内&#xff0c; 和 等价吗&#xff1f;实验表明&#xff0c;两个大模型&#xff08;其中一个是数学大模型&#xff09;均在输出幻觉&#xff0c;均说等价&#xff01; 例1. 在(0, ) 范围内&#xff0c; 和 等价吗&#xf…

简单的jmeter数据请求学习

简单的jmeter数据请求学习 1.需求 我们的流程服务由原来的workflow-server调用wfms进行了优化&#xff0c;将wfms服务操作并入了workflow-server中&#xff0c;去除了原来的webservice服务调用形式&#xff0c;增加了并发处理&#xff0c;现在想测试模拟一下&#xff0c;在一…

Unity3D仿星露谷物语开发17之空库存栏UI

1、目标 将库存栏放在游戏界面中&#xff0c;一般情况下角色居中展示时库存栏在底部&#xff0c;当角色位于界面下方时库存栏展示在顶部避免遮挡。 2、CanvasGroup组件 用于集中控制UI元素的透明度、交互性和射线投射行为。CanvasGroup的Alpha属性允许渐变效果&#xff0c;I…

现代谱估计的原理及MATLAB仿真(二)(AR模型法、MVDR法、MUSIC法)

现代谱估计的原理及MATLAB仿真AR参数模型法&#xff08;参数模型功率谱估计&#xff09;、MVDR法&#xff08;最小方差无失真响应法&#xff09;、MUSIC法&#xff08;多重信号分类法&#xff09; 文章目录 前言一、AR参数模型1 原理2 MATLAB仿真 二、MVDR法1 原理2 MATLAB仿真…

交换机划分Vlan配置

交换机划分Vlan配置 实验目标 理解虚拟LAN(VLAN)基本配置&#xff1b;掌握一般交换机按端口划分VLAN的配置方法&#xff1b;掌握Tag VLAN配置方法。 实验背景 某一公司内财务部、销售部的PC通过2台交换机实现通信&#xff1b;要求财务部和销售部的PC可以互通&#xff0c;但…

《Opencv》信用卡信息识别项目

目录 一、项目介绍 二、数据材料介绍 1、模板图片&#xff08;1张&#xff09; 2、需要处理的信用卡图片&#xff08;5张&#xff09; 三、实现过程 1、导入需要用到的库 2、设置命令行参数 3、模板图像中数字的定位处理 4、信用卡图像处理 5、模板匹配 四、总结 一…

.NET AI 开发人员库 --AI Dev Gallery简单示例--问答机器人

资源及介绍接上篇 nuget引用以下组件 效果展示&#xff1a; 内存和cpu占有&#xff1a; 代码如下&#xff1a;路径换成自己的模型路径 模型请从上篇文尾下载 internal class Program{private static CancellationTokenSource? cts;private static IChatClient? model;privat…

特种设备安全管理人员免费题库限时练习(判断题)

56.(判断题)特别重大事故、重大事故、较大事故和一般事故,负责事故调查的人民政府应当自收到事故调查报告之日起15日内做出批复。 A.正确 B.错误 答案:错误 57.(判断题)每一类事故灾难的应急救援措施可能千差万别,因此其基本应急模式是不一致的。 A.正确 B.错误 答案:错…

在Virtuoso中使用Clisoft SOS

在Virtuoso中使用Clisoft SOS 由于本人也是刚接触&#xff0c;后续用到其他的再进行更新&#xff0c;博客中可能有地方写的不好&#xff0c;欢迎大佬指点。 一、打开virtuoso 创建一个cds.lib&#xff08;不受SOS版本控制&#xff09; [bhlumaster /proj/trinity/work/cds/bh…

Android Audio基础(53)——PCM逻辑设备Write数据

1. 前言 本文,我们将以回放(Playback,播放音频)为例,讲解PCM Data是如何从用户空间到内核空间,最后传递到Codec。 在 ASoC音频框架简介中,我们给出了回放(Playback)PCM数据流示意图。: 对于Linux来说,由于分为 user space 和kernel space,而且两者之间数据不能随便…

算命网站源码PHP框架_附2025新版设计书教程

算命网站源码PHP设计书 1. 项目概述 1.1 项目背景 随着互联网的发展&#xff0c;越来越多的人对命理和占卜产生了兴趣。算命网站可以为用户提供个性化的命理分析、运势预测等服务。本项目旨在设计一个基于PHP的算命网站&#xff0c;方便用户在线获取命理服务。 1.2 项目目标…

【Linux】硬链接和软连接(符号连接)

目录 硬链接 软连接 硬链接和软连接的区别 硬链接 ln根据linux系统分配给文件inode(ls -li)进行建立&#xff0c;没办法跨越文件系统 格式&#xff1a;ln 被链接的文件(源文件) 生成的链接文件(目标文件) 1) 硬链接的属性 - 相当于生成一个副本 起别名 2) 修改内容都变化…

后台管理系统全屏功能实现

后台管理系统中有一个比较常见的功能就是全屏显示&#xff0c;以方便用最大的屏幕查看系统&#xff0c;特别是在小屏模式下。 对于 screenfull 而言&#xff0c;浏览器本身已经提供了对用的 API&#xff0c;点击这里即可查看&#xff0c;这个 API 中&#xff0c;主要提供了两个…

Ensp基础实验---同网段PC以及网关之间的通信

通过安装ENSP&#xff0c;可以模拟搭建网络仿真环境&#xff0c;初步了解ENSP之后&#xff0c;可以进行一些简单的网络拓扑搭建&#xff0c;通过对相关设备的配置&#xff0c;实现网络畅通的目的 此次模拟的是同一个网段内&#xff0c;两台PC之间的通信情况&#xff0c;同时选用…

WinDbg内存泄露追踪

随着win sdk一并安装了&#xff0c;可以在C:\Program Files (x86)\Windows Kits\10\Debuggers\x64 里找到 管理员运行cmd 配置跟踪 cd C:\Program Files (x86)\Windows Kits\10\Debuggers\x64 gflags.exe设置待跟踪的应用程序 gflags.exe /i D:\XXXX.exe ust运行应用程序&am…