Android图片识别应用详解

作者:迪小子 时间:2022-01-13 15:37:31 

最近由于参加一个小小的创意比赛,用安卓做了一个小小的图片识别应用,主要是通过拍照识别图片中的菜品,还有对象位置查找的东西。之前没有做过安卓,都是拼拼凑凑多篇博客完成的,我也把这个项目的一些过程分享一下。先把功能贴一下,其实就是点击拍照,将照片保存在本地,然后识别出图中的菜品,然后用红色方框圈出来,并显示菜品种类。采用最新的Camera2的API,的确是比Camera好用。

Android图片识别应用详解

Android图片识别应用详解

1、界面

我采用了一个SurfaceView用来显示摄像头的预览画面,重写了一个SurfaceView来进行红色方框还有菜品名字的绘制。图片是一个ImageVIew,相当于拍照按钮的功能。


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="com.hd.hd.MainActivity">

<SurfaceView
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:id="@+id/surfaceView"
   android:layout_centerHorizontal="true"
   android:layout_centerVertical="true"/>

<com.hd.hd.SVDraw
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:id="@+id/mySurfaceView"
   android:layout_centerHorizontal="true"
   android:layout_centerVertical="true"/>
 <LinearLayout
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:orientation="horizontal"
   android:layout_alignParentBottom="true"
   >
 <ImageView
   android:id="@+id/btngal"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:gravity="center_horizontal"
   android:layout_alignParentBottom="true"
   android:src="@drawable/s_8"
   android:layout_alignParentLeft="true"

/>

<TextView
   android:id="@+id/textview"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center"
   android:textColor="@color/white"
   android:textSize="20dp"
   android:layout_toRightOf="@id/btngal"
   android:layout_alignParentTop="true"

/>
 </LinearLayout>

</RelativeLayout>

SVDraw,,继承SurfaceView,用于绘制红色方框


package com.hd.hd;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.List;

/*定义一个画矩形框的类*/
public class SVDraw extends SurfaceView implements SurfaceHolder.Callback{

protected SurfaceHolder sh;
 private int mWidth;
 private int mHeight;
 public SVDraw(Context context, AttributeSet attrs) {
   super(context, attrs);
   // TODO Auto-generated constructor stub
   sh = getHolder();
   sh.addCallback(this);
   sh.setFormat(PixelFormat.TRANSPARENT);
   setZOrderOnTop(true);
 }

public void surfaceChanged(SurfaceHolder arg0, int arg1, int w, int h) {
   // TODO Auto-generated method stub

}

public void surfaceCreated(SurfaceHolder sh) {
   // TODO Auto-generated method stub

mWidth = this.getWidth();
   mHeight = this.getHeight();

}

public void surfaceDestroyed(SurfaceHolder arg0) {
   // TODO Auto-generated method stub

}
 void clearDraw()
 {
   Canvas canvas = sh.lockCanvas();
   canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
   sh.unlockCanvasAndPost(canvas);
 }

public void drawLine(List<String> keys, List<String> values)
 {
   Canvas canvas = sh.lockCanvas();
   canvas.drawColor(Color.TRANSPARENT);
   Paint p = new Paint();
   p.setAntiAlias(true);
   p.setColor(Color.RED);
   p.setStrokeWidth(6);
   p.setStyle(Paint.Style.STROKE);//设置空心
   p.setTextSize(160);

Paint p1 = new Paint();
   p1.setColor(Color.WHITE);
   p1.setTextSize(80);

for(int i = 0;i < keys.size();i++){
     String v = values.get(i);
     v = v.replace("[","");
     v = v.replace("]","");
     String[] value = v.split(",");
     canvas.drawRect(mWidth - Integer.parseInt(value[3]), Integer.parseInt(value[0]), mHeight - Integer.parseInt(value[1]), Integer.parseInt(value[2]), p);// 正方形
     canvas.drawText(keys.get(i), mWidth - Integer.parseInt(value[3]), Integer.parseInt(value[0])-5, p1);

}
   sh.unlockCanvasAndPost(canvas);

}

}

