Android Camera预览角度和拍照保存图片角度学习

1 Camera预览角度处理

开发Camera过程中会遇到Camera拍照,获取照片后可以上传照片或者展示给用户。
Camera的图像数据来源于摄像头硬件的图像传感器,这个图像传感器被固定到手机上后会有一个默认的方向,一般默认方向是当手机左侧横放时(手机横放并且手机顶部在左侧)。由于默认图片传感器为横向,大部分手机拍照则是竖向,所以得到的数据依然会是横向的,这时就需要对图片进行旋转。
图像传感器的取景方向与手机正常方向成90读夹角。
在这里插入图片描述
由于Camera默认是横向的,竖向拍照时得到的照片和预览的照片会有所不同,因为预览可以利用setDisplayOrientation设置预览角度调节预览图片,但是setDisplayOrientation只是改变了预览的角度,对于拍摄生成的图片依然会拿到原来的未被旋转和默认图片传感器方向相同的数据。而对于前置摄像头预览得到的图片会比后置摄像头多一个镜面效果,两者都需要对拍摄生成的图片进行旋转处理才能得到正常的符合眼睛所看到的预览图片的样式。

解决预览方向问题:setDisplayOrientation(int rotateDegree),默认情况下该方法的值为0,与图像传感器取景方向一致,竖向使用手机时只需要设置setDisplayOrientation(90)一般就可以解决预览问题
对于后置摄像头想要正常预览旋转角度应该设置为Camera默认角度减去屏幕朝向角度,这个值可能为负,角度值不能为负故需要加上360求正然后取余;对于前置摄像头拍照时可以明显发现预览图片是左右翻转的,也就是前置摄像头的预览成像是沿图像的中央垂直线翻转过来,形成镜面效果。所以前置摄像头求旋转角度为摄像头的默认角度加上手机屏幕旋转角度,之后进行镜面操作利用360度减去上面求到的值(翻转),然后加上360度(防止出现负数)之后对360度取余(预览是镜面的,但是最终拿到的data数据不是镜面翻转的,为保持和预览的一致性需要对图片进行镜面操作)。

如何计算setDisplayOrientation需要翻转的角度,每次重新预览或者SurfaceView变化都需要重新求角度:

public static int calculateCameraPreviewOrientation(Activity activity) {Camera.CameraInfo info = new Camera.CameraInfo();Camera.getCameraInfo(mCameraID, info);int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();int degrees = 0;switch (rotation) {case Surface.ROTATION_0:degrees = 0;break;case Surface.ROTATION_90:degrees = 90;break;case Surface.ROTATION_180:degrees = 180;break;case Surface.ROTATION_270:degrees = 270;break;}int result;if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {result = (info.orientation + degrees) % 360;result = (360 - result) % 360;} else {result = (info.orientation - degrees + 360) % 360;}mOrientation = result;return result;
}

setDisplayOrientation 只对预览有作用,不会影响其他数据。
info.orientation默认为90度,屏幕竖屏默认为0。

如果不设置预览角度:
在这里插入图片描述
设置了预览角度
在这里插入图片描述

2 拍照生成图片角度处理

利用Camera拍照时,读取图片数据存储为图片,取到的数据直接来源于图像传感器采集到的图像数据,预览由于setDisplayOrientation 正常但原始处于依然没有变化,所以保存的图片不与预览时看到的画面方向一致,而是与图像传感器的方向一致。竖着拍照得到的照片看起来是横向的,当横着拍照时,得到的照片看起来才是正常的。前置摄像头的预览有镜面效果,但从图像传感器采集到的数据却没有镜面效果,所以生成的图片需要镜面操作。
后置摄像头得到的图片,未经任何处理:
在这里插入图片描述
前置摄像头得到的图片未经任何处理:
在这里插入图片描述
上面得到的图片是Activity设置了竖向显示,然后手机屏幕0度(手机顶部在上)状态进行拍照。如果拍照过程中旋转手机,此时可以发现预览图片还是正常的但是保存的图片却发生了旋转。上一部分文章解决了预览图片的旋转角度问题,当拍照过程中旋转,预览可以很好地处理的,但拍摄生成的图片还是从原始图像传感器获取,它的方向会随手机位置的变化(特别是方向)而变化,所以需要对手机屏幕方向进行实时监听,然后对保存图片做相应操作。

