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<String, String> options = new HashMap<String, String>();
                            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<jsonArray.length();i++){
                                            JSONObject json=(JSONObject)jsonArray.get(i);
                                            String type=json.getString("root");
                                            JSONObject baike_info=json.getJSONObject("baike_info");
                                            String description="";
                                            String name=json.getString("keyword");
                                            if(!type.isEmpty())
                                            {
                                                System.out.println("in");
                                                save_name=name;
                                                save_type=type;
                                                if(baike_info.toString().length()!=2)//最佳识别有可能无描述的情况
                                                {
                                                    description= baike_info.getString("description");
                                                    Speck_TEXT=""+name+"的简介是:"+description+"";
                                                }
                                                else{
                                                    Speck_TEXT=""+name+"的简介并未查找到最佳匹配,若需要获取简介,请再次查询。";
                                                }
                                                //安卓6.0版本,子线程更新UI将报错弹出,需要用handler处理UI更新
                                                Message message = Message.obtain();
                                                message.what=1;
                                                handler.sendMessage(message);
                                                break;
                                            }
                                        }
                                    } catch (JSONException e) {
                                        System.out.println("in Exception");
                                        e.printStackTrace();
                                        Message message = Message.obtain();
                                        message.what=2;
                                        handler.sendMessage(message);
                                    }
                                    break;
                                case "btnanimal":
                                        /*与上面差不多描写方法*/
                            break;
                            }
                        }
                    }.start();
                }
                else{
                    Toast.makeText(getApplicationContext(),"尚未导入图片",Toast.LENGTH_SHORT).show();
                }
            }
        });

我们可以看到不同识别的调用在于

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;
            }
        };
    };

 

结合上一节和这一节,语音播放和拍照/选择图片/图像识别功能局可以成功实现。(核心功能就已经实现)

下一节的话,就介绍界面的设计/启动程序动画。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值