Android 百度图像识别(详细步骤+源码)(上)

2021-04-22 10:07:57 浏览数 (1)

运行效果图

在这里插入图片描述在这里插入图片描述

如果你对这个效果图不满意就不用往下看了,那样只会浪费你的时间。

一、创建平台应用

先登录百度开放平台

在这里插入图片描述在这里插入图片描述

然后进入管理控制台找到图像识别

在这里插入图片描述在这里插入图片描述

点击进入。

在这里插入图片描述在这里插入图片描述

创建应用

在这里插入图片描述在这里插入图片描述

然后点击下方的立即创建按钮。

在这里插入图片描述在这里插入图片描述

注意看下图标注的信息

在这里插入图片描述在这里插入图片描述

由于图像识别没有直接的Android SDK,因此本文将通过API访问进行图像的识别。

二、创建Android项目

通过API方式,则需要先完成鉴权认证,然后拿到Access Token,通过这个Access Token才能去请求这个图像识别的接口,这里要分为两步走。现在思路清楚了,下面先创建一个项目吧,命名为ImageDiscernDemo。

在这里插入图片描述在这里插入图片描述

项目创建好之后,先配置项目。打开工程的build.gradle,添加如下代码:

代码语言:txt复制
	maven { url "https://jitpack.io" }

添加位置如下:

在这里插入图片描述在这里插入图片描述

然后是修改app下的build.gradle,有两处

代码语言:txt复制
	compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
代码语言:txt复制
	//权限请求框架
    implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
    implementation "io.reactivex.rxjava2:rxjava:2.0.0"
    //retrofit2
    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
    //RecyclerView最好的适配器,让你的适配器一目了然,告别代码冗余
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
    //Glide框架
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
    //添加material库
    implementation 'com.google.android.material:material:1.2.1'

添加位置如下:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

然后Sync Now,完成后来配置AndroidManifest.xml,添加如下权限:

代码语言:txt复制
	<!--网络权限-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--文件读写-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!--相机-->
    <uses-permission android:name="android.permission.CAMERA"/>
在这里插入图片描述在这里插入图片描述

再来配置一个FileProvider,在res文件夹下新建一个xml文件夹,与layout文件夹同级,在xml文件夹下新建一个file_paths.xml,里面的代码如下:

代码语言:txt复制
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="" />
</paths>

然后在AndroidManifest.xml中配置

代码语言:txt复制
		<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.llw.imagediscerndemo.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>

添加位置如下图:

在这里插入图片描述在这里插入图片描述

下面我们首先简单来写一个网络访问的工具类。

三、网络访问框架

在com.llw.imagediscerndemo下新建一个network包,包下新建一个ServiceGenerator类,里面的代码如下:

代码语言:txt复制
package com.llw.imagediscerndemo.network;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * 接口地址管理
 *
 * @author llw
 */
public class ServiceGenerator {

    /**
     * 默认地址
     */
    public static String BASE_URL = "https://aip.baidubce.com";

    /**
     * 创建服务  参数就是API服务
     *
     * @param serviceClass 服务接口
     * @param <T>          泛型规范
     * @return api接口服务
     */
    public static <T> T createService(Class<T> serviceClass) {

        //创建OkHttpClient构建器对象
        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();

        //设置请求超时的时间,这里是10秒
        okHttpClientBuilder.connectTimeout(20000, TimeUnit.MILLISECONDS);

        //消息拦截器  因为有时候接口不同在排错的时候 需要先从接口的响应中做分析。利用了消息拦截器可以清楚的看到接口返回的所有内容
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();

        //setlevel用来设置日志打印的级别,共包括了四个级别:NONE,BASIC,HEADER,BODY
        //BASEIC:请求/响应行
        //HEADER:请求/响应行   头
        //BODY:请求/响应航   头   体
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        //为OkHttp添加消息拦截器
        okHttpClientBuilder.addInterceptor(httpLoggingInterceptor);

        //在Retrofit中设置httpclient
        //设置地址  就是上面的固定地址,如果你是本地访问的话,可以拼接上端口号  例如  ":8080"
        Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
                //用Gson把服务端返回的json数据解析成实体
                .addConverterFactory(GsonConverterFactory.create())
                //放入OKHttp,之前说过retrofit是对OkHttp的进一步封装
                .client(okHttpClientBuilder.build())
                .build();
        //返回这个创建好的API服务
        return retrofit.create(serviceClass);
    }

}

