Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/ko/lite/android/quickstart.md
25118 views

Android ๋น ๋ฅธ ์‹œ์ž‘

์ด ํŽ˜์ด์ง€๋Š” TensorFlow Lite๋ฅผ ํ†ตํ•ด Android ์•ฑ์„ ๊ตฌ์ถ•ํ•˜์—ฌ ๋ผ์ด๋ธŒ ์นด๋ฉ”๋ผ ํ”ผ๋“œ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ๊ฐ์ฒด๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด ๋จธ์‹ ๋Ÿฌ๋‹ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๊ฐ์ฒด ๊ฐ์ง€๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ ์•ฑ์€ Google Play ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด TensorFlow Lite ๋น„์ „์šฉ ์ž‘์—… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ TensorFlow Lite๋ฅผ ํ†ตํ•ด ML ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ๊ถŒ์žฅ๋˜๋Š” ์ ‘๊ทผ ๋ฐฉ๋ฒ•์ธ ๊ฐ์ฒด ๊ฐ์ง€ ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ์˜ ์‹คํ–‰์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์ฒด ๊ฐ์ง€ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐ๋ชจ{: .attempt-right width="250px"}

์„ค์น˜ ๋ฐ ์˜ˆ์ œ ์‹คํ–‰

์ด ์—ฐ์Šต์˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ถ„์—์„œ๋Š” GitHub์—์„œ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  Android Studio๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์˜ ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” ์ฝ”๋“œ ์˜ˆ์ œ์˜ ๊ด€๋ จ ์„น์…˜์„ ์‚ดํŽด๋ณผ ๊ฒƒ์ด๋ฏ€๋กœ ์ด๋ฅผ ์ž์‹ ์˜ Android ์•ฑ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋„๊ตฌ์˜ ๋‹ค์Œ ๋ฒ„์ „์ด ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • Android Studio 4.2 ์ด์ƒ

  • Android SDK ๋ฒ„์ „ 21 ์ด์ƒ

์ฐธ๊ณ : ์ด ์˜ˆ์—์„œ๋Š” ์นด๋ฉ”๋ผ๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์‹ค์ œ Android ๊ธฐ๊ธฐ์—์„œ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ ๊ฐ€์ ธ์˜ค๊ธฐ

์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ  ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์˜ˆ์ œ ์ฝ”๋“œ์˜ ๋กœ์ปฌ ์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๋ณต์ œํ•˜๊ณ  ์„ค์ •ํ•˜๋ ค๋ฉด:

  1. git ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋ณต์ œํ•ฉ๋‹ˆ๋‹ค.

        git clone https://github.com/tensorflow/examples.git
         
  2. ํฌ์†Œ ์ฒดํฌ์•„์›ƒ์„ ์‚ฌ์šฉํ•˜๋„๋ก git ์ธ์Šคํ„ด์Šค๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด ๊ฐ์ฒด ๊ฐ์ง€ ์˜ˆ์ œ ์•ฑ์— ๋Œ€ํ•œ ํŒŒ์ผ๋งŒ ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

        cd examples
         git sparse-checkout init --cone
         git sparse-checkout set lite/examples/object_detection/android_play_services
         

ํ”„๋กœ์ ํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ์‹คํ–‰ํ•˜๊ธฐ

Android Studio๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์šด๋กœ๋“œํ•œ ์˜ˆ์ œ ์ฝ”๋“œ์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์ฝ”๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๋นŒ๋“œํ•˜๋ ค๋ฉด:

  1. Android Studio๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

  2. Android Studio์˜ ์‹œ์ž‘ ํŽ˜์ด์ง€์—์„œ **Import Project(ํ”„๋กœ์ ํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ)**๋ฅผ ์„ ํƒํ•˜๊ฑฐ๋‚˜ **File(ํŒŒ์ผ) > New(์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ) > Import Project(ํ”„๋กœ์ ํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ)**๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

  3. build.gradle ํŒŒ์ผ(...examples/lite/examples/object_detection/android_play_services/build.gradle)์ด ํฌํ•จ๋œ ์˜ˆ์ œ ์ฝ”๋“œ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•˜์—ฌ ํ•ด๋‹น ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