手机顶部朝右拍摄:
在这里插入图片描述
利用sensor就可以实现对手机方向的判断,由于手机可能在任意角度,但是传感器返回的数值多种多样,但是最终利用传感器获取到的屏幕方向只能是0,90,180,270四种,所以需要有个阈值来确定手机方向。

判断手机旋转角度:

@Override
public void onSensorChanged(SensorEvent event) {//手机移动一段时间后静止,然后静止一段时间后进行对焦// 读取加速度传感器数值,values数组0,1,2分别对应x,y,z轴的加速度if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {int x = (int) event.values[0];int y = (int) event.values[1];int z = (int) event.values[2];}mSensorRotation = calculateSensorRotation(event.values[0],event.values[1]);
}public  int calculateSensorRotation(float x, float y) {//x是values[0]的值,X轴方向加速度,从左侧向右侧移动,values[0]为负值;从右向左移动,values[0]为正值//y是values[1]的值,Y轴方向加速度,从上到下移动,values[1]为负值;从下往上移动,values[1]为正值//不考虑Z轴上的数据,if (Math.abs(x) > 6 && Math.abs(y) < 4) {if (x > 6) {return 270;} else {return 90;}} else if (Math.abs(y) > 6 && Math.abs(x) < 4) {if (y > 6) {return 0;} else {return 180;}}return -1;
}

保存图片时做的变换:

 {final Bitmap result;if (data != null && data.length > 0) {Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);Matrix matrix = new Matrix();
//利用传感器获取当前屏幕方向对应角度 加上 开始预览是角度int rotation = (calculateCameraPreviewOrientation(Main23Activity.this) + mSensorRotation) % 360 ;if (mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK) {
//如果是后置摄像头因为没有镜面效果直接旋转特定角度matrix.setRotate(rotation);} else {
//如果是前置摄像头需要做镜面操作,然后对图片做镜面postScale(-1, 1)//因为镜面效果需要360-rotation,才是前置摄像头真正的旋转角度rotation = (360 - rotation) % 360;matrix.setRotate(rotation);matrix.postScale(-1, 1);}result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);saveBitmap(path+ "focusdemo2.jpg",result);} else {result = null;}}
}/*** 设置预览角度,setDisplayOrientation本身只能改变预览的角度* previewFrameCallback以及拍摄出来的照片是不会发生改变的,拍摄出来的照片角度依旧不正常的* 拍摄的照片需要自行处理*/
public  int calculateCameraPreviewOrientation(Activity activity) {Camera.CameraInfo info = new Camera.CameraInfo();Camera.getCameraInfo(mCameraID, info);int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();int degrees = 0;switch (rotation) {case Surface.ROTATION_0:degrees = 0;break;case Surface.ROTATION_90:degrees = 90;break;case Surface.ROTATION_180:degrees = 180;break;case Surface.ROTATION_270:degrees = 270;break;}int result;if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {result = (info.orientation + degrees) % 360;result = (360 - result) % 360;} else {result = (info.orientation - degrees + 360) % 360;}System.out.println("=======info.orientation==========="+info.orientation + degrees);mOrientation = result;return result;
}

PS:处理保存图片的旋转也有人利用图片的ExifInterface 信息,首先读取图片被旋转的角度,然后再进行相应旋转。
但测试发现很多手机获取到的图片的ExifInterface的旋转信息为0(因为只要我们对图片进行了处理,类似压缩,图片的旋转角度就会恢复到默认0度),所以还是要利用上面的方式处理。

3 利用上面的公式的实例代码