很简单的代码,也都是网络上常见的,OkHttp Retrofit。

这里面的默认地址 https://aip.baidubce.com是图像识别API的固定地址,后面的有变化的,通过接口来配置。

然后再写一个NetCallBack类,用来处理Retrofit的返回,里面的代码如下:

代码语言:txt复制
package com.llw.imagediscerndemo.network;

import android.util.Log;

import com.google.gson.Gson;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**
 * 网络请求回调
 *
 * @param <T>
 */
public abstract class NetCallBack<T> implements Callback<T> {//这里实现了retrofit2.Callback

    //访问成功回调
    @Override
    public void onResponse(Call<T> call, Response<T> response) {//数据返回
        if (response != null && response.body() != null && response.isSuccessful()) {
            onSuccess(call, response);
        } else {
            onFailed(response.raw().toString());
        }
    }

    //访问失败回调
    @Override
    public void onFailure(Call<T> call, Throwable t) {
        Log.d("data str", t.toString());
        onFailed(t.toString());
    }

    //数据返回
    public abstract void onSuccess(Call<T> call, Response<T> response);

    //失败异常
    public abstract void onFailed(String errorStr);


}

那么这样简单的网络框架写好了。

四、添加请求API接口

百度的图像识别,首先要完成鉴权认证,拿到一个Token,然后通过这个Token再去请求图像识别的API接口才行,所以要完成两步操作。先来看第一步

鉴权的地址如下:

代码语言:txt复制
https://aip.baidubce.com/oauth/2.0/token

这里面需要再带三个Url参数,使用Post请求方式。

代码语言:txt复制
grant_type: 必须参数,固定为client_credentials;
client_id: 必须参数,应用的API Key;
client_secret: 必须参数,应用的Secret Key;

返回的是一串JSON字符串,如下:

代码语言:txt复制
{
  "refresh_token": "25.b55fe1d287227ca97aab219bb249b8ab.315360000.1798284651.282335-8574074",
  "expires_in": 2592000,
  "scope": "public wise_adapt",
  "session_key": "9mzdDZXu3dENdFZQurfg0Vz8slgSgvvOAUebNFzyzcpQ5EnbxbF hfG9DQkpUVQdh4p6HbQcAiz5RmuBAja1JJGgIdJI",
  "access_token": "24.6c5e1ff107f0e8bcef8c46d3424a0e78.2592000.1485516651.282335-8574074",
  "session_secret": "dfac94a3489fe9fca7c3221cbf7525ff"
}

当请求和返回都确定之后,我们就可以构建请求实体和返回实体了。

而请求实体都是放在Url中的,因此不需要通过实体来构建,直接传参数就好。

在com.llw.imagediscerndemo包下新建一个model包,包下新建一个GetTokenResponse类,里面的代码如下:

代码语言:txt复制
package com.llw.imagediscerndemo.model;

/**
 * 获取鉴权认证Token响应实体
 */
public class GetTokenResponse {

    /**
     * refresh_token : 25.b55fe1d287227ca97aab219bb249b8ab.315360000.1798284651.282335-8574074
     * expires_in : 2592000
     * scope : public wise_adapt
     * session_key : 9mzdDZXu3dENdFZQurfg0Vz8slgSgvvOAUebNFzyzcpQ5EnbxbF hfG9DQkpUVQdh4p6HbQcAiz5RmuBAja1JJGgIdJI
     * access_token : 24.6c5e1ff107f0e8bcef8c46d3424a0e78.2592000.1485516651.282335-8574074
     * session_secret : dfac94a3489fe9fca7c3221cbf7525ff
     */