2、上传图片到服务器,我没有采用JSon的格式,而是直接将图片文件转化为字节数组,发送给服务器。使用一个异步任务,完成后,直接在onPostExcute()方法里绘制。


package com.hd.hd;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

/**
* Created by asus on 2017/8/13.
*/
public class MyTask extends AsyncTask<String, Integer, String> {

private static String TAG = "MainActivity";
 private File file; //需要发送的图片
 private String result_content; //服务器返回的结果
 private SVDraw surfaceView;   //需要绘制的surfaceview
 private TextView tv;    //显示文字
 private static final int TIME_OUT = 10 * 1000; // 超时时间
 private static final String CHARSET = "utf-8"; // 设置编码

public MyTask(File f,SVDraw s,TextView tv){
   this.file = f;
   this.surfaceView = s;
   this.tv = tv;
 }

@Override
 protected void onPreExecute() {

}

//doInBackground方法内部执行后台任务,不可在此方法内修改UI
 @Override
 protected String doInBackground(String... params) {
   //调用文件上传方法
   result_content = uploadFile(file,"http://13.76.211.62/");

return null;
 }

//onProgressUpdate方法用于更新进度信息
 @Override
 protected void onProgressUpdate(Integer... progresses) {

}

//onPostExecute方法用于在执行完后台任务后更新UI,显示结果
 @Override
 protected void onPostExecute(String result) {
   //由于返回的是一个python的字典形式的字符串,用json来解析
   JSONObject obj = null;
   List<String> keys = new ArrayList<String>();
   List<String> values = new ArrayList<String>();
   try {
     obj = new JSONObject(result_content);
     //json对象的Key的迭代器,用来遍历json
     Iterator it = obj.keys();
     while (it.hasNext()) {
       String key = (String) it.next();
       String value = obj.getString(key);
       keys.add(key);
       values.add(value);
     }
   } catch (JSONException e) {
     e.printStackTrace();
   }
   //绘制图形
   surfaceView.clearDraw();
   surfaceView.drawLine(keys,values);
   tv.setText("搭配很赞哦");

}

//onCancelled方法用于在取消执行中的任务时更改UI
 @Override
 protected void onCancelled() {

}

/**
  * 上传图片文件到服务器
  * @param file
  * @param RequestURL
  * @return
  */
 public static String uploadFile(File file, String RequestURL) {
   String result = null;
   String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
   String PREFIX = "--", LINE_END = "\r\n";
   String CONTENT_TYPE = "multipart/form-data"; // 内容类型

try {
     //创建URL连接,指明连接地址
     URL url = new URL(RequestURL);
     HttpURLConnection conn = (HttpURLConnection) url.openConnection();

//设置http请求的属性为POST
     conn.setReadTimeout(TIME_OUT);
     conn.setConnectTimeout(TIME_OUT);
     conn.setDoInput(true); // 允许输入流
     conn.setDoOutput(true); // 允许输出流
     conn.setUseCaches(false); // 不允许使用缓存
     conn.setRequestMethod("POST"); // 请求方式
     conn.setRequestProperty("Charset", CHARSET); // 设置编码
     conn.setRequestProperty("connection", "keep-alive");
     conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

if (file != null) {
       /**
        * 当文件不为空,把文件包装并且上传
        */
       Log.i(TAG,"upload");
       DataOutputStream dos = new DataOutputStream(conn.getOutputStream());

Log.e(TAG,"not null");
       /**
        * 这里重点注意: name里面的值为服务端需要key 只有这个key 才可以得到对应的文件
        * filename是文件的名字,包含后缀名的 比如:abc.png
        */

InputStream is = new FileInputStream(file);
       byte[] bytes = new byte[1024];
       int len;
       while ((len = is.read(bytes)) != -1) {
         dos.write(bytes, 0, len);
       }
       is.close();
       dos.flush();
       Log.e(TAG,"sent");

/**
        * 获取响应码 200=成功 当响应成功,获取响应的流
        */
       int res = conn.getResponseCode();
       Log.e(TAG, "response code:" + res);

Log.e(TAG, "request success");
       InputStream input = conn.getInputStream();

StringBuffer sb1 = new StringBuffer();
       int ss;
       while ((ss = input.read()) != -1) {
         sb1.append((char) ss);
       }
       result = sb1.toString();
       Log.e(TAG, "result : " + result);

}
   } catch (MalformedURLException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   }
   return result;
 }
}