public class Main23Activity extends AppCompatActivity implements SurfaceHolder.Callback ,SensorEventListener{private static int mOrientation = 0;private static int mCameraID = Camera.CameraInfo.CAMERA_FACING_BACK;private CustomSurfaceView mSurfaceView;private SurfaceHolder mSurfaceHolder;private Camera mCamera;private boolean havePermission = false;private Button btnFocus;private Button btnTakePic;private Button btnRestar;private Button btnChange;private LinearLayout mContainer;private int useWidth;private int useHeight;private SensorManager mSensorManager;private Sensor mSensor;private int mSensorRotation = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main23);mContainer = findViewById(R.id.container);btnFocus = findViewById(R.id.focus);btnTakePic = findViewById(R.id.takepic);btnRestar = findViewById(R.id.restar);btnChange = findViewById(R.id.change);btnChange.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {switchCamera();}});btnRestar.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {/* if(mCamera != null){mCamera.startPreview();}*/// mSurfaceView.scrollBy(10,10);mContainer.animate().scaleX(0.4f).scaleY(0.7f);// mContainer.animate().rotation(50);}});btnFocus.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mCamera != null && mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK){mCamera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {if(success){Toast.makeText(Main23Activity.this,"对焦成功",Toast.LENGTH_SHORT).show();}else{}}});}}});btnTakePic.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(mCamera!= null){mCamera.takePicture(null, null, new Camera.PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {// 获取Jpeg图片,并保存在sd卡上String path = Environment.getExternalStorageDirectory().getPath()  +"/focus/";File pathDir = new File(path);if (!pathDir.exists()){pathDir.mkdir();}File pictureFile = new File(path+ "focusdemo.jpg");File pictureFile2 = new File(path+ "focusdemo2.jpg");if (pictureFile.exists()){pictureFile.delete();}if (pictureFile2.exists()){pictureFile2.delete();}try {FileOutputStream fos = new FileOutputStream(pictureFile);fos.write(data);fos.close();} catch (Exception e) {}{final Bitmap result;if (data != null && data.length > 0) {Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);Matrix matrix = new Matrix();int rotation = (calculateCameraPreviewOrientation(Main23Activity.this) + mSensorRotation) % 360 ;if (mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK) {matrix.setRotate(rotation);} else {rotation = (360 - rotation) % 360;matrix.setRotate(rotation);matrix.postScale(-1, 1);}result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);saveBitmap(path+ "focusdemo2.jpg",result);} else {result = null;}}}});}}});mSensorManager = (SensorManager) Main23Activity.this.getSystemService(Activity.SENSOR_SERVICE);mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// 加速度// Android 6.0相机动态权限检查,省略了if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)== PackageManager.PERMISSION_GRANTED &&ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {havePermission = true;init();} else {havePermission = false;ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);}}public  int calculateSensorRotation(float x, float y) {//x是values[0]的值,X轴方向加速度,从左侧向右侧移动,values[0]为负值;从右向左移动,values[0]为正值//y是values[1]的值,Y轴方向加速度,从上到下移动,values[1]为负值;从下往上移动,values[1]为正值//不考虑Z轴上的数据,if (Math.abs(x) > 6 && Math.abs(y) < 4) {if (x > 6) {return 270;} else {return 90;}} else if (Math.abs(y) > 6 && Math.abs(x) < 4) {if (y > 6) {return 0;} else {return 180;}}return -1;}@Overrideprotected void onStop() {super.onStop();mSensorManager.unregisterListener(this,mSensor);}public void releaseCamera(){if (mCamera != null) {mSurfaceHolder.removeCallback(this);mCamera.setPreviewCallback(null);mCamera.stopPreview();mCamera.lock();mCamera.release();mCamera = null;}}public void switchCamera(){if(mCameraID ==  Camera.CameraInfo.CAMERA_FACING_BACK){mCameraID =  Camera.CameraInfo.CAMERA_FACING_FRONT;}else{mCameraID =  Camera.CameraInfo.CAMERA_FACING_BACK;}try {initCamera();} catch (Exception e) {e.printStackTrace();}}public void init(){if(mSurfaceView == null){mSurfaceView = findViewById(R.id.surfaceview);mSurfaceView.setCustomEvent(new CustomSurfaceView.ONTouchEvent() {@Overridepublic void onTouchEvent(MotionEvent event) {handleFocus(event, mCamera);}});mSurfaceHolder = mSurfaceView.getHolder();mSurfaceHolder.addCallback(this);WindowManager wm = (WindowManager) Main23Activity.this.getSystemService(Context.WINDOW_SERVICE);int width = wm.getDefaultDisplay().getWidth();LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mSurfaceView.getLayoutParams();layoutParams.width = width;layoutParams.height = width*4/3;useWidth = width;useHeight = width*4/3;mSurfaceView.setLayoutParams(layoutParams);}}private void initCamera() {if (mCamera != null){releaseCamera();System.out.println("===================releaseCamera=============");}mCamera = Camera.open(mCameraID);System.out.println("===================openCamera=============");if (mCamera != null){try {mCamera.setPreviewDisplay(mSurfaceHolder);} catch (IOException e) {e.printStackTrace();}Camera.Parameters parameters = mCamera.getParameters();parameters.setRecordingHint(true);{//设置获取数据parameters.setPreviewFormat(ImageFormat.NV21);//parameters.setPreviewFormat(ImageFormat.YUV_420_888);//通过setPreviewCallback方法监听预览的回调:mCamera.setPreviewCallback(new Camera.PreviewCallback() {@Overridepublic void onPreviewFrame(byte[] bytes, Camera camera) {//这里面的Bytes的数据就是NV21格式的数据,或者YUV_420_888的数据}});}if(mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK){parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);}mCamera.setParameters(parameters);calculateCameraPreviewOrientation(this);Camera.Size tempSize = setPreviewSize(mCamera, useHeight,useWidth);{//此处可以处理,获取到tempSize,如果tempSize和设置的SurfaceView的宽高冲突,重新设置SurfaceView的宽高}setPictureSize(mCamera,  useHeight,useWidth);mCamera.setDisplayOrientation(mOrientation);int degree = calculateCameraPreviewOrientation(Main23Activity.this);mCamera.setDisplayOrientation(degree);mCamera.startPreview();}}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//当SurfaceView变化时也需要做相应操作,这里未做相应操作if (havePermission){initCamera();}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mCamera.stopPreview();}private void setPictureSize(Camera camera ,int expectWidth,int expectHeight){Camera.Parameters parameters = camera.getParameters();Point point = new Point(expectWidth, expectHeight);Camera.Size size = findProperSize(point,parameters.getSupportedPreviewSizes());parameters.setPictureSize(size.width, size.height);camera.setParameters(parameters);}private Camera.Size setPreviewSize(Camera camera, int expectWidth, int expectHeight) {Camera.Parameters parameters = camera.getParameters();Point point = new Point(expectWidth, expectHeight);Camera.Size size = findProperSize(point,parameters.getSupportedPictureSizes());parameters.setPictureSize(size.width, size.height);camera.setParameters(parameters);return size;}/*** 找出最合适的尺寸,规则如下:* 1.将尺寸按比例分组,找出比例最接近屏幕比例的尺寸组* 2.在比例最接近的尺寸组中找出最接近屏幕尺寸且大于屏幕尺寸的尺寸* 3.如果没有找到,则忽略2中第二个条件再找一遍,应该是最合适的尺寸了*/private static Camera.Size findProperSize(Point surfaceSize, List<Camera.Size> sizeList) {if (surfaceSize.x <= 0 || surfaceSize.y <= 0 || sizeList == null) {return null;}int surfaceWidth = surfaceSize.x;int surfaceHeight = surfaceSize.y;List<List<Camera.Size>> ratioListList = new ArrayList<>();for (Camera.Size size : sizeList) {addRatioList(ratioListList, size);}final float surfaceRatio = (float) surfaceWidth / surfaceHeight;List<Camera.Size> bestRatioList = null;float ratioDiff = Float.MAX_VALUE;for (List<Camera.Size> ratioList : ratioListList) {float ratio = (float) ratioList.get(0).width / ratioList.get(0).height;float newRatioDiff = Math.abs(ratio - surfaceRatio);if (newRatioDiff < ratioDiff) {bestRatioList = ratioList;ratioDiff = newRatioDiff;}}Camera.Size bestSize = null;int diff = Integer.MAX_VALUE;assert bestRatioList != null;for (Camera.Size size : bestRatioList) {int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);if (size.height >= surfaceHeight && newDiff < diff) {bestSize = size;diff = newDiff;}}if (bestSize != null) {return bestSize;}diff = Integer.MAX_VALUE;for (Camera.Size size : bestRatioList) {int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);if (newDiff < diff) {bestSize = size;diff = newDiff;}}return bestSize;}private static void addRatioList(List<List<Camera.Size>> ratioListList, Camera.Size size) {float ratio = (float) size.width / size.height;for (List<Camera.Size> ratioList : ratioListList) {float mine = (float) ratioList.get(0).width / ratioList.get(0).height;if (ratio == mine) {ratioList.add(size);return;}}List<Camera.Size> ratioList = new ArrayList<>();ratioList.add(size);ratioListList.add(ratioList);}/*** 排序* @param list*/private static void sortList(List<Camera.Size> list) {Collections.sort(list, new Comparator<Camera.Size>() {@Overridepublic int compare(Camera.Size pre, Camera.Size after) {if (pre.width > after.width) {return 1;} else if (pre.width < after.width) {return -1;}return 0;}});}/*** 设置预览角度,setDisplayOrientation本身只能改变预览的角度* previewFrameCallback以及拍摄出来的照片是不会发生改变的,拍摄出来的照片角度依旧不正常的* 拍摄的照片需要自行处理*/public  int calculateCameraPreviewOrientation(Activity activity) {Camera.CameraInfo info = new Camera.CameraInfo();Camera.getCameraInfo(mCameraID, info);int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();int degrees = 0;switch (rotation) {case Surface.ROTATION_0:degrees = 0;break;case Surface.ROTATION_90:degrees = 90;break;case Surface.ROTATION_180:degrees = 180;break;case Surface.ROTATION_270:degrees = 270;break;}int result;if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {result = (info.orientation + degrees) % 360;result = (360 - result) % 360;} else {result = (info.orientation - degrees + 360) % 360;}System.out.println("=======info.orientation==========="+info.orientation + degrees);mOrientation = result;return result;}@Overrideprotected void onResume() {super.onResume();mSensorManager.registerListener(this, mSensor,SensorManager.SENSOR_DELAY_NORMAL);if (havePermission && mCamera != null)mCamera.startPreview();}@Overrideprotected void onPause() {super.onPause();if (havePermission && mCamera != null)mCamera.stopPreview();}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode) {// 相机权限case 100:havePermission = true;init();break;}}/*** 转换对焦区域* 范围(-1000, -1000, 1000, 1000)*/private  Rect calculateTapArea(float x, float y,  int width, int height, float coefficient) {float focusAreaSize = 200;int areaSize = (int) (focusAreaSize * coefficient);int surfaceWidth = width;int surfaceHeight = height;int centerX = (int) (x / surfaceHeight * 2000 - 1000);int centerY = (int) (y / surfaceWidth * 2000 - 1000);int left = clamp(centerX - (areaSize / 2), -1000, 1000);int top = clamp(centerY - (areaSize / 2), -1000, 1000);int right = clamp(left + areaSize, -1000, 1000);int bottom = clamp(top + areaSize, -1000, 1000);return new Rect(left, top, right, bottom);}//不大于最大值,不小于最小值private  int clamp(int x, int min, int max) {if (x > max) {return max;}if (x < min) {return min;}return x;}private  void handleFocus(MotionEvent event, Camera camera) {int viewWidth = useWidth;int viewHeight = useHeight;Rect focusRect = calculateTapArea(event.getX(), event.getY(),  viewWidth, viewHeight,1.0f);//一定要首先取消camera.cancelAutoFocus();Camera.Parameters params = camera.getParameters();if (params.getMaxNumFocusAreas() > 0) {List<Camera.Area> focusAreas = new ArrayList<>();focusAreas.add(new Camera.Area(focusRect, 800));params.setFocusAreas(focusAreas);} else {//focus areas not supported}//首先保存原来的对焦模式,然后设置为macro,对焦回调后设置为保存的对焦模式final String currentFocusMode = params.getFocusMode();params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);camera.setParameters(params);camera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {//回调后 还原模式Camera.Parameters params = camera.getParameters();params.setFocusMode(currentFocusMode);camera.setParameters(params);if(success){Toast.makeText(Main23Activity.this,"对焦区域对焦成功",Toast.LENGTH_SHORT).show();}}});}@Overridepublic void onSensorChanged(SensorEvent event) {//手机移动一段时间后静止,然后静止一段时间后进行对焦// 读取加速度传感器数值,values数组0,1,2分别对应x,y,z轴的加速度if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {int x = (int) event.values[0];int y = (int) event.values[1];int z = (int) event.values[2];}mSensorRotation = calculateSensorRotation(event.values[0],event.values[1]);}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}public  void saveBitmap(String filePath ,Bitmap mBitmap) {File f = new File(filePath);FileOutputStream fOut = null;try {fOut = new FileOutputStream(f);} catch (FileNotFoundException e) {e.printStackTrace();}mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);try {fOut.flush();} catch (IOException e) {e.printStackTrace();}try {fOut.close();} catch (IOException e) {e.printStackTrace();}}
}