    private String refresh_token;
    private long expires_in;
    private String scope;
    private String session_key;
    private String access_token;
    private String session_secret;

    public String getRefresh_token() {
        return refresh_token;
    }

    public void setRefresh_token(String refresh_token) {
        this.refresh_token = refresh_token;
    }

    public long getExpires_in() {
        return expires_in;
    }

    public void setExpires_in(long expires_in) {
        this.expires_in = expires_in;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public String getSession_key() {
        return session_key;
    }

    public void setSession_key(String session_key) {
        this.session_key = session_key;
    }

    public String getAccess_token() {
        return access_token;
    }

    public void setAccess_token(String access_token) {
        this.access_token = access_token;
    }

    public String getSession_secret() {
        return session_secret;
    }

    public void setSession_secret(String session_secret) {
        this.session_secret = session_secret;
    }
}

这是通过刚才的返回数据生成的实体Bean,当网络请求返回数据后通过Retrofit会解析成这个返回实体。

下面添加接口,在network包下新建一个ApiService接口,里面的代码如下:

代码语言:txt复制
package com.llw.imagediscerndemo.network;

import com.llw.imagediscerndemo.model.GetTokenResponse;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.Headers;
import retrofit2.http.POST;

/**
 * API服务
 *
 * @author llw
 * @date 2021/4/1 17:48
 */
public interface ApiService {

    /**
     * 获取鉴权认证Token
     * @param grant_type 类型
     * @param client_id API Key
     * @param client_secret Secret Key
     * @return GetTokenResponse
     */
    @FormUrlEncoded
    @POST("/oauth/2.0/token")
    Call<GetTokenResponse> getToken(@Field("grant_type") String grant_type,
                                    @Field("client_id") String client_id,
                                    @Field("client_secret") String client_secret);

    
}

这里还有一个接口呢,那就是图像识别接口。地址为:

代码语言:txt复制
https://aip.baidubce.com/rest/2.0/image-classify/v2/advanced_general

找个接口比较特殊,官方文档的描述如下:

在这里插入图片描述在这里插入图片描述

看你是否理解了。返回数据如下:

代码语言:txt复制
{
	"log_id": 327863200205075661,
	"result_num": 5,
	"result": [{
		"score": 0.967622,
		"root": "公众人物",
		"baike_info": {
			"baike_url": "http://baike.baidu.com/item/新垣结衣/8035884",
			"image_url": "http://imgsrc.baidu.com/baikehttps://img.yuanmabao.com/zijie/pic/item/91ef76c6a7efce1b27893518a451f3deb58f6546.jpg",
			"description": "新垣结衣(Aragaki Yui),1988年6月11日出生于冲绳县那霸市。日本女演员、歌手、模特。毕业于日出高中。2001年,参加《nicola》模特比赛并获得最优秀奖。2005年,因出演现代剧《涩谷15》而作为演员出道。2006年,参演校园剧《我的老大,我的英雄》;同年,她还出版了个人首本写真集《水漾青春》。2007年,她从日出高校毕业后开始专注于演艺发展,并发表个人首张音乐专辑《天空》;同年,新垣结衣还主演了爱情片《恋空》,而她也凭借该片获得了多个电影新人奖项。2010年,主演爱情片《花水木》。2011年,主演都市剧《全开女孩》。2012年,相继参演现代剧《Legal High》、剧情片《剧场版新参者:麒麟之翼》。2013年,主演都市剧《飞翔情报室》。2014年,她主演了剧情片《黎明的沙耶》。2016年,主演爱情喜剧《逃避虽可耻但有用》,并凭借该剧获得了多个电视剧女主角奖项。2017年,主演爱情片《恋爱回旋》,凭借该片获得第60届蓝丝带奖最佳女主角;同年11月,她还凭借医疗剧《Code Blue 3》获得第94届日剧学院赏最佳女配角。"
		},
		"keyword": "新垣结衣"
	},
	{
		"score": 0.716067,
		"root": "人物-人物特写",
		"keyword": "头发"
	},
	{
		"score": 0.421281,
		"root": "商品-穿戴",
		"keyword": "围巾"
	},
	{
		"score": 0.22347,
		"root": "商品-五金",
		"keyword": "拉链"
	},
	{
		"score": 0.028031,
		"root": "商品-穿戴",
		"keyword": "脖套"
	}]
}

通过这个返回示例数据,可以生成一个实体Bean。在model包下新建一个GetDiscernResultResponse类,代码如下:

代码语言:txt复制
package com.llw.imagediscerndemo.model;

import java.util.List;

/**
 * 获取识别结果响应实体
 */
public class GetDiscernResultResponse {

