Android(安卓)apps 拍立知-功能实现2(相机/选择相册及图像识别调用)
上一篇实现了语音播放的功能,接下来就开始实现相机及图像识别功能调用。
首先,画一个大致的流程图方便理解:
以下是对相机/选择相册进行实现。
(大家可以参考其它Android调用相机/选择相册的教程,不一定使用我的代码,只要获取好地址就可以。)
(主要步骤是启动相机-调用相机-保存图片(地址一定要保存好),在相册选择图片也亦然,知道步骤后实现就比较简单)
Button takePhoto = findViewById(R.id.camerabutton);//拍照的按钮takePhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CAMERA},24); } File outputImage = new File(getExternalCacheDir(), "output_image.jpg"); try { if (outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } try { if (outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } //判断版本号 if (Build.VERSION.SDK_INT < 24) { imageUri = Uri.fromFile(outputImage); } else { imageUri = FileProvider.getUriForFile(MainActivity.this, "com.MapScanner.MapScanner", outputImage); } // 启动相机程序 Log.d("TAG", "---------b"+outputImage.getAbsolutePath()); Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");; intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO); } });
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d("TAG", "---------d----"+requestCode+"----"+resultCode+"----"+data); //成功的时候requestCode:1 resultCode:1 失败的时候requestCode:1 resultCode:0 switch (requestCode) { case 1: try {// 将拍摄的照片显示出来 Date date=new Date(System.currentTimeMillis()); SimpleDateFormat dateFormat=new SimpleDateFormat("yyyyMMddHHmmss"); String fileName=dateFormat.format(date)+".jpeg"; String name=Environment.getExternalStorageDirectory().getPath()+"/DCIM/Camera/"+fileName ; File file = new File(name); FileOutputStream out; Matrix matrix = new Matrix(); matrix.setRotate(90); Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), matrix, true); picture.setImageBitmap(bitmap); try{ out = new FileOutputStream(file); // 格式为 JPEG,照相机拍出的图片为JPEG格式的,PNG格式的不能显示在相册中 if(bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) { out.flush(); out.close(); MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), name, null); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } path=name; Log.d("TAG", "imagePath====== " + imageUri); } catch (Exception e) { e.printStackTrace(); } break; case 2: // 判断手机系统版本号 if (Build.VERSION.SDK_INT >= 19) { // 4.4及以上系统使用这个方法处理图片 handleImageOnKitKat(data); } else { // 4.4以下系统使用这个方法处理图片 handleImageBeforeKitKat(data); } break; default: break; } }
对于选取相册中的图片。
Button choosePicture = findViewById(R.id.picturebutton); choosePicture.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2); } Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent, CHOOSE_PHOTO); } });
HandleImage的处理
@TargetApi(19) private void handleImageOnKitKat(Intent data) { String imagePath = null; Uri uri = data.getData(); Log.d("TAG", "handleImageOnKitKat: uri is " + uri); if (DocumentsContract.isDocumentUri(this, uri)) { // 如果是document类型的Uri,则通过document id处理 String docId = DocumentsContract.getDocumentId(uri); if("com.android.providers.media.documents".equals(uri.getAuthority())) { String id = docId.split(":")[1]; // 解析出数字格式的id String selection = MediaStore.Images.Media._ID + "=" + id; imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); imagePath = getImagePath(contentUri, null); } } else if ("content".equalsIgnoreCase(uri.getScheme())) { // 如果是content类型的Uri,则使用普通方式处理 imagePath = getImagePath(uri, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) { // 如果是file类型的Uri,直接获取图片路径即可 imagePath = uri.getPath(); } displayImage(imagePath); // 根据图片路径显示图片 } private void handleImageBeforeKitKat(Intent data) { Uri uri = data.getData(); String imagePath = getImagePath(uri, null); displayImage(imagePath); } private String getImagePath(Uri uri, String selection) { String path = null; // 通过Uri和selection来获取真实的图片路径 Cursor cursor = getContentResolver().query(uri, null, selection, null, null); if (cursor != null) { if (cursor.moveToFirst()) { path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } cursor.close(); } return path; } private void displayImage(String imagePath) { path=imagePath; if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath); picture.setImageBitmap(bitmap); } else { Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show(); } }
(权限的声明在上一篇已经设置好,这里就不重复设置了)
相机设置完毕后,就是实现图像识别调用的功能,因为我们实现的是四个识别,其实界面都是一样,只是方法调用里面只需要修改,所以我们在跳转页面的时候,给它一个标志位,只需要修改调用的内容和把处理返回来数据内容作修改即可。
看图的话直观一点:(两个不同识别是使用同一个界面,只是调用的接口不一样,其他功能可以复用)
上代码:
首先是ViewActivity下,跳转到MainActivity回传选择的是哪一个识别。
(只截取了ViewActivity跳转部分代码,ViewActivity在介绍界面的时候再做细讲。)
public void myClick(View v) { //btncommon btnanimal btnplant btnplace String name=""; switch(v.getId()) { case R.id.btncommon: name="btncommon"; break; case R.id.btnanimal: name="btnanimal"; break; case R.id.btnplant: name="btnplant"; break; case R.id.btnplace: name="btnplace"; break; }Intent i = new Intent(ViewActivity.this, MainActivity.class); i.putExtra("myChoose",name); startActivity(i);}
跳转到MainActivity中获取name。(这里是把标题修改了)
Intent i=getIntent();//页面选择 final String youChoose=i.getStringExtra("myChoose"); switch (youChoose){ case "btncommon": setTitle("通用识别"); break; case "btnanimal": setTitle("动物识别"); break; case "btnplant": setTitle("植物识别"); break; case "btnplace": setTitle("地标识别"); break; }
接下来截取通用识别代码部分讲解。
当我们把图片选择好/调用拍照后,点击识别按钮,就开始调用 通用识别 进行工作。
首先图像识别申请信息必不可少
//图像识别申请信息 String APP_ID="你的百度id"; String API_KEY="你的百度KEY"; String SECRET_KEY="你的百度SECRET_KEY"; String path="";//存地址
Button takePhoto = findViewById(R.id.camerabutton); Button choosePicture = findViewById(R.id.picturebutton); Button chooseOk=findViewById(R.id.okbutton);//按钮的定义按照自己的需求
chooseok点击进行处理
chooseOk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (path!="") { Toast.makeText(getApplicationContext(),"正在识别...请稍等",Toast.LENGTH_LONG).show(); new Thread(){ public void run(){ //线程处理 AipImageClassify client = new AipImageClassify(APP_ID, API_KEY, SECRET_KEY); HashMap options = new HashMap(); options.put("baike_num", "4"); String image = path; switch (youChoose){ case "btncommon": res = client.advancedGeneral(image, options);//通用 try { JSONArray jsonArray = res.getJSONArray("result");//返回JsonArray for(int i=0;i
我们可以看到不同识别的调用在于
res = client.advancedGeneral(image, options);//通用
这一句话里面,如果我是动物识别调用就是
res = client.animalDetect(image, options);//动物
所以在switch里面,只需要修改client.xxx函数,还有对返回的数据
res.getJSONObject
进行处理显示,即可达到效果。(不同的识别调用返回的数据格式不一样,需要分开处理,详情阅读 视觉技术 图像识别 API文档 可查阅有关返回的格式信息)
我们还发现,我们在Android6.0版本测试中,ui在此线程中更新的话会报错(UI线程不安全),为解决这个问题,我们通过用Handler方式更新UI。
private Handler handler=new Handler(){ public void handleMessage(android.os.Message msg){//获取消息携带的属性值 int what = msg.what; System.out.println("-what--->>" + what); switch (what) { case 1: Mytype.setText("类型: "+save_type); Myname.setText("名称: "+save_name); mShowText.setText(Speck_TEXT); break; case 2: Mytype.setText("类型: 无"); Myname.setText("名称: 无"); mShowText.setText("类型无法识别,请尝试重新拍照或按类型进行识别。"); break; default:break; } }; };
结合上一节和这一节,语音播放和拍照/选择图片/图像识别功能局可以成功实现。(核心功能就已经实现)
下一节的话,就介绍界面的设计/启动程序动画。
更多相关文章
- Android(安卓)View从源码的角度分析事件的注册和接收
- 2016年腾讯android开发工程师面试题目
- 在 Android(安卓)中使用 JNI 的总结
- [Android] 图像处理整合之处理ColorMatrix和Intend传递路径显示
- Android中实现native服务利用binder与应用通信
- Android(安卓)studio 小白使用Android(安卓)studio 2.3.1遇到的
- Android实现拍照或从相册中获取图片并且显示圆形图片
- Android(安卓)Activity 与Service进行数据交互详解
- Android(安卓)显示图片的时候设置转换动画