后置摄像头拍摄的原图和 处理后的图
在这里插入图片描述
在这里插入图片描述
前置摄像头拍摄的原图和处理后的图:
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

国仁网络资讯:短视频拍摄如何上热门;掌握这8大拍摄运镜手法即可。

抖音视频拍摄基本分为两种:一种是随手拍,记录生活精彩时刻;一种是情景拍摄,一般整个视频都是设计好的。 随手一拍很轻松,但未免没有那么多偶然的精彩瞬间,此时就需要我们自己去编排了,编排出一条精彩视频,拍摄技巧是必须的。 不同拍摄手法所表达的意思也各不相同。那么…

定位教程4-固定相机之先抓后拍

相机固定,机器人吸住一个物料,拍照,然后将电池放到其他位置,这也是一个经典的应用场景。 相机在上和在下都是一样的标定方法,只是需要注意下角度取反而已,大家在实际使用的时候自己测试一下就知道角度取反问题. 其标定方法和之前的固定相机-先拍再抓一样,都是先9点标定,再5点标…

Android 使用CameraX实现预览/拍照/录制视频/图片分析/对焦/缩放/切换摄像头等操作

1. CameraX架构 看官方文档 CameraX架构 有如下这一段话 使用CameraX&#xff0c;借助名为"用例"的抽象概念与设备的相机进行交互。 预览 : 接受用于显示预览的Surface&#xff0c;例如PreviewView图片分析 : 为分析 (例如机器学习) 提供CPU可访问的缓冲区图片拍摄…