    /**
     * log_id : 327863200205075661
     * result_num : 5
     * result : [{"score":0.967622,"root":"公众人物","baike_info":{"baike_url":"http://baike.baidu.com/item/新垣结衣/8035884","image_url":"http://imgsrc.baidu.com/baikehttps://img.yuanmabao.com/zijie/pic/item/91ef76c6a7efce1b27893518a451f3deb58f6546.jpg","description":"新垣结衣(Aragaki Yui),1988年6月11日出生于冲绳县那霸市。日本女演员、歌手、模特。毕业于日出高中。2001年,参加《nicola》模特比赛并获得最优秀奖。2005年,因出演现代剧《涩谷15》而作为演员出道。2006年,参演校园剧《我的老大,我的英雄》;同年,她还出版了个人首本写真集《水漾青春》。2007年,她从日出高校毕业后开始专注于演艺发展,并发表个人首张音乐专辑《天空》;同年,新垣结衣还主演了爱情片《恋空》,而她也凭借该片获得了多个电影新人奖项。2010年,主演爱情片《花水木》。2011年,主演都市剧《全开女孩》。2012年,相继参演现代剧《Legal High》、剧情片《剧场版新参者:麒麟之翼》。2013年,主演都市剧《飞翔情报室》。2014年,她主演了剧情片《黎明的沙耶》。2016年,主演爱情喜剧《逃避虽可耻但有用》,并凭借该剧获得了多个电视剧女主角奖项。2017年,主演爱情片《恋爱回旋》,凭借该片获得第60届蓝丝带奖最佳女主角;同年11月,她还凭借医疗剧《Code Blue 3》获得第94届日剧学院赏最佳女配角。"},"keyword":"新垣结衣"},{"score":0.716067,"root":"人物-人物特写","keyword":"头发"},{"score":0.421281,"root":"商品-穿戴","keyword":"围巾"},{"score":0.22347,"root":"商品-五金","keyword":"拉链"},{"score":0.028031,"root":"商品-穿戴","keyword":"脖套"}]
     */

    private long log_id;
    private int result_num;
    private List<ResultBean> result;

    public long getLog_id() {
        return log_id;
    }

    public void setLog_id(long log_id) {
        this.log_id = log_id;
    }

    public int getResult_num() {
        return result_num;
    }

    public void setResult_num(int result_num) {
        this.result_num = result_num;
    }

    public List<ResultBean> getResult() {
        return result;
    }

    public void setResult(List<ResultBean> result) {
        this.result = result;
    }

    public static class ResultBean {
        /**
         * score : 0.967622
         * root : 公众人物
         * baike_info : {"baike_url":"http://baike.baidu.com/item/新垣结衣/8035884","image_url":"http://imgsrc.baidu.com/baikehttps://img.yuanmabao.com/zijie/pic/item/91ef76c6a7efce1b27893518a451f3deb58f6546.jpg","description":"新垣结衣(Aragaki Yui),1988年6月11日出生于冲绳县那霸市。日本女演员、歌手、模特。毕业于日出高中。2001年,参加《nicola》模特比赛并获得最优秀奖。2005年,因出演现代剧《涩谷15》而作为演员出道。2006年,参演校园剧《我的老大,我的英雄》;同年,她还出版了个人首本写真集《水漾青春》。2007年,她从日出高校毕业后开始专注于演艺发展,并发表个人首张音乐专辑《天空》;同年,新垣结衣还主演了爱情片《恋空》,而她也凭借该片获得了多个电影新人奖项。2010年,主演爱情片《花水木》。2011年,主演都市剧《全开女孩》。2012年,相继参演现代剧《Legal High》、剧情片《剧场版新参者:麒麟之翼》。2013年,主演都市剧《飞翔情报室》。2014年,她主演了剧情片《黎明的沙耶》。2016年,主演爱情喜剧《逃避虽可耻但有用》,并凭借该剧获得了多个电视剧女主角奖项。2017年,主演爱情片《恋爱回旋》,凭借该片获得第60届蓝丝带奖最佳女主角;同年11月,她还凭借医疗剧《Code Blue 3》获得第94届日剧学院赏最佳女配角。"}
         * keyword : 新垣结衣
         */

