本篇文章为大家展示了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>
上述内容就是Android中怎么实现图片识别功能,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。