Android 使用Camera2 实现拍照录像的功能

职场小白迷上优美句子: 还是电影 《无问西东》中的台词&#xff0c;这句有点感人&#xff1a; 沈光耀的妈妈对沈光耀说&#xff1a;"当初你离家千里&#xff0c;来到这个地方读书&#xff0c;你父亲和我都没有反对过&#xff0c;因为&#xff0c;是我们想你&#xff0c;…

天猫精灵Aligenie对接记录(三)

原文 https://www.jksxit.com/essay/42 服务端需要开发API接口处理阿里精灵发送的智能设备控制指令&#xff0c;并遵循AliGenie智能家居接入协议。 &#xff08;1&#xff09;同步模式

天猫精灵智能设备对接(4)

apache2php7.0 web服务器的构建 我个人使用的服务器是腾讯云&#xff0c;系统是ubuntu16.04&#xff0c;如果大家要是没有云服务器可以采用花生壳内网穿透的方法&#xff0c;还能得到一个只能在花生壳免费部署的域名&#xff0c;但是也要花6块钱&#xff0c;看需求了&#xff0…

天猫精灵智能家居对接,及天猫iot官网配置图文讲解(二)

天猫精灵智能家居对接,及天猫iot官网配置图文讲解&#xff08;二&#xff09; 2、天猫精灵设备对接 2-1、介绍 ​ 上一章里&#xff0c;我已经讲了天猫精灵的技能配置&#xff0c;设备创建&#xff0c;登录验证这三个部分做了&#xff0c;此次篇文章就讲之后的设备查询&…