        private double score;
        private String root;
        private BaikeInfoBean baike_info;
        private String keyword;

        public double getScore() {
            return score;
        }

        public void setScore(double score) {
            this.score = score;
        }

        public String getRoot() {
            return root;
        }

        public void setRoot(String root) {
            this.root = root;
        }

        public BaikeInfoBean getBaike_info() {
            return baike_info;
        }

        public void setBaike_info(BaikeInfoBean baike_info) {
            this.baike_info = baike_info;
        }

        public String getKeyword() {
            return keyword;
        }

        public void setKeyword(String keyword) {
            this.keyword = keyword;
        }

        public static class BaikeInfoBean {
            /**
             * baike_url : http://baike.baidu.com/item/新垣结衣/8035884
             * image_url : http://imgsrc.baidu.com/baikehttps://img.yuanmabao.com/zijie/pic/item/91ef76c6a7efce1b27893518a451f3deb58f6546.jpg
             * description : 新垣结衣(Aragaki Yui),1988年6月11日出生于冲绳县那霸市。日本女演员、歌手、模特。毕业于日出高中。2001年,参加《nicola》模特比赛并获得最优秀奖。2005年,因出演现代剧《涩谷15》而作为演员出道。2006年,参演校园剧《我的老大,我的英雄》;同年,她还出版了个人首本写真集《水漾青春》。2007年,她从日出高校毕业后开始专注于演艺发展,并发表个人首张音乐专辑《天空》;同年,新垣结衣还主演了爱情片《恋空》,而她也凭借该片获得了多个电影新人奖项。2010年,主演爱情片《花水木》。2011年,主演都市剧《全开女孩》。2012年,相继参演现代剧《Legal High》、剧情片《剧场版新参者:麒麟之翼》。2013年,主演都市剧《飞翔情报室》。2014年,她主演了剧情片《黎明的沙耶》。2016年,主演爱情喜剧《逃避虽可耻但有用》,并凭借该剧获得了多个电视剧女主角奖项。2017年,主演爱情片《恋爱回旋》,凭借该片获得第60届蓝丝带奖最佳女主角;同年11月,她还凭借医疗剧《Code Blue 3》获得第94届日剧学院赏最佳女配角。
             */

            private String baike_url;
            private String image_url;
            private String description;

            public String getBaike_url() {
                return baike_url;
            }

            public void setBaike_url(String baike_url) {
                this.baike_url = baike_url;
            }

            public String getImage_url() {
                return image_url;
            }

            public void setImage_url(String image_url) {
                this.image_url = image_url;
            }

            public String getDescription() {
                return description;
            }

            public void setDescription(String description) {
                this.description = description;
            }
        }
    }
}

下面在ApiService中添加接口。

代码语言:txt复制
	/**
     * 获取图像识别结果
     * @param accessToken 获取鉴权认证Token
     * @param url 网络图片Url
     * @return JsonObject
     */
    @FormUrlEncoded
    @POST("/rest/2.0/image-classify/v2/advanced_general")
    @Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
    Call<GetDiscernResultResponse> getDiscernResult(@Field("access_token") String accessToken,
                                                    @Field("url") String url);

我这个写法和官方说明好像有点不同,我没有用Body。选择直接把数据放在Url中请求。

现在万事具备了,下面先来获取鉴权认证Token。

0 人点赞