์ด ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์„ ํƒํ•œ ํ›„, Android Studio๋Š” ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์ถ•์ด ์™„๋ฃŒ๋˜๋ฉด Android Studio๋Š” Build Output ์ƒํƒœ ํŒจ๋„์— BUILD SUCCESSFUL ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด:

  1. Android Studio์—์„œ Run(์‹คํ–‰) > Run(์‹คํ–‰)โ€ฆ ๋ฐ MainActivity๋ฅผ ์„ ํƒํ•˜์—ฌ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  2. ์นด๋ฉ”๋ผ๊ฐ€ ์žˆ๋Š” ์—ฐ๊ฒฐ Android ๊ธฐ๊ธฐ๋ฅผ ์„ ํƒํ•˜์—ฌ ์•ฑ์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์•ฑ ์ž‘๋™ ๋ฐฉ์‹

์˜ˆ์ œ ์•ฑ์€ TensorFlow Lite ํ˜•์‹์˜ mobilenetv1.tflite๊ณผ ๊ฐ™์€ ์‚ฌ์ „ ํ›ˆ๋ จ๋œ ๊ฐ์ฒด ๊ฐ์ง€ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด Android ๊ธฐ๊ธฐ์˜ ์นด๋ฉ”๋ผ์—์„œ ๋ผ์ด๋ธŒ ๋น„๋””์˜ค ์ŠคํŠธ๋ฆผ์˜ ๊ฐ์ฒด๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์ฝ”๋“œ๋Š” ์ฃผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒŒ์ผ์— ์žˆ์Šต๋‹ˆ๋‹ค.

  • ObjectDetectorHelper.kt - ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ํ•˜๋“œ์›จ์–ด ๊ฐ€์†์„ ํ™œ์„ฑํ™”ํ•˜๋ฉฐ ๊ฐ์ฒด ๊ฐ์ง€ ML ๋ชจ๋ธ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • CameraFragment.kt - ์นด๋ฉ”๋ผ ์ด๋ฏธ์ง€ ๋ฐ์ดํŠธ ์ŠคํŠธ๋ฆผ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ๋ชจ๋ธ์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๋ฉฐ ๊ฐ์ฒด ๊ฐ์ง€ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

์ฐธ์—ฌ: ์ด ์˜ˆ์ œ ์•ฑ์€ ์ผ๋ฐ˜ ๋จธ์‹ ๋Ÿฌ๋‹ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด, ์ž‘์—…๋ณ„ API๋ฅผ ์ œ๊ณตํ•˜๋Š” TensorFlow Lite ์ž‘์—… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋”์šฑ ๊ตฌ์ฒด์ ์ธ ์š”๊ตฌ์™€ ์‚ฌ์šฉ์ž ์ •์˜๋œ ML ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š” ์•ฑ์˜ ๊ฒฝ์šฐ, Interpreter API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