天猫精灵智能设备对接(5) SSL https设置

至于什么是SSL证书具体有什么用&#xff0c;想了解的自行百度吧&#xff0c;再不行谷歌&#xff0c;百度出来的东西比我这个外行巴拉巴拉说半天来的痛快&#xff0c;本来腾讯云是送免费一年的SSL证书的&#xff0c;但是我赶得非常不巧&#xff0c;在我做测试那几天腾讯的ssl服务…

天猫精灵智能设备对接(8) 开发者网关地址

洋洋洒洒六七千字已经搭进去了&#xff0c;终于把服务器篇写的差不多了&#xff0c;当然小狂不是专业的写手&#xff0c;有些东西写的凑合看吧&#xff0c;只是说明过程&#xff0c;并不修饰言辞&#xff0c;看的舒服就点个赞&#xff0c;不舒服就当学东西了吧。这篇文章我们将…

springboot项目接入天猫精灵

springboot项目接入天猫精灵 最近工作需要使用到天猫精灵的语音功能&#xff0c;大体是通过呼叫对应的“调用词”实现携带参数&#xff0c;然后调用我项目中的接口&#xff0c;以实现对应的业务。所以在此简单的记录下使用过程 实际上&#xff1a;天猫精灵的官方文档记录的也很…

天猫精灵智能家居对接,及天猫iot官网配置图文讲解(一)