3、初始化界面、照相机,使得照相机能够实时预览,并实现拍照功能


package com.hd.hd;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity{

private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
 private String TAG = "MainActivity";

///为了使照片竖直显示
 static {
   ORIENTATIONS.append(Surface.ROTATION_0, 90);
   ORIENTATIONS.append(Surface.ROTATION_90, 0);
   ORIENTATIONS.append(Surface.ROTATION_180, 270);
   ORIENTATIONS.append(Surface.ROTATION_270, 180);
 }

private SurfaceView mSurfaceView;
 private SurfaceHolder mSurfaceHolder;
 private CameraManager mCameraManager;//摄像头管理器
 private Handler childHandler, mainHandler;
 private String mCameraID;//摄像头Id 0 为后 1 为前
 private ImageReader mImageReader;
 private CameraCaptureSession mCameraCaptureSession;
 private CameraDevice mCameraDevice;
 private SVDraw hSurfaceView;
 private MyTask myTask;
 private CaptureRequest.Builder captureRequestBuilder;
 private TextView tv;
 private final int DRAW_ORDER = 10;
 private Handler myHandler;
 private ImageView imageView;
 private String dir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Healthy_d/";

@Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

//此步骤非常重要,安卓不用自动帮你创建文件夹来保存拍照的照片
   File dirFirstFolder = new File(dir);//方法二:通过变量文件来获取需要创建的文件夹名字
   if(!dirFirstFolder.exists())
   { //如果该文件夹不存在,则进行创建
     dirFirstFolder.mkdirs();//创建文件夹

}

//Android 6后有些敏感的权限不能随意分配,必须向用户发送请求赋予
   //这里请求用户赋予拍照,读写内存卡,连接网络的权限,其实只有拍照权限需要向用户请求,但是有备无患吧
   if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
     Log.e(TAG,ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)+"");
     ActivityCompat.requestPermissions(MainActivity.this,
         new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
         43);
   }

if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
     ActivityCompat.requestPermissions(MainActivity.this,
         new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
         44);
   }

if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
     ActivityCompat.requestPermissions(MainActivity.this,
         new String[]{Manifest.permission.INTERNET},
         45);
   }

initVIew();

}

/**
  * 初始化视图
  */
 private void initVIew() {
   HandlerThread handlerThread = new HandlerThread("Camera2");
   handlerThread.start();
   childHandler = new Handler(handlerThread.getLooper());
   //mSurfaceView
   mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
   hSurfaceView = (SVDraw) findViewById(R.id.mySurfaceView);
   imageView = (ImageView) findViewById(R.id.btngal);
   tv = (TextView)findViewById(R.id.textview);

//设置ImageView * ,点击图片,拍照
   imageView.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
       Toast.makeText(MainActivity.this, "正在识别,请稍等", Toast.LENGTH_LONG).show();
       if (mCameraDevice == null) return;
       // 创建拍照需要的CaptureRequest.Builder
       try {
         captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
         // 将imageReader的surface作为CaptureRequest.Builder的目标
         captureRequestBuilder.addTarget(mImageReader.getSurface());
         // 自动对焦
         captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
         // 自动曝光
         captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
         // 获取手机方向
         int rotation = getWindowManager().getDefaultDisplay().getRotation();
         // 根据设备方向计算设置照片的方向
         captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
         //拍照
         CaptureRequest mCaptureRequest = captureRequestBuilder.build();
         mCameraCaptureSession.capture(mCaptureRequest, mSessionCaptureCallback, childHandler);

} catch (CameraAccessException e) {
         e.printStackTrace();
       }
     }
   });

