Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Androidで触れてみようCloud Vision API_ハンズオン

Androidで触れてみようCloud Vision API_ハンズオン

2016/4/30 GDG is a hands-on document of CloudVisionAPI in Kobe

Avatar for katsuki-nakatani

katsuki-nakatani

April 30, 2016
Tweet

More Decks by katsuki-nakatani

Other Decks in Technology

Transcript

  1. ͜ΕΛΫϦοΫͯ͠HSBEMFϏϧυ͠·͢ ৭ʑ؀ڥҧ͏ͱΤϥʔ͕ग़Δ CVJMEHSBEMF .PEVMFBQQ BOESPJE\ DPNQJMF4EL7FSTJPO CVJME5PPMT7FSTJPȌ EFGBVMU$POpH\ BQQMJDBUJPO*EPSHHEHLPCFFYBNQMFDMPVEWJTJPO NJO4EL7FSTJPO

    UBSHFU4EL7FSTJPO WFSTJPO$PEF WFSTJPO/BNF ^ CVJME5ZQFT\ SFMFBTF\ NJOJGZ&OBCMFEGBMTF QSPHVBSE'JMFTHFU%FGBVMU1SPHVBSE'JMF QSPHVBSEBOESPJEUYU QSPHVBSESVMFTQSP ^ ^ ^ ͜͜Β΁Μʁ
  2. -BCFM%FUFDUJPOͷϑΥʔϚοτΛݟͯΈ·͠ΐ͏ 3FRVFTUଆ IUUQTDMPVEHPPHMFDPNWJTJPOSFGFSFODFSFTUWJNBHFTBOOPUBUF GFBUVSFTʹ͸UZQF ղੳ͍ͨ͠λΠϓ ͱNBY3FTVMUT ࠷େ݁Ռ਺ Λ౉͠·͢ ྫ͑͹Ͱ͕͢ɺ෺ମݕ஌ͱإݕ஌྆ํΛಉ͡ը૾ʹରͯ͠ߦ͍͍ͨ৔߹͸ɺ ͜ͷΑ͏ͳσʔλΛ࡞੒͢ΔΠϝʔδʹͳΓ·͢

    'FBUVSF -"#&-@%&5&$5*0/   'FBUVSF '"$&@%&5&$5*0/   KBWBPSHHEHLPCFFYBNQMFDMPVEWJTJPOFOUJUZ಺ʹಉ༷ͷ໊લͰఆٛΛ͍ͯ͠·͢ ཁ͸ԿΛ౉ͤ͹͍͍͔ͱ͍͏ͱ ɹը૾σʔλ ɹ ݕ஌͍ͨ͠λΠϓ ɹ݁Ռͱͯ͠΄͍͠࠷େ݅਺ Y/ ͜ΕΛ౉ͤ͹0,Ͱ͢
  3. "1*ͷϦΫΤετఆٛ QVCMJDJOUFSGBDF7JTJPO"QJ\ !)FBEFST $POUFOU5ZQFBQQMJDBUJPOKTPO  !1045 WJNBHFTBOOPUBUF  $BMM3FTQPOTFQPTU !2VFSZ

    LFZ 4USJOH"QJ,FZ !#PEZ3FRVFTUSFRVFTU  ^ KBWBPSHHEHLPCFFYBNQMFDMPVEWJTJPOBQJ7JTJPO"QJΛ։͖·͢ ࣮ࡍͷSFRVFTU͸ԼهͷΑ͏ͳ63-ʹͳΓ·͢ IUUQTWJTJPOHPPHMFBQJTDPNWJNBHFTBOOPUBUF LFZ:063,&:
  4. "1*ίʔϧॲཧΛॻ͖·͠ΐ͏ DBMM$MPVE7JTJPO ͷϝιου಺ͷɺ#JUNBQͷ/VMMνΣοΫ͕ऴΘͬͨͱ͜Ζʹ௥ه͠·͢ //HttpClientͷੜ੒ OkHttpClient client = new OkHttpClient.Builder(). addInterceptor(new

    JsonInterceptor()). build(); // RetrofitAdapterͷੜ੒ Retrofit adapter = new Retrofit.Builder() .baseUrl(API_BASE_URL) .addConverterFactory(MoshiConverterFactory.create(new Moshi.Builder().build())) .client(client) .build(); // ඇಉظॲཧͷ࣮ߦ Request request = new Request(); request.addRequest(mBitmap, new Feature(Feature.FeatureType.LABEL_DETECTION)); adapter.create(VisionApi.class).post(getString(R.string.vision_api), request) .enqueue(new Callback<Response>() { @Override public void onResponse(Call<Response> call, retrofit2.Response<Response> response) { if (response.body().getResponses().get(0).getLabelAnnotations().size() <= 0) { Snackbar.make(mCoordinator, R.string.label_annotation_error, Snackbar.LENGTH_LONG).show(); } else { mOriginalJson = response.message(); } } @Override public void onFailure(Call<Response> call, Throwable t) { } }); Snackbar.make(mCoordinator, R.string.vision_api_upload, Snackbar.LENGTH_LONG).show(); 3FRVFTUͱ3FTQPOTF͸Πϯϙʔτީิ͕ෳ਺͋ΔͨΊ"MU &OUFSͰϓϩδΣΫτ಺෦ͷ෺ΛΠϯϙʔτ͍ͯͩ͘͠͞ $BMM#BDL΋ෳ਺ީิ͕͋ΔͷͰɺͪ͜Β͸SFUSPpUͷ΋ͷΛΠϯϙʔτ͍ͯͩ͘͠͞
  5. ݁ՌͷηοτॲཧΛॻ͖·͠ΐ͏ ৽نͰϝιουΛ࡞੒͠·͢ void setText(List<LabelAnnotation> labelAnnotations) { StringBuilder stringBuilder = new

    StringBuilder(); for (LabelAnnotation labelAnnotation : labelAnnotations) { stringBuilder.append(getString(R.string.label_detection_result, labelAnnotation.getDescription(), labelAnnotation.getScore() * 100)); } mTextView.setText(stringBuilder.toString()); } adapter.create(VisionApi.class).post(getString(R.string.vision_api), request) .enqueue(new Callback<Response>() { @Override public void onResponse(Call<Response> call, retrofit2.Response<Response> response) { if (response.body().getResponses().get(0).getLabelAnnotations().size() <= 0) { Snackbar.make(mCoordinator, R.string.label_annotation_error, Snackbar.LENGTH_LONG).show(); } else { mOriginalJson = response.message(); ɹɹɹɹsetText(response.body().getResponses().get(0).getLabelAnnotations()); } } @Override public void onFailure(Call<Response> call, Throwable t) { } }); Snackbar.make(mCoordinator, R.string.vision_api_upload, Snackbar.LENGTH_LONG).show(); MBCFM"OOPUBUJPOT͕̍݅Ͱ΋͋ͬͨ৔߹͸4FU5FYUΛݺͼग़ͯ͠දࣔ͢ΔΑ͏ʹ͠·͠ΐ͏
  6. "1*ίʔϧॲཧΛॻ͖·͠ΐ͏ DBMM$MPVE7JTJPO ͷϝιου಺ͷɺ#JUNBQͷ/VMMνΣοΫ͕ऴΘͬͨͱ͜Ζʹ௥ه͠·͢ //HttpClientͷੜ੒ OkHttpClient client = new OkHttpClient.Builder(). addInterceptor(new

    JsonInterceptor()). build(); // RetrofitAdapterͷੜ੒ Retrofit adapter = new Retrofit.Builder() .baseUrl(API_BASE_URL) .addConverterFactory(MoshiConverterFactory.create(new Moshi.Builder().build())) .client(client) .build(); // ඇಉظॲཧͷ࣮ߦ Request request = new Request(); request.addRequest(mBitmap, new Feature(Feature.FeatureType.FACE_DETECTION)); adapter.create(VisionApi.class).post(getString(R.string.vision_api), request) .enqueue(new Callback<Response>() { @Override public void onResponse(Call<Response> call, retrofit2.Response<Response> response) { if (response.body().getResponses().get(0).getFaceAnnotations().size() <= 0) { Snackbar.make(mCoordinator, R.string.face_annotation_error, Snackbar.LENGTH_LONG).show(); } else { mOriginalJson = response.message(); } } @Override public void onFailure(Call<Response> call, Throwable t) { } }); Snackbar.make(mCoordinator, R.string.vision_api_upload, Snackbar.LENGTH_LONG).show();
  7. ݁ՌͷηοτॲཧΛॻ͖·͠ΐ͏ ࠓճ͸'SBHNFOUʹ஋Λ౉͢Α͏ʹ͍ͯ͠·͢ ৽نͰϝιουΛ࡞੒͠·͢ void showFaceDetectionFragment(String json) { Fragment f =

    getSupportFragmentManager().findFragmentById(R.id.fragment); if (f instanceof FaceDetectionFragment) { ((FaceDetectionFragment) f).update(json); } else { getSupportFragmentManager(). beginTransaction() .replace(R.id.fragment, FaceDetectionFragment.newInstance(json)) .commitAllowingStateLoss(); } } adapter.create(VisionApi.class).post(getString(R.string.vision_api), request) .enqueue(new Callback<Response>() { @Override public void onResponse(Call<Response> call, retrofit2.Response<Response> response) { if (response.body().getResponses().get(0).getFaceAnnotations().size() <= 0) { Snackbar.make(mCoordinator, R.string.face_annotation_error, Snackbar.LENGTH_LONG).show(); } else { mOriginalJson = response.message(); showFaceDetectionFragment(response.message()); } } @Override public void onFailure(Call<Response> call, Throwable t) { } }); Snackbar.make(mCoordinator, R.string.vision_api_upload, Snackbar.LENGTH_LONG).show(); 'BDF"OOPUBUJPOT͕̍݅Ͱ΋͋ͬͨ৔߹͸'SBHNFOU΁஋Ληοτͯ͠දࣔ͢ΔΑ͏ʹ͠·͠ΐ͏
  8. "DUJWJUZଆʹ࠲ඪදࣔ༻ͷϝιουΛ૊ΈࠐΈ·͠ΐ͏ ࣄલʹJOUFSGBDFΛ࡞੒͍ͯ͠ΔͷͰͦΕΛ࣮૷͠·͢ ฤू͢Δͷ͸'BDF%FUFDUJPO"DUJWJUZͰ͢ "DUJWJUZʹ·ͣJNQMFNFOUT͠·͠ΐ͏ QVCMJDDMBTT'BDF%FUFDUJPO"DUJWJUZFYUFOET7JTJPO#BTF"DUJWJUZJNQMFNFOUT*NBHF6QEBUF-JTUFOFS //ύʔπݕग़ΤϦΞͷϘʔμʔΧϥʔ private static final int

    LANDMARK_AREA_COLOR = Color.argb(255, 255, 255, 255); //إݕग़ΤϦΞͷϘʔμʔΧϥʔ private static final int POLY_AREA_COLOR = Color.argb(255, 255, 0, 0); //ύʔπݕग़ΤϦΞͷΤϦΞαΠζ private static final int LANDMARK_AREA_SIZE = 10; ࿮ઢඳը༻ͷύϥϝʔλΛઌʹఆ͓͖ٛͯ͠·͢ *NBHF6QEBUF-JTUFOFSʹΧʔιϧΛ౰ͯͯ"MU &OUFSͰ*NQMFNFOUNFUIPETΛల։Ͱ͖·͢
  9. ࿮ઢΛඳը͢ΔϝιουΛ૊ΈࠐΈ·͠ΐ͏ -BOENBSL إͷύʔπ ͷ৔ॴΛදࣔ͠·͢ !0WFSSJEF QVCMJDWPJETFU1PJOU qPBUY qPBUZ \ $BOWBTDBOWBT

    #JUNBQOFX#JUNBQ#JUNBQDSFBUF#JUNBQ N#JUNBQHFU8JEUI N#JUNBQHFU)FJHIU #JUNBQ$POpH"3(#@  DBOWBTOFX$BOWBT OFX#JUNBQ  DBOWBTESBX#JUNBQ N#JUNBQ   OVMM  1BJOUQBJOUOFX1BJOU  QBJOUTFU$PMPS -"/%."3,@"3&"@$0-03  QBJOUTFU4UZMF 1BJOU4UZMF4530,&  QBJOUTFU4USPLF8JEUI   DBOWBTESBX3FDU Y-"/%."3,@"3&"@4*;& Z-"/%."3,@"3&"@4*;& Y -"/%."3,@"3&"@4*;&  Z  -"/%."3,@"3&"@4*;&  QBJOU  N*NBHFTFU*NBHF#JUNBQ OFX#JUNBQ  DPMMBQTF#PUUPN4IFFU  ^ ̎ ̍ ̏ ̐ ̍ɽΩϟϯόεʹ·ͣ͸Ξοϓϩʔυͨ͠ը૾Λඳը͍ͯ͠·͢ ̎ɽΩϟϯόεʹ௥ՃͰॻ͘ϒϥγͷఆٛΛ͍ͯ͠·͢ ࣄલʹఆٛͨ͠$0-03Λར༻͢ΔΑ͏ʹ͍ͯ͠·͢ ̏ɽ࢛֯࿮Λඳը͍ͯ͠·͢ɹ࢛۱ͷϙΠϯτΛࢦఆ͍ͯ͠ΔͨΊɺ΋ΒͬͨҐஔΛ൒෼ʹͯ͠଍͠Ҿ͖࢛ͯ͠۱Λࢦఆ͍ͯ͠·͢ ̐ɽඳ͍ͨ#JUNBQΛը໘ͷ*NBHF7JFXʹηοτ͍ͯ͠·͢
  10. ࿮ઢΛඳը͢ΔϝιουΛ૊ΈࠐΈ·͠ΐ͏ CPVOEJOH1PMZ ݕग़ͨ͠إͷΤϦΞ ͷ৔ॴΛදࣔ͠·͢ !0WFSSJEF QVCMJDWPJETFU1PMZ 1PMZCPVOEJOH1PMZ 1PMZGC#PVOEJOH1PMZ \ $BOWBTDBOWBT

    #JUNBQOFX#JUNBQ#JUNBQDSFBUF#JUNBQ N#JUNBQHFU8JEUI N#JUNBQHFU)FJHIU #JUNBQ$POpH"3(#@  DBOWBTOFX$BOWBT OFX#JUNBQ  DBOWBTESBX#JUNBQ N#JUNBQ   OVMM  1BJOUQBJOUOFX1BJOU  QBJOUTFU$PMPS 10-:@"3&"@$0-03  QBJOUTFU4UZMF 1BJOU4UZMF4530,&  QBJOUTFU4USPLF8JEUI   DBOWBTESBX3FDU CPVOEJOH1PMZHFU7FSUJDFT HFU  HFU9  CPVOEJOH1PMZHFU7FSUJDFT HFU  HFU:  CPVOEJOH1PMZHFU7FSUJDFT HFU  HFU9  CPVOEJOH1PMZHFU7FSUJDFT HFU  HFU:   QBJOU  DBOWBTESBX3FDU GC#PVOEJOH1PMZHFU7FSUJDFT HFU  HFU9  GC#PVOEJOH1PMZHFU7FSUJDFT HFU  HFU:  GC#PVOEJOH1PMZHFU7FSUJDFT HFU  HFU9  GC#PVOEJOH1PMZHFU7FSUJDFT HFU  HFU:   QBJOU  N*NBHFTFU*NBHF#JUNBQ OFX#JUNBQ  ^ 1PMZܕ͸ɺ࢛۱ͷ৘ใΛ͢΂͍ͯ࣋ͬͯ ΔͷͰɺࠨ্ͱӈԼͷ࠲ඪΛऔΓग़ͯ͠ࢦ ఆ͍ͯ͠·͢
  11. 5FYU%FUFDUJPOͷϨεϙϯεϑΥʔϚοτΛݟͯΈ·͠ΐ͏ ͜Ε͕ϦετͰฦͬͯདྷ·͢ NJE *%  MPDBMF ղੳͨ͠ݴޠ  EFTDSJQUJPO ղੳ݁Ռͷจࣈྻ

     TDPSF ৴པ཰  CPVOEJOH1PMZ ղੳͨ͠ΤϦΞͷ৘ใ QSJWBUF4USJOHNJE QSJWBUF4USJOHMPDBMF QSJWBUF4USJOHEFTDSJQUJPO QSJWBUFqPBUTDPSF QSJWBUF1PMZCPVOEJOH1PMZ 5FYU"OOPUBUJPOKBWB
  12. 5FYU%FUFDUJPO"DUJWJUZΛฤू͠·͢ DBMM$MPVE7JTJPO ͷϝιου಺ͷɺ#JUNBQͷ/VMMνΣοΫ͕ऴΘͬͨͱ͜Ζʹ௥ه͠·͢ʢ΋͏ҰॹͰ͢Ͷɻɻɻʣ //HttpClientͷੜ੒ OkHttpClient client = new OkHttpClient.Builder(). addInterceptor(new

    JsonInterceptor()). build(); // RetrofitAdapterͷੜ੒ Retrofit adapter = new Retrofit.Builder() .baseUrl(API_BASE_URL) .addConverterFactory(MoshiConverterFactory.create(new Moshi.Builder().build())) .client(client) .build(); // ඇಉظॲཧͷ࣮ߦ Request request = new Request(); request.addRequest(mBitmap, new Feature(Feature.FeatureType.TEXT_DETECTION)); adapter.create(VisionApi.class).post(getString(R.string.vision_api), request) .enqueue(new Callback<Response>() { @Override public void onResponse(Call<Response> call, retrofit2.Response<Response> response) { if (response.body().getResponses().get(0).getTextAnnotations().size() <= 0) { Snackbar.make(mCoordinator, R.string.text_annotation_error, Snackbar.LENGTH_LONG).show(); } else { mOriginalJson = response.message(); showResult(); } } @Override public void onFailure(Call<Response> call, Throwable t) { } }); Snackbar.make(mCoordinator, R.string.vision_api_upload, Snackbar.LENGTH_LONG).show();
  13. ݁ՌΛηοτ͠Α͏ TIPX3FTVMU ͷϝιου಺ʹ݁ՌΛදࣔ͢ΔΑ͏ʹ͠·͠ΐ͏ 5FYU%FUFDUJPO͸ɺೝࣝͨ͠ΤϦΞ৘ใ΋ฦͬͯདྷ·͢ͷͰɺฦͬͯདྷͨςΩετͱɺ࿮ઢΛ྆ํηοτ͍ͯ͠·͢ void showResult() { parse(); if (mResponse

    != null) { mLanguage.setText(mResponse.getResponses().get(0).getTextAnnotations().get(0).getLocale()); mResultText.setText(mResponse.getResponses().get(0).getTextAnnotations().get(0).getDescription()); List<Vertex> vertexList = mResponse.getResponses().get(0).getTextAnnotations().get(0).getBoundingPoly().getVertices(); Canvas canvas; Bitmap newBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888); canvas = new Canvas(newBitmap); canvas.drawBitmap(mBitmap, 0, 0, null); Paint paint = new Paint(); paint.setColor(POLY_AREA_COLOR); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(2); canvas.drawRect(vertexList.get(0).getX(), vertexList.get(0).getY(), vertexList.get(2).getX(), vertexList.get(2).getY() , paint); mImage.setImageBitmap(newBitmap); } }
  14. "OOPUBUF3FTQPOTFΛฤू͠·͢ ϨεϙϯεʹTBGF4FBSDI"OOPUBUJPOͷఆٛΛ௥Ճ͠·͢ public class AnnotateResponse { private List<FaceAnnotation> faceAnnotations =

    new ArrayList<>(); private List<TextAnnotation> textAnnotations = new ArrayList<>(); private List<LabelAnnotation> labelAnnotations = new ArrayList<>(); private SafeSearchAnnotation safeSearchAnnotation; }
  15. ݁ՌΛηοτ͠Α͏ 4BGF4FBSDI%FUFDUJPO"DUJWJUZ಺ͷTIPX3FTVMU ͷϝιου಺ʹ݁ՌΛදࣔ͢ΔΑ͏ʹ͠·͠ΐ͏ void showResult() { parse(); if (mResponse !=

    null) { SafeSearchAnnotation annotation = mResponse.getResponses().get(0).getSafeSearchAnnotation(); mAdult.setRating(annotation.getRating(annotation.getAdult())); mSpoof.setRating(annotation.getRating(annotation.getSpoof())); mMedical.setRating(annotation.getRating(annotation.getMedical())); mViolence.setRating(annotation.getRating(annotation.getViolence())); mAdult.setText(getString(R.string.adult)); mSpoof.setText(getString(R.string.spoof)); mMedical.setText(getString(R.string.medical)); mViolence.setText(getString(R.string.violence)); } }