天猫智能家居对接 1-1、介绍 这篇文章主要是介绍&#xff0c;如何使用java对接天猫精灵智能家居提供的api。这么做的好处就是能让用户通过天猫精灵发送命令到我们的服务器&#xff0c;然后操控设备执行一系列的命令&#xff0c;当然这些功能呢都是天猫精灵官方制定的协议&…

java对接天猫精灵语音助手实现对公司其下的智能设备进行控制(附上源码)

java对接天猫精灵语音助手实现对公司其下的智能设备进行控制 前言当初刚来广州 公司上一任java已经离职半年 &#xff0c;项目已经跑不动了&#xff0c;才招人的&#xff0c;所以我获得的是一个连跑都跑不起来的项目源码并且对项目一无所知&#xff0c;一年前网上并没有对接天…

天猫精灵智能设备对接(7) OAuth2.0

在开始之前先放两篇参考&#xff0c;一篇英文http://bshaffer.github.io/oauth2-server-php-docs/cookbook/&#xff0c;一篇中文https://www.cnblogs.com/endv/p/7868549.html&#xff0c;中文博客里的内容基本上是把英文官方文档翻译一遍。到这里如果你不知道OAuth2.0是啥可以…

天猫精灵对接2(OAuth 搭建)

根据 接入方式及流程 中的说明&#xff0c;可知&#xff0c;搭建过程中&#xff0c;我们需要自己整一个 OAuth 的授权平台&#xff0c;具体说明可以参考蟋蟀大哥的文章 ASP.NET WebApi OWIN 实现 OAuth 2.0 &#xff0c;我的实际代码也是基于文章给出的源码修改的。 第一步 认…

天猫精灵对接智能设备

why to do&#xff1a;   我之前一直很喜欢智能家居&#xff0c;可惜的是现在市场上成品的智能家居实在是太贵了&#xff0c;屌丝的码农是在背不起每月高额的房贷和装修费用的基础上&#xff0c;再买成品的智能设备&#xff08;像某米那样一个智能开关&#xff0c;竟然卖那么…

从零玩转系列之SpringBoot3-核心原理

一、简介 1.前置知识 ● Java17 ● Spring、SpringMVC、MyBatis ● Maven、IDEA 2.环境要求 环境&工具版本(or later)SpringBoot3.1.xIDEA2023.xJava17Maven3.5Tomcat10.0Servlet5.0GraalVM Community22.3Native Build Tools0.9.19 二、SpringBoot3-核心原理 1.事件和监听器…

SpringBoot3【⑤ 核心原理】

1. 事件和监听器 1. 生命周期监听 场景&#xff1a;监听应用的生命周期 1. 监听器-SpringApplicationRunListener 自定义SpringApplicationRunListener来监听事件&#xff1b; 1.1. 编写SpringApplicationRunListener 这个接口的实现类 1.2. 在 META-INF/spring.factories …

开发必备,开源 or 免费的 AI 编程助手

AI 大模型的火热&#xff0c;让开发圈近来如虎添翼&#xff0c;各种各样基于 AI 技术的开发者工具和新范式不断涌现&#xff0c;尤其是 Github 和 OpenAI 共同推出的 Copilot X &#xff0c;更是一骑绝尘。本文推荐一些开源 or 免费的 AI 编程工具&#xff0c;不妨试着用起来。…

超过5000人的2年研究表明,这一活动破坏你的身心健康

Tips 原文作者&#xff1a;Minda Zetlin 原文出处&#xff1a;A 2-Year Study of More Than 5,000 People Shows This 1 Activity Destroys Your Emotional and Physical Health 阅读时&#xff0c;把文中的 Fackbook 换成微信。 国外主要用 Facebook&#xff1b; 国内主要是微…

申请阿里云服务器并搭建公网可支持数据上传下载的HTTP服务器

1. 前言 拥有一台自己的云服务器可以做很多事情。阿里云服务器毫无疑问是国内最好的。 阿里云服务器可以用于各种互联网应用的搭建和运行&#xff0c;提供稳定、高性能的服务。 阿里云服务器的用途&#xff0c;包括但不限于以下几个方面&#xff1a; 网站托管&#xff1a;可以将…