mSurfaceHolder = mSurfaceView.getHolder();
   mSurfaceHolder.setKeepScreenOn(true);
   // mSurfaceView添加回调
   mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
     @Override
     public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建
       // 初始化Camera
       initCamera2();
     }

@Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     }

@Override
     public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁
       // 释放Camera资源
       if (null != mCameraDevice) {
         mCameraDevice.close();
         mCameraDevice = null;
       }
     }
   });
 }

//拍照时,可以对照片进行操作,这里可以不写,因为我没对其进行操作
 private CameraCaptureSession.CaptureCallback mSessionCaptureCallback =
     new CameraCaptureSession.CaptureCallback() {

@Override
       public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
                       TotalCaptureResult result) {}

@Override
       public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
                       CaptureResult partialResult){}};

/**
  * 初始化Camera2
  */
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 private void initCamera2() {
   HandlerThread handlerThread = new HandlerThread("Camera2");
   handlerThread.start();
   childHandler = new Handler(handlerThread.getLooper());
   mainHandler = new Handler(getMainLooper());
   mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后摄像头
   mImageReader = ImageReader.newInstance(mSurfaceView.getWidth(), mSurfaceView.getHeight(), ImageFormat.JPEG,1);
   mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地
     @Override
     public void onImageAvailable(ImageReader reader) {

Image image = reader.acquireNextImage();
       ByteBuffer buffer = image.getPlanes()[0].getBuffer();
       byte[] bytes = new byte[buffer.remaining()];
       buffer.get(bytes);//由缓冲区存入字节数组
       Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
       String fileName = "test";
       File file = new File(dir + fileName + ".jpg");
       String state = Environment.getExternalStorageState();
       //如果状态不是mounted,无法读写
       if (!state.equals(Environment.MEDIA_MOUNTED)) {
         return;
       }

FileOutputStream out = null;
       try {
         out = new FileOutputStream(file);
         bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);//转化为jpeg图片
         out.flush();
         out.close();
         image.close();//一定要记得关,否则会出现程序崩溃
       } catch (FileNotFoundException e) {
         e.printStackTrace();
       } catch (IOException e) {
         e.printStackTrace();
       }
       new MyTask(file,hSurfaceView,tv).execute();

}
   }, mainHandler);
   //获取摄像头管理
   mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
   try {
     if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
       ActivityCompat.requestPermissions(this,
           new String[]{Manifest.permission.CAMERA},
           42);
     }
     //打开摄像头
     mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
   } catch (CameraAccessException e) {
     e.printStackTrace();
   }
 }

/**
  * 当发送权限请求用户响应时,回调该函数
  * @param requestCode
  * @param permissions
  * @param grantResults
  */
 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
   if (requestCode == 42) {

Toast.makeText(this, "CAMERA PERMISSION GRANTED", Toast.LENGTH_SHORT).show();
     if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
       //申请成功,可以拍照
       Log.i(TAG,"apply camera success");
       CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
       try {
         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
           Toast.makeText(this, "CAMERA PERMISSION DENIED", Toast.LENGTH_SHORT).show();
         }
         mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
       } catch (CameraAccessException e) {
         e.printStackTrace();
       }
     } else {
       Toast.makeText(this, "CAMERA PERMISSION DENIED", Toast.LENGTH_SHORT).show();
     }
     return;
   }
   super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 }

/**
  * 摄像头创建监听
  */
 private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
   @Override
   public void onOpened(CameraDevice camera) {//打开摄像头
     mCameraDevice = camera;
     //开启预览
     takePreview();

}