๋‹ค์Œ ์„น์…˜์€ Android ์•ฑ์„ ์ˆ˜์ •ํ•˜์—ฌ ์ด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด๋Ÿฌํ•œ ์ฝ”๋“œ ํŒŒ์ผ์˜ ์ฃผ์š” ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์•ฑ ๊ตฌ์ถ• {:#build_app}

๋‹ค์Œ ์„น์…˜์€ ์ž์‹ ๋งŒ์˜ Android ์•ฑ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ์˜ˆ์ œ ์•ฑ์— ํ‘œ์‹œ๋œ ๋ชจ๋ธ์„ ์‹คํ–‰ํ•˜๋Š” ์ฃผ์š” ๋‹จ๊ณ„๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ง€์นจ์€ ์•ž์„œ ๋ณด์—ฌ๋“œ๋ฆฐ ์˜ˆ์‹œ ์•ฑ์„ ์ฐธ์กฐ ํฌ์ธํŠธ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : ์ด๋Ÿฌํ•œ ์ง€์นจ์„ ๋”ฐ๋ฅด๊ณ  ์ž์‹ ๋งŒ์˜ ์•ฑ์„ ๊ตฌ์ถ•ํ•˜๋ ค๋ฉด Android Studio๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ Android ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”.

ํ”„๋กœ์ ํŠธ ์ข…์†์„ฑ ์ถ”๊ฐ€ {:#add_dependencies}

๊ธฐ๋ณธ Android ์•ฑ์—์„œ, TensorFlow Lite ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ์‹คํ–‰ํ•˜๊ณ  ML ๋ฐ์ดํ„ฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ธฐ๋Šฅ์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”. ์ด๋Ÿฌํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ธฐ๋Šฅ์€ ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋ธ์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ…์„œ ๋ฐ์ดํ„ฐ ํ˜•์‹์œผ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ ์•ฑ์€ Google Play ์„œ๋น„์Šค์˜ TensorFlow Lite ๋น„์ „์šฉ ์ž‘์—… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด ๊ฐ์ง€ ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์ง€์นจ์€ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ข…์†์„ฑ์„ ์ž์ฒด Android ์•ฑ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“ˆ ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด:

  1. TensorFlow Lite๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“ˆ์—์„œ ๋‹ค์Œ ์ข…์†์„ฑ์„ ํฌํ•จํ•˜๋„๋ก ๋ชจ๋“ˆ์˜ build.gradle ํŒŒ์ผ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ ์ฝ”๋“œ์—์„œ ์ด ํŒŒ์ผ์€ ...examples/lite/examples/object_detection/android_play_services/app/build.gradle์— ์žˆ์Šต๋‹ˆ๋‹ค.

    ... dependencies { ... // Tensorflow Lite dependencies implementation 'org.tensorflow:tensorflow-lite-task-vision-play-services:0.4.2' implementation 'com.google.android.gms:play-services-tflite-gpu:16.1.0' ... }
  2. Android Studio์—์„œ **File(ํŒŒ์ผ) > Sync Project with Gradle Files(ํ”„๋กœ์ ํŠธ๋ฅผ Gradle ํŒŒ์ผ๊ณผ ๋™๊ธฐํ™”)**๋ฅผ ์„ ํƒํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ์ข…์†์„ฑ์„ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

Google Play ์„œ๋น„์Šค ์ดˆ๊ธฐํ™”

Google Play ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ TensorFlow Lite ๋ชจ๋ธ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, ์„œ๋น„์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ์ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด GPU ๊ฐ€์†๊ณผ ๊ฐ™์€ ํ•˜๋“œ์›จ์–ด ๊ฐ€์† ์ง€์›์„ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒฝ์šฐ, ์ด ์ดˆ๊ธฐํ™”์˜ ์ผํ™˜์œผ๋กœ ํ•ด๋‹น ์ง€์›๋„ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Google Play ์„œ๋น„์Šค๋กœ TensorFlow Lite๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  1. TfLiteInitializationOptions ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ˆ˜์ •ํ•˜์—ฌ GPU ์ง€์›์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.

    val options = TfLiteInitializationOptions.builder() .setEnableGpuDelegateSupport(true) .build()
  2. TfLiteVision.initialize() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Play ์„œ๋น„์Šค ๋Ÿฐํƒ€์ž„ ์‚ฌ์šฉ์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ๋ฆฌ์Šค๋„ˆ๋ฅผ ์„ค์ •ํ•˜์—ฌ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋“œ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

    TfLiteVision.initialize(context, options).addOnSuccessListener { objectDetectorListener.onInitialized() }.addOnFailureListener { // Called if the GPU Delegate is not supported on the device TfLiteVision.initialize(context).addOnSuccessListener { objectDetectorListener.onInitialized() }.addOnFailureListener{ objectDetectorListener.onError("TfLiteVision failed to initialize: " + it.message) } }

ML ๋ชจ๋ธ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ

๋ชจ๋ธ ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๊ณ  ๋ชจ๋ธ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์—ฌ TensorFlow Lite ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. TensorFlow Lite ๋ชจ๋ธ์€ ๋ชจ๋ธ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” .tflite ํŒŒ์ผ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ์˜ src/main/assets ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋ชจ๋ธ์„ ์ €์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

.../src/main/assets/mobilenetv1.tflite`

ํŒ: ์ž‘์—… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์ฝ”๋“œ๋Š” ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด src/main/assets ๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ ๋ชจ๋ธ์„ ์ž๋™์œผ๋กœ ์ฐพ์Šต๋‹ˆ๋‹ค.

๋ชจ๋ธ์„ ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  1. .tflite ๋ชจ๋ธ ํŒŒ์ผ์„ ๊ฐœ๋ฐœ ํ”„๋กœ์ ํŠธ์˜ src/main/assets ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ssd_mobilenet_v1).

  2. modelName ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์—ฌ ML ๋ชจ๋ธ์˜ ํŒŒ์ผ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

    val modelName = "mobilenetv1.tflite"
  3. ์˜ˆ์ธก ์ž„๊ณ„๊ฐ’ ๋ฐ ๊ฒฐ๊ณผ ์„ธํŠธ ํฌ๊ธฐ์™€ ๊ฐ™์€ ๋ชจ๋ธ์— ๋Œ€ํ•œ ์˜ต์…˜์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

    val optionsBuilder = ObjectDetector.ObjectDetectorOptions.builder() .setScoreThreshold(threshold) .setMaxResults(maxResults)
  4. ์˜ต์…˜์ด ์žˆ๋Š” GPU ๊ฐ€์†์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ๊ฐ€์†์ด ๊ธฐ๊ธฐ์—์„œ ์ง€์›๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์ฝ”๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํŒจํ•˜๋„๋ก ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

    try { optionsBuilder.useGpu() } catch(e: Exception) { objectDetectorListener.onError("GPU is not supported on this device") }
  5. ์ด ๊ฐ์ฒด์˜ ์„ค์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋ธ์ด ํฌํ•จ๋œ TensorFlow Lite ObjectDetector ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

    objectDetector = ObjectDetector.createFromFileAndOptions( context, modelName, optionsBuilder.build())

TensorFlow Lite์™€ ํ•จ๊ป˜ ํ•˜๋“œ์›จ์–ด ๊ฐ€์† ๋Œ€๋ฆฌ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ TensorFlow Lite ๋Œ€๋ฆฌ์ž๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ชจ๋ธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ์ค€๋น„ํ•˜๊ธฐ

๋ชจ๋ธ์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ํ…์„œ ๋ฐ์ดํ„ฐ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ชจ๋ธ์ด ํ•ด์„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ํ…์„œ์˜ ๋ฐ์ดํ„ฐ๋Š” ๋ชจ๋ธ์„ ํ›ˆ๋ จํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ฐ์ดํ„ฐ ํ˜•์‹๊ณผ ์ผ์น˜ํ•˜๋Š” ํŠน์ • ์น˜์ˆ˜๋‚˜ ํ˜•์ƒ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์— ๋”ฐ๋ผ, ๋ชจ๋ธ์ด ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒƒ์— ๋งž๋„๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ ์•ฑ์€ ImageAnalysis ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์นด๋ฉ”๋ผ ํ•˜์œ„ ์‹œ์Šคํ…œ์—์„œ ์ด๋ฏธ์ง€ ํ”„๋ ˆ์ž„์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋ธ์ด ์ฒ˜๋ฆฌํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  1. ImageAnalysis ๊ฐ์ฒด๋ฅผ ๋นŒ๋“œํ•˜์—ฌ ํ•„์š”ํ•œ ํ˜•์‹์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.

    imageAnalyzer = ImageAnalysis.Builder() .setTargetAspectRatio(AspectRatio.RATIO_4_3) .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888) .build() ...
  2. ๋ถ„์„๊ธฐ๋ฅผ ์นด๋ฉ”๋ผ ํ•˜์œ„ ์‹œ์Šคํ…œ์— ์—ฐ๊ฒฐํ•˜๊ณ  ์นด๋ฉ”๋ผ์—์„œ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•  ๋น„ํŠธ๋งต ๋ฒ„ํผ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    .also { it.setAnalyzer(cameraExecutor) { image -> if (!::bitmapBuffer.isInitialized) { bitmapBuffer = Bitmap.createBitmap( image.width, image.height, Bitmap.Config.ARGB_8888 ) } detectObjects(image) } }
  3. ๋ชจ๋ธ์— ํ•„์š”ํ•œ ํŠน์ • ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์ด๋ฏธ์ง€ ํšŒ์ „ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

    private fun detectObjects(image: ImageProxy) { // Copy out RGB bits to the shared bitmap buffer image.use { bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) } val imageRotation = image.imageInfo.rotationDegrees objectDetectorHelper.detect(bitmapBuffer, imageRotation) }
  4. ์˜ˆ์ œ ์•ฑ์˜ ObjectDetectorHelper.detect() ๋ฉ”์„œ๋“œ์— ํ‘œ์‹œ๋œ ๋Œ€๋กœ ์ตœ์ข… ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์„ ์™„๋ฃŒํ•˜๊ณ  ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ TensorImage ๊ฐ์ฒด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

    val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build() // Preprocess the image and convert it into a TensorImage for detection. val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))

์˜ˆ์ธก ์‹คํ–‰ํ•˜๊ธฐ

์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹์˜ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋กœ TensorImage ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ๋ชจ๋ธ์„ ์‹คํ–‰ํ•˜์—ฌ ์˜ˆ์ธก ๋˜๋Š” ์ถ”๋ก ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ ์•ฑ์—์„œ, ์ด ์ฝ”๋“œ๋Š” ObjectDetectorHelper.detect() ๋ฉ”์„œ๋“œ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋ธ์„ ์‹คํ–‰ํ•˜๊ณ  ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ์—์„œ ์˜ˆ์ธก์„ ์ƒ์„ฑํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ˆ์ธก ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜์—ฌ ์˜ˆ์ธก์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    val results = objectDetector?.detect(tensorImage)

๋ชจ๋ธ ์ถœ๋ ฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ

๊ฐ์ฒด ๊ฐ์ง€ ๋ชจ๋ธ์— ๋Œ€ํ•ด ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ์ถ”๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์กฐ์น˜๋ฅผ ์ทจํ•˜์—ฌ ์•ฑ ์ฝ”๋“œ๊ฐ€ ๋‹ค๋ค„์•ผ ํ•˜๋Š” ์˜ˆ์ธก ๊ฒฐ๊ณผ ๋ชฉ๋ก์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ ์•ฑ์˜ ๊ฐ์ฒด ๊ฐ์ง€ ๋ชจ๋ธ์€ ์˜ˆ์ธก ๋ชฉ๋ก๊ณผ ๊ฐ์ง€๋œ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ ์•ฑ์—์„œ, ์˜ˆ์ธก ๊ฒฐ๊ณผ๋Š” ์ถ”๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ๋ฆฌ์Šค๋„ˆ ๊ฐ์ฒด๋กœ ์ „๋‹ฌ๋˜๋ฉฐ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋ธ ์˜ˆ์ธก ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด:

  1. ๋ฆฌ์Šค๋„ˆ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ ์ฝ”๋“œ ๋˜๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ๊ฐ์ฒด์— ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ ์•ฑ์€ ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ObjectDetectorHelper ๊ฐ์ฒด์˜ ๊ฐ์ง€ ๊ฒฐ๊ณผ๋ฅผ CameraFragment ๊ฐ์ฒด๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

    objectDetectorListener.onResults( // instance of CameraFragment results, inferenceTime, tensorImage.height, tensorImage.width)
  2. ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ˆ์ธก์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์—์„œ๋Š” CameraPreview ๊ฐ์ฒด์— ์˜ค๋ฒ„๋ ˆ์ด๋ฅผ ๊ทธ๋ ค ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

    override fun onResults( results: MutableList<Detection>?, inferenceTime: Long, imageHeight: Int, imageWidth: Int ) { activity?.runOnUiThread { fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text = String.format("%d ms", inferenceTime) // Pass necessary information to OverlayView for drawing on the canvas fragmentCameraBinding.overlay.setResults( results ?: LinkedList<Detection>(), imageHeight, imageWidth ) // Force a redraw fragmentCameraBinding.overlay.invalidate() } }

๋‹ค์Œ ๋‹จ๊ณ„

  • Task Library API์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

  • Interpreter API์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

  • ์˜ˆ์ œ์—์„œ TensorFlow Lite์˜ ์šฉ๋„๋ฅผ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค.

  • ๋ชจ๋ธ ์„น์…˜์—์„œ TensorFlow Lite๋ฅผ ํ†ตํ•ด ๋จธ์‹ ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

  • TensorFlow Lite ๊ฐœ๋ฐœ์ž ๊ฐ€์ด๋“œ์—์„œ ๋ชจ๋ฐ”์ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋จธ์‹ ๋Ÿฌ๋‹์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.