@Override
   public void onDisconnected(CameraDevice camera) {//关闭摄像头
     if (null != mCameraDevice) {
       mCameraDevice.close();
       mCameraDevice = null;
     }
   }

@Override
   public void onError(CameraDevice camera, int error) {//发生错误
     Toast.makeText(MainActivity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();
   }
 };

/**
  * 开始预览
  */
 private void takePreview() {
   try {

// 创建预览需要的CaptureRequest.Builder
     final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
     // 将SurfaceView的surface作为CaptureRequest.Builder的目标
     previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
//      previewRequestBuilder.addTarget(mImageReader.getSurface());
     // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
     mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③
     {
       @Override
       public void onConfigured(CameraCaptureSession cameraCaptureSession) {
         if (null == mCameraDevice) return;
         // 当摄像头已经准备好时,开始显示预览
         mCameraCaptureSession = cameraCaptureSession;
         try {
           // 自动对焦
           previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
           // 打开闪光灯
           previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
           // 显示预览
           CaptureRequest previewRequest = previewRequestBuilder.build();
           mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);
         } catch (CameraAccessException e) {
           e.printStackTrace();
         }
       }

@Override
       public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
         Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show();
       }
     }, childHandler);
   } catch (CameraAccessException e) {
     e.printStackTrace();
   }
 }

}

4、AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.hd.hd">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.CAMERA"/>
 <uses-feature android:name="android.hardware.camera2.full" />
 <uses-permission android:name="android.permission.INTERNET" />

<application
   android:allowBackup="true"
   android:icon="@mipmap/ic_launcher"
   android:label="@string/app_name"
   android:supportsRtl="true"
   android:theme="@style/AppTheme">
   <activity android:name=".MainActivity">
     <intent-filter>
       <action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
   </activity>
 </application>

</manifest>

今天代码先分享到那么多,明天给大家分享一下Camera2的架构。有不懂的可以评论,一起讨论。

来源:http://blog.csdn.net/u011476718/article/details/77171225

标签:Android,图片识别
0
投稿

猜你喜欢

  • Java实现的微信图片处理工具类【裁剪,合并,等比例缩放等】

    2022-03-26 11:32:59
  • c#生成高清缩略图的二个示例分享

    2023-04-09 23:21:46
  • Java8新特性之默认方法和静态方法

    2021-08-29 13:34:26
  • springboot 多数据源的实现(最简单的整合方式)

    2022-08-20 02:30:11
  • Java ConcurrentHashMap用法案例详解

    2023-08-30 02:01:41
  • Android中点击按钮启动另一个Activity及Activity之间传值问题

    2023-09-01 13:08:20
  • C#控制台实现飞行棋小游戏

    2023-04-27 05:13:43
  • Unity之绕轴进行旋转的操作

    2021-11-14 17:53:10
  • C#使用后台线程BackgroundWorker处理任务的总结

    2023-12-08 10:28:19
  • HashSet如何保证元素不重复(面试必问)

    2023-04-12 02:16:24
  • c# 控件截图的简单实例

    2022-01-21 16:43:19
  • SpringBoot统一功能处理的方式详解

    2021-08-17 10:46:07
  • Java编程中的4种代码块详解

    2022-01-04 03:10:20
  • Spring Boot集成Ehcache缓存解决方式

    2023-05-13 08:27:27
  • Flutter本地存储之基本的键值对存储详解

    2023-08-18 03:52:35
  • springboot项目启动慢的问题排查方式

    2023-06-19 18:58:40
  • java compare compareTo方法区别详解

    2022-06-26 08:13:55
  • C++ 中String 替换指定字符串的实例详解

    2021-06-05 19:08:23
  • C# 对MongoDB 进行增删改查的简单操作实例

    2022-03-07 14:10:26
  • 浅析java中的取整(/)和求余(%)

    2023-04-30 23:46:23
  • asp之家 软件编程 m.aspxhome.com