11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ML Kit for Firebase Quickstart
2 | ==============================
3 |
4 | The ML Kit for Firebase Android Quickstart app demonstrates how to use the
5 | various features of ML Kit to add machine learning to your application.
6 |
7 | Introduction
8 | ------------
9 |
10 | - [Read more about ML Kit for Firebase](https://firebase.google.com/docs/ml-kit/)
11 |
12 | Getting Started
13 | ---------------
14 |
15 | - [Add Firebase to your Android Project](https://firebase.google.com/docs/android/setup).
16 | - Run the sample on an Android device.
17 | - Choose LivePreviewActivity to see a demo of the following APIs:
18 | - Face detection
19 | - Text recognition (on-device)
20 | - Barcode scanning
21 | - Image labeling (on-device)
22 | - Landmark recognition
23 | - Choose StillImageActivity to see a demo of the following:
24 | - Image labeling (Cloud)
25 | - Landmark recognition (Cloud)
26 | - Text recognition (Cloud)
27 | - Document text recognition (Cloud)
28 |
29 | Result
30 | -----------
31 |
32 |
33 | Support
34 | -------
35 |
36 | - [Stack Overflow](https://stackoverflow.com/questions/tagged/mlkit)
37 | - [Firebase Support](https://firebase.google.com/support/).
38 |
39 | License
40 | -------
41 |
42 | Copyright 2018 Google, Inc.
43 |
44 | Licensed to the Apache Software Foundation (ASF) under one or more contributor
45 | license agreements. See the NOTICE file distributed with this work for
46 | additional information regarding copyright ownership. The ASF licenses this
47 | file to you under the Apache License, Version 2.0 (the "License"); you may not
48 | use this file except in compliance with the License. You may obtain a copy of
49 | the License at
50 |
51 | http://www.apache.org/licenses/LICENSE-2.0
52 |
53 | Unless required by applicable law or agreed to in writing, software
54 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
55 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
56 | License for the specific language governing permissions and limitations under
57 | the License.
58 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "com.google.firebase.samples.apps.mlkit"
7 | minSdkVersion 21
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:27.1.1'
24 | implementation 'com.android.support:design:27.1.1'
25 | implementation 'com.android.support.constraint:constraint-layout:1.1.0'
26 | testImplementation 'junit:junit:4.12'
27 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
28 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
29 |
30 | // ML Kit dependencies
31 | implementation 'com.google.firebase:firebase-ml-vision:15.0.0'
32 | implementation 'com.google.firebase:firebase-ml-vision-image-label-model:15.0.0'
33 | implementation 'com.google.firebase:firebase-ml-model-interpreter:15.0.0'
34 | }
35 | apply plugin: 'com.google.gms.google-services'
36 |
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "199636744573",
4 | "firebase_url": "https://mlkit-demo-ab019.firebaseio.com",
5 | "project_id": "mlkit-demo-ab019",
6 | "storage_bucket": "mlkit-demo-ab019.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:199636744573:android:09546560b4505797",
12 | "android_client_info": {
13 | "package_name": "com.google.firebase.samples.apps.mlkit"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "199636744573-5omkbk053cb4o5a02q1n63bdk491rff4.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyABq_7Obj5jFJT6TZv8jN1h74bzyafA4pw"
25 | }
26 | ],
27 | "services": {
28 | "analytics_service": {
29 | "status": 1
30 | },
31 | "appinvite_service": {
32 | "status": 1,
33 | "other_platform_oauth_client": []
34 | },
35 | "ads_service": {
36 | "status": 2
37 | }
38 | }
39 | }
40 | ],
41 | "configuration_version": "1"
42 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/assets/labels.txt:
--------------------------------------------------------------------------------
1 | background
2 | tench
3 | goldfish
4 | great white shark
5 | tiger shark
6 | hammerhead
7 | electric ray
8 | stingray
9 | cock
10 | hen
11 | ostrich
12 | brambling
13 | goldfinch
14 | house finch
15 | junco
16 | indigo bunting
17 | robin
18 | bulbul
19 | jay
20 | magpie
21 | chickadee
22 | water ouzel
23 | kite
24 | bald eagle
25 | vulture
26 | great grey owl
27 | European fire salamander
28 | common newt
29 | eft
30 | spotted salamander
31 | axolotl
32 | bullfrog
33 | tree frog
34 | tailed frog
35 | loggerhead
36 | leatherback turtle
37 | mud turtle
38 | terrapin
39 | box turtle
40 | banded gecko
41 | common iguana
42 | American chameleon
43 | whiptail
44 | agama
45 | frilled lizard
46 | alligator lizard
47 | Gila monster
48 | green lizard
49 | African chameleon
50 | Komodo dragon
51 | African crocodile
52 | American alligator
53 | triceratops
54 | thunder snake
55 | ringneck snake
56 | hognose snake
57 | green snake
58 | king snake
59 | garter snake
60 | water snake
61 | vine snake
62 | night snake
63 | boa constrictor
64 | rock python
65 | Indian cobra
66 | green mamba
67 | sea snake
68 | horned viper
69 | diamondback
70 | sidewinder
71 | trilobite
72 | harvestman
73 | scorpion
74 | black and gold garden spider
75 | barn spider
76 | garden spider
77 | black widow
78 | tarantula
79 | wolf spider
80 | tick
81 | centipede
82 | black grouse
83 | ptarmigan
84 | ruffed grouse
85 | prairie chicken
86 | peacock
87 | quail
88 | partridge
89 | African grey
90 | macaw
91 | sulphur-crested cockatoo
92 | lorikeet
93 | coucal
94 | bee eater
95 | hornbill
96 | hummingbird
97 | jacamar
98 | toucan
99 | drake
100 | red-breasted merganser
101 | goose
102 | black swan
103 | tusker
104 | echidna
105 | platypus
106 | wallaby
107 | koala
108 | wombat
109 | jellyfish
110 | sea anemone
111 | brain coral
112 | flatworm
113 | nematode
114 | conch
115 | snail
116 | slug
117 | sea slug
118 | chiton
119 | chambered nautilus
120 | Dungeness crab
121 | rock crab
122 | fiddler crab
123 | king crab
124 | American lobster
125 | spiny lobster
126 | crayfish
127 | hermit crab
128 | isopod
129 | white stork
130 | black stork
131 | spoonbill
132 | flamingo
133 | little blue heron
134 | American egret
135 | bittern
136 | crane
137 | limpkin
138 | European gallinule
139 | American coot
140 | bustard
141 | ruddy turnstone
142 | red-backed sandpiper
143 | redshank
144 | dowitcher
145 | oystercatcher
146 | pelican
147 | king penguin
148 | albatross
149 | grey whale
150 | killer whale
151 | dugong
152 | sea lion
153 | Chihuahua
154 | Japanese spaniel
155 | Maltese dog
156 | Pekinese
157 | Shih-Tzu
158 | Blenheim spaniel
159 | papillon
160 | toy terrier
161 | Rhodesian ridgeback
162 | Afghan hound
163 | basset
164 | beagle
165 | bloodhound
166 | bluetick
167 | black-and-tan coonhound
168 | Walker hound
169 | English foxhound
170 | redbone
171 | borzoi
172 | Irish wolfhound
173 | Italian greyhound
174 | whippet
175 | Ibizan hound
176 | Norwegian elkhound
177 | otterhound
178 | Saluki
179 | Scottish deerhound
180 | Weimaraner
181 | Staffordshire bullterrier
182 | American Staffordshire terrier
183 | Bedlington terrier
184 | Border terrier
185 | Kerry blue terrier
186 | Irish terrier
187 | Norfolk terrier
188 | Norwich terrier
189 | Yorkshire terrier
190 | wire-haired fox terrier
191 | Lakeland terrier
192 | Sealyham terrier
193 | Airedale
194 | cairn
195 | Australian terrier
196 | Dandie Dinmont
197 | Boston bull
198 | miniature schnauzer
199 | giant schnauzer
200 | standard schnauzer
201 | Scotch terrier
202 | Tibetan terrier
203 | silky terrier
204 | soft-coated wheaten terrier
205 | West Highland white terrier
206 | Lhasa
207 | flat-coated retriever
208 | curly-coated retriever
209 | golden retriever
210 | Labrador retriever
211 | Chesapeake Bay retriever
212 | German short-haired pointer
213 | vizsla
214 | English setter
215 | Irish setter
216 | Gordon setter
217 | Brittany spaniel
218 | clumber
219 | English springer
220 | Welsh springer spaniel
221 | cocker spaniel
222 | Sussex spaniel
223 | Irish water spaniel
224 | kuvasz
225 | schipperke
226 | groenendael
227 | malinois
228 | briard
229 | kelpie
230 | komondor
231 | Old English sheepdog
232 | Shetland sheepdog
233 | collie
234 | Border collie
235 | Bouvier des Flandres
236 | Rottweiler
237 | German shepherd
238 | Doberman
239 | miniature pinscher
240 | Greater Swiss Mountain dog
241 | Bernese mountain dog
242 | Appenzeller
243 | EntleBucher
244 | boxer
245 | bull mastiff
246 | Tibetan mastiff
247 | French bulldog
248 | Great Dane
249 | Saint Bernard
250 | Eskimo dog
251 | malamute
252 | Siberian husky
253 | dalmatian
254 | affenpinscher
255 | basenji
256 | pug
257 | Leonberg
258 | Newfoundland
259 | Great Pyrenees
260 | Samoyed
261 | Pomeranian
262 | chow
263 | keeshond
264 | Brabancon griffon
265 | Pembroke
266 | Cardigan
267 | toy poodle
268 | miniature poodle
269 | standard poodle
270 | Mexican hairless
271 | timber wolf
272 | white wolf
273 | red wolf
274 | coyote
275 | dingo
276 | dhole
277 | African hunting dog
278 | hyena
279 | red fox
280 | kit fox
281 | Arctic fox
282 | grey fox
283 | tabby
284 | tiger cat
285 | Persian cat
286 | Siamese cat
287 | Egyptian cat
288 | cougar
289 | lynx
290 | leopard
291 | snow leopard
292 | jaguar
293 | lion
294 | tiger
295 | cheetah
296 | brown bear
297 | American black bear
298 | ice bear
299 | sloth bear
300 | mongoose
301 | meerkat
302 | tiger beetle
303 | ladybug
304 | ground beetle
305 | long-horned beetle
306 | leaf beetle
307 | dung beetle
308 | rhinoceros beetle
309 | weevil
310 | fly
311 | bee
312 | ant
313 | grasshopper
314 | cricket
315 | walking stick
316 | cockroach
317 | mantis
318 | cicada
319 | leafhopper
320 | lacewing
321 | dragonfly
322 | damselfly
323 | admiral
324 | ringlet
325 | monarch
326 | cabbage butterfly
327 | sulphur butterfly
328 | lycaenid
329 | starfish
330 | sea urchin
331 | sea cucumber
332 | wood rabbit
333 | hare
334 | Angora
335 | hamster
336 | porcupine
337 | fox squirrel
338 | marmot
339 | beaver
340 | guinea pig
341 | sorrel
342 | zebra
343 | hog
344 | wild boar
345 | warthog
346 | hippopotamus
347 | ox
348 | water buffalo
349 | bison
350 | ram
351 | bighorn
352 | ibex
353 | hartebeest
354 | impala
355 | gazelle
356 | Arabian camel
357 | llama
358 | weasel
359 | mink
360 | polecat
361 | black-footed ferret
362 | otter
363 | skunk
364 | badger
365 | armadillo
366 | three-toed sloth
367 | orangutan
368 | gorilla
369 | chimpanzee
370 | gibbon
371 | siamang
372 | guenon
373 | patas
374 | baboon
375 | macaque
376 | langur
377 | colobus
378 | proboscis monkey
379 | marmoset
380 | capuchin
381 | howler monkey
382 | titi
383 | spider monkey
384 | squirrel monkey
385 | Madagascar cat
386 | indri
387 | Indian elephant
388 | African elephant
389 | lesser panda
390 | giant panda
391 | barracouta
392 | eel
393 | coho
394 | rock beauty
395 | anemone fish
396 | sturgeon
397 | gar
398 | lionfish
399 | puffer
400 | abacus
401 | abaya
402 | academic gown
403 | accordion
404 | acoustic guitar
405 | aircraft carrier
406 | airliner
407 | airship
408 | altar
409 | ambulance
410 | amphibian
411 | analog clock
412 | apiary
413 | apron
414 | ashcan
415 | assault rifle
416 | backpack
417 | bakery
418 | balance beam
419 | balloon
420 | ballpoint
421 | Band Aid
422 | banjo
423 | bannister
424 | barbell
425 | barber chair
426 | barbershop
427 | barn
428 | barometer
429 | barrel
430 | barrow
431 | baseball
432 | basketball
433 | bassinet
434 | bassoon
435 | bathing cap
436 | bath towel
437 | bathtub
438 | beach wagon
439 | beacon
440 | beaker
441 | bearskin
442 | beer bottle
443 | beer glass
444 | bell cote
445 | bib
446 | bicycle-built-for-two
447 | bikini
448 | binder
449 | binoculars
450 | birdhouse
451 | boathouse
452 | bobsled
453 | bolo tie
454 | bonnet
455 | bookcase
456 | bookshop
457 | bottlecap
458 | bow
459 | bow tie
460 | brass
461 | brassiere
462 | breakwater
463 | breastplate
464 | broom
465 | bucket
466 | buckle
467 | bulletproof vest
468 | bullet train
469 | butcher shop
470 | cab
471 | caldron
472 | candle
473 | cannon
474 | canoe
475 | can opener
476 | cardigan
477 | car mirror
478 | carousel
479 | carpenter's kit
480 | carton
481 | car wheel
482 | cash machine
483 | cassette
484 | cassette player
485 | castle
486 | catamaran
487 | CD player
488 | cello
489 | cellular telephone
490 | chain
491 | chainlink fence
492 | chain mail
493 | chain saw
494 | chest
495 | chiffonier
496 | chime
497 | china cabinet
498 | Christmas stocking
499 | church
500 | cinema
501 | cleaver
502 | cliff dwelling
503 | cloak
504 | clog
505 | cocktail shaker
506 | coffee mug
507 | coffeepot
508 | coil
509 | combination lock
510 | computer keyboard
511 | confectionery
512 | container ship
513 | convertible
514 | corkscrew
515 | cornet
516 | cowboy boot
517 | cowboy hat
518 | cradle
519 | crane
520 | crash helmet
521 | crate
522 | crib
523 | Crock Pot
524 | croquet ball
525 | crutch
526 | cuirass
527 | dam
528 | desk
529 | desktop computer
530 | dial telephone
531 | diaper
532 | digital clock
533 | digital watch
534 | dining table
535 | dishrag
536 | dishwasher
537 | disk brake
538 | dock
539 | dogsled
540 | dome
541 | doormat
542 | drilling platform
543 | drum
544 | drumstick
545 | dumbbell
546 | Dutch oven
547 | electric fan
548 | electric guitar
549 | electric locomotive
550 | entertainment center
551 | envelope
552 | espresso maker
553 | face powder
554 | feather boa
555 | file
556 | fireboat
557 | fire engine
558 | fire screen
559 | flagpole
560 | flute
561 | folding chair
562 | football helmet
563 | forklift
564 | fountain
565 | fountain pen
566 | four-poster
567 | freight car
568 | French horn
569 | frying pan
570 | fur coat
571 | garbage truck
572 | gasmask
573 | gas pump
574 | goblet
575 | go-kart
576 | golf ball
577 | golfcart
578 | gondola
579 | gong
580 | gown
581 | grand piano
582 | greenhouse
583 | grille
584 | grocery store
585 | guillotine
586 | hair slide
587 | hair spray
588 | half track
589 | hammer
590 | hamper
591 | hand blower
592 | hand-held computer
593 | handkerchief
594 | hard disc
595 | harmonica
596 | harp
597 | harvester
598 | hatchet
599 | holster
600 | home theater
601 | honeycomb
602 | hook
603 | hoopskirt
604 | horizontal bar
605 | horse cart
606 | hourglass
607 | iPod
608 | iron
609 | jack-o'-lantern
610 | jean
611 | jeep
612 | jersey
613 | jigsaw puzzle
614 | jinrikisha
615 | joystick
616 | kimono
617 | knee pad
618 | knot
619 | lab coat
620 | ladle
621 | lampshade
622 | laptop
623 | lawn mower
624 | lens cap
625 | letter opener
626 | library
627 | lifeboat
628 | lighter
629 | limousine
630 | liner
631 | lipstick
632 | Loafer
633 | lotion
634 | loudspeaker
635 | loupe
636 | lumbermill
637 | magnetic compass
638 | mailbag
639 | mailbox
640 | maillot
641 | maillot
642 | manhole cover
643 | maraca
644 | marimba
645 | mask
646 | matchstick
647 | maypole
648 | maze
649 | measuring cup
650 | medicine chest
651 | megalith
652 | microphone
653 | microwave
654 | military uniform
655 | milk can
656 | minibus
657 | miniskirt
658 | minivan
659 | missile
660 | mitten
661 | mixing bowl
662 | mobile home
663 | Model T
664 | modem
665 | monastery
666 | monitor
667 | moped
668 | mortar
669 | mortarboard
670 | mosque
671 | mosquito net
672 | motor scooter
673 | mountain bike
674 | mountain tent
675 | mouse
676 | mousetrap
677 | moving van
678 | muzzle
679 | nail
680 | neck brace
681 | necklace
682 | nipple
683 | notebook
684 | obelisk
685 | oboe
686 | ocarina
687 | odometer
688 | oil filter
689 | organ
690 | oscilloscope
691 | overskirt
692 | oxcart
693 | oxygen mask
694 | packet
695 | paddle
696 | paddlewheel
697 | padlock
698 | paintbrush
699 | pajama
700 | palace
701 | panpipe
702 | paper towel
703 | parachute
704 | parallel bars
705 | park bench
706 | parking meter
707 | passenger car
708 | patio
709 | pay-phone
710 | pedestal
711 | pencil box
712 | pencil sharpener
713 | perfume
714 | Petri dish
715 | photocopier
716 | pick
717 | pickelhaube
718 | picket fence
719 | pickup
720 | pier
721 | piggy bank
722 | pill bottle
723 | pillow
724 | ping-pong ball
725 | pinwheel
726 | pirate
727 | pitcher
728 | plane
729 | planetarium
730 | plastic bag
731 | plate rack
732 | plow
733 | plunger
734 | Polaroid camera
735 | pole
736 | police van
737 | poncho
738 | pool table
739 | pop bottle
740 | pot
741 | potter's wheel
742 | power drill
743 | prayer rug
744 | printer
745 | prison
746 | projectile
747 | projector
748 | puck
749 | punching bag
750 | purse
751 | quill
752 | quilt
753 | racer
754 | racket
755 | radiator
756 | radio
757 | radio telescope
758 | rain barrel
759 | recreational vehicle
760 | reel
761 | reflex camera
762 | refrigerator
763 | remote control
764 | restaurant
765 | revolver
766 | rifle
767 | rocking chair
768 | rotisserie
769 | rubber eraser
770 | rugby ball
771 | rule
772 | running shoe
773 | safe
774 | safety pin
775 | saltshaker
776 | sandal
777 | sarong
778 | sax
779 | scabbard
780 | scale
781 | school bus
782 | schooner
783 | scoreboard
784 | screen
785 | screw
786 | screwdriver
787 | seat belt
788 | sewing machine
789 | shield
790 | shoe shop
791 | shoji
792 | shopping basket
793 | shopping cart
794 | shovel
795 | shower cap
796 | shower curtain
797 | ski
798 | ski mask
799 | sleeping bag
800 | slide rule
801 | sliding door
802 | slot
803 | snorkel
804 | snowmobile
805 | snowplow
806 | soap dispenser
807 | soccer ball
808 | sock
809 | solar dish
810 | sombrero
811 | soup bowl
812 | space bar
813 | space heater
814 | space shuttle
815 | spatula
816 | speedboat
817 | spider web
818 | spindle
819 | sports car
820 | spotlight
821 | stage
822 | steam locomotive
823 | steel arch bridge
824 | steel drum
825 | stethoscope
826 | stole
827 | stone wall
828 | stopwatch
829 | stove
830 | strainer
831 | streetcar
832 | stretcher
833 | studio couch
834 | stupa
835 | submarine
836 | suit
837 | sundial
838 | sunglass
839 | sunglasses
840 | sunscreen
841 | suspension bridge
842 | swab
843 | sweatshirt
844 | swimming trunks
845 | swing
846 | switch
847 | syringe
848 | table lamp
849 | tank
850 | tape player
851 | teapot
852 | teddy
853 | television
854 | tennis ball
855 | thatch
856 | theater curtain
857 | thimble
858 | thresher
859 | throne
860 | tile roof
861 | toaster
862 | tobacco shop
863 | toilet seat
864 | torch
865 | totem pole
866 | tow truck
867 | toyshop
868 | tractor
869 | trailer truck
870 | tray
871 | trench coat
872 | tricycle
873 | trimaran
874 | tripod
875 | triumphal arch
876 | trolleybus
877 | trombone
878 | tub
879 | turnstile
880 | typewriter keyboard
881 | umbrella
882 | unicycle
883 | upright
884 | vacuum
885 | vase
886 | vault
887 | velvet
888 | vending machine
889 | vestment
890 | viaduct
891 | violin
892 | volleyball
893 | waffle iron
894 | wall clock
895 | wallet
896 | wardrobe
897 | warplane
898 | washbasin
899 | washer
900 | water bottle
901 | water jug
902 | water tower
903 | whiskey jug
904 | whistle
905 | wig
906 | window screen
907 | window shade
908 | Windsor tie
909 | wine bottle
910 | wing
911 | wok
912 | wooden spoon
913 | wool
914 | worm fence
915 | wreck
916 | yawl
917 | yurt
918 | web site
919 | comic book
920 | crossword puzzle
921 | street sign
922 | traffic light
923 | book jacket
924 | menu
925 | plate
926 | guacamole
927 | consomme
928 | hot pot
929 | trifle
930 | ice cream
931 | ice lolly
932 | French loaf
933 | bagel
934 | pretzel
935 | cheeseburger
936 | hotdog
937 | mashed potato
938 | head cabbage
939 | broccoli
940 | cauliflower
941 | zucchini
942 | spaghetti squash
943 | acorn squash
944 | butternut squash
945 | cucumber
946 | artichoke
947 | bell pepper
948 | cardoon
949 | mushroom
950 | Granny Smith
951 | strawberry
952 | orange
953 | lemon
954 | fig
955 | pineapple
956 | banana
957 | jackfruit
958 | custard apple
959 | pomegranate
960 | hay
961 | carbonara
962 | chocolate sauce
963 | dough
964 | meat loaf
965 | pizza
966 | potpie
967 | burrito
968 | red wine
969 | espresso
970 | cup
971 | eggnog
972 | alp
973 | bubble
974 | cliff
975 | coral reef
976 | geyser
977 | lakeside
978 | promontory
979 | sandbar
980 | seashore
981 | valley
982 | volcano
983 | ballplayer
984 | groom
985 | scuba diver
986 | rapeseed
987 | daisy
988 | yellow lady's slipper
989 | corn
990 | acorn
991 | hip
992 | buckeye
993 | coral fungus
994 | agaric
995 | gyromitra
996 | stinkhorn
997 | earthstar
998 | hen-of-the-woods
999 | bolete
1000 | ear
1001 | toilet tissue
1002 |
--------------------------------------------------------------------------------
/app/src/main/assets/mobilenet_quant_v1_224.tflite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/assets/mobilenet_quant_v1_224.tflite
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSource.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package com.google.firebase.samples.apps.mlkit;
16 |
17 | import android.Manifest;
18 | import android.annotation.SuppressLint;
19 | import android.app.Activity;
20 | import android.content.Context;
21 | import android.graphics.ImageFormat;
22 | import android.graphics.SurfaceTexture;
23 | import android.hardware.Camera;
24 | import android.hardware.Camera.CameraInfo;
25 | import android.support.annotation.Nullable;
26 | import android.support.annotation.RequiresPermission;
27 | import android.util.Log;
28 | import android.view.Surface;
29 | import android.view.SurfaceHolder;
30 | import android.view.WindowManager;
31 |
32 | import com.google.android.gms.common.images.Size;
33 |
34 | import java.io.IOException;
35 | import java.lang.Thread.State;
36 | import java.nio.ByteBuffer;
37 | import java.util.ArrayList;
38 | import java.util.IdentityHashMap;
39 | import java.util.List;
40 | import java.util.Map;
41 |
42 | /**
43 | * Manages the camera and allows UI updates on top of it (e.g. overlaying extra Graphics or
44 | * displaying extra information). This receives preview frames from the camera at a specified rate,
45 | * sending those frames to child classes' detectors / classifiers as fast as it is able to process.
46 | */
47 | public class CameraSource {
48 | @SuppressLint("InlinedApi")
49 | public static final int CAMERA_FACING_BACK = CameraInfo.CAMERA_FACING_BACK;
50 |
51 | @SuppressLint("InlinedApi")
52 | public static final int CAMERA_FACING_FRONT = CameraInfo.CAMERA_FACING_FRONT;
53 |
54 | private static final String TAG = "MIDemoApp:CameraSource";
55 |
56 | /**
57 | * The dummy surface texture must be assigned a chosen name. Since we never use an OpenGL context,
58 | * we can choose any ID we want here. The dummy surface texture is not a crazy hack - it is
59 | * actually how the camera team recommends using the camera without a preview.
60 | */
61 | private static final int DUMMY_TEXTURE_NAME = 100;
62 |
63 | /**
64 | * If the absolute difference between a preview size aspect ratio and a picture size aspect ratio
65 | * is less than this tolerance, they are considered to be the same aspect ratio.
66 | */
67 | private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
68 |
69 | protected Activity activity;
70 |
71 | private Camera camera;
72 |
73 | protected int facing = CAMERA_FACING_BACK;
74 |
75 | /**
76 | * Rotation of the device, and thus the associated preview images captured from the device. See
77 | * Frame.Metadata#getRotation().
78 | */
79 | private int rotation;
80 |
81 | private Size previewSize;
82 |
83 | // These values may be requested by the caller. Due to hardware limitations, we may need to
84 | // select close, but not exactly the same values for these.
85 | private final float requestedFps = 20.0f;
86 | private final int requestedPreviewWidth = 1280;
87 | private final int requestedPreviewHeight = 960;
88 | private final boolean requestedAutoFocus = true;
89 |
90 | // These instances need to be held onto to avoid GC of their underlying resources. Even though
91 | // these aren't used outside of the method that creates them, they still must have hard
92 | // references maintained to them.
93 | private SurfaceTexture dummySurfaceTexture;
94 | private final GraphicOverlay graphicOverlay;
95 |
96 | // True if a SurfaceTexture is being used for the preview, false if a SurfaceHolder is being
97 | // used for the preview. We want to be compatible back to Gingerbread, but SurfaceTexture
98 | // wasn't introduced until Honeycomb. Since the interface cannot use a SurfaceTexture, if the
99 | // developer wants to display a preview we must use a SurfaceHolder. If the developer doesn't
100 | // want to display a preview we use a SurfaceTexture if we are running at least Honeycomb.
101 | private boolean usingSurfaceTexture;
102 |
103 | /**
104 | * Dedicated thread and associated runnable for calling into the detector with frames, as the
105 | * frames become available from the camera.
106 | */
107 | private Thread processingThread;
108 |
109 | private final FrameProcessingRunnable processingRunnable;
110 |
111 | private final Object processorLock = new Object();
112 | // TODO(b/74400062) Re-enable the annotaion
113 | // @GuardedBy("processorLock")
114 | private VisionImageProcessor frameProcessor;
115 |
116 | /**
117 | * Map to convert between a byte array, received from the camera, and its associated byte buffer.
118 | * We use byte buffers internally because this is a more efficient way to call into native code
119 | * later (avoids a potential copy).
120 | *
121 | *
Note: uses IdentityHashMap here instead of HashMap because the behavior of an array's
122 | * equals, hashCode and toString methods is both useless and unexpected. IdentityHashMap enforces
123 | * identity ('==') check on the keys.
124 | */
125 | private final Map bytesToByteBuffer = new IdentityHashMap<>();
126 |
127 | public CameraSource(Activity activity, GraphicOverlay overlay) {
128 | this.activity = activity;
129 | graphicOverlay = overlay;
130 | graphicOverlay.clear();
131 | processingRunnable = new FrameProcessingRunnable();
132 | }
133 |
134 | // ==============================================================================================
135 | // Public
136 | // ==============================================================================================
137 |
138 | /** Stops the camera and releases the resources of the camera and underlying detector. */
139 | public void release() {
140 | synchronized (processorLock) {
141 | stop();
142 | processingRunnable.release();
143 | cleanScreen();
144 |
145 | if (frameProcessor != null) {
146 | frameProcessor.stop();
147 | }
148 | }
149 | }
150 |
151 | /**
152 | * Opens the camera and starts sending preview frames to the underlying detector. The preview
153 | * frames are not displayed.
154 | *
155 | * @throws IOException if the camera's preview texture or display could not be initialized
156 | */
157 | @RequiresPermission(Manifest.permission.CAMERA)
158 | public synchronized CameraSource start() throws IOException {
159 | if (camera != null) {
160 | return this;
161 | }
162 |
163 | camera = createCamera();
164 | dummySurfaceTexture = new SurfaceTexture(DUMMY_TEXTURE_NAME);
165 | camera.setPreviewTexture(dummySurfaceTexture);
166 | usingSurfaceTexture = true;
167 | camera.startPreview();
168 |
169 | processingThread = new Thread(processingRunnable);
170 | processingRunnable.setActive(true);
171 | processingThread.start();
172 | return this;
173 | }
174 |
175 | /**
176 | * Opens the camera and starts sending preview frames to the underlying detector. The supplied
177 | * surface holder is used for the preview so frames can be displayed to the user.
178 | *
179 | * @param surfaceHolder the surface holder to use for the preview frames
180 | * @throws IOException if the supplied surface holder could not be used as the preview display
181 | */
182 | @RequiresPermission(Manifest.permission.CAMERA)
183 | public synchronized CameraSource start(SurfaceHolder surfaceHolder) throws IOException {
184 | if (camera != null) {
185 | return this;
186 | }
187 |
188 | camera = createCamera();
189 | camera.setPreviewDisplay(surfaceHolder);
190 | camera.startPreview();
191 |
192 | processingThread = new Thread(processingRunnable);
193 | processingRunnable.setActive(true);
194 | processingThread.start();
195 |
196 | usingSurfaceTexture = false;
197 | return this;
198 | }
199 |
200 | /**
201 | * Closes the camera and stops sending frames to the underlying frame detector.
202 | *
203 | *
This camera source may be restarted again by calling {@link #start()} or {@link
204 | * #start(SurfaceHolder)}.
205 | *
206 | *
Call {@link #release()} instead to completely shut down this camera source and release the
207 | * resources of the underlying detector.
208 | */
209 | public synchronized void stop() {
210 | processingRunnable.setActive(false);
211 | if (processingThread != null) {
212 | try {
213 | // Wait for the thread to complete to ensure that we can't have multiple threads
214 | // executing at the same time (i.e., which would happen if we called start too
215 | // quickly after stop).
216 | processingThread.join();
217 | } catch (InterruptedException e) {
218 | Log.d(TAG, "Frame processing thread interrupted on release.");
219 | }
220 | processingThread = null;
221 | }
222 |
223 | if (camera != null) {
224 | camera.stopPreview();
225 | camera.setPreviewCallbackWithBuffer(null);
226 | try {
227 | if (usingSurfaceTexture) {
228 | camera.setPreviewTexture(null);
229 | } else {
230 | camera.setPreviewDisplay(null);
231 | }
232 | } catch (Exception e) {
233 | Log.e(TAG, "Failed to clear camera preview: " + e);
234 | }
235 | camera.release();
236 | camera = null;
237 | }
238 |
239 | // Release the reference to any image buffers, since these will no longer be in use.
240 | bytesToByteBuffer.clear();
241 | }
242 |
243 | /** Changes the facing of the camera. */
244 | public synchronized void setFacing(int facing) {
245 | if ((facing != CAMERA_FACING_BACK) && (facing != CAMERA_FACING_FRONT)) {
246 | throw new IllegalArgumentException("Invalid camera: " + facing);
247 | }
248 | this.facing = facing;
249 | }
250 |
251 | /** Returns the preview size that is currently in use by the underlying camera. */
252 | public Size getPreviewSize() {
253 | return previewSize;
254 | }
255 |
256 | /**
257 | * Returns the selected camera; one of {@link #CAMERA_FACING_BACK} or {@link
258 | * #CAMERA_FACING_FRONT}.
259 | */
260 | public int getCameraFacing() {
261 | return facing;
262 | }
263 |
264 | /**
265 | * Opens the camera and applies the user settings.
266 | *
267 | * @throws IOException if camera cannot be found or preview cannot be processed
268 | */
269 | @SuppressLint("InlinedApi")
270 | private Camera createCamera() throws IOException {
271 | int requestedCameraId = getIdForRequestedCamera(facing);
272 | if (requestedCameraId == -1) {
273 | throw new IOException("Could not find requested camera.");
274 | }
275 | Camera camera = Camera.open(requestedCameraId);
276 |
277 | SizePair sizePair = selectSizePair(camera, requestedPreviewWidth, requestedPreviewHeight);
278 | if (sizePair == null) {
279 | throw new IOException("Could not find suitable preview size.");
280 | }
281 | Size pictureSize = sizePair.pictureSize();
282 | previewSize = sizePair.previewSize();
283 |
284 | int[] previewFpsRange = selectPreviewFpsRange(camera, requestedFps);
285 | if (previewFpsRange == null) {
286 | throw new IOException("Could not find suitable preview frames per second range.");
287 | }
288 |
289 | Camera.Parameters parameters = camera.getParameters();
290 |
291 | if (pictureSize != null) {
292 | parameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
293 | }
294 | parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
295 | parameters.setPreviewFpsRange(
296 | previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
297 | previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
298 | parameters.setPreviewFormat(ImageFormat.NV21);
299 |
300 | setRotation(camera, parameters, requestedCameraId);
301 |
302 | if (requestedAutoFocus) {
303 | if (parameters
304 | .getSupportedFocusModes()
305 | .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
306 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
307 | } else {
308 | Log.i(TAG, "Camera auto focus is not supported on this device.");
309 | }
310 | }
311 |
312 | camera.setParameters(parameters);
313 |
314 | // Four frame buffers are needed for working with the camera:
315 | //
316 | // one for the frame that is currently being executed upon in doing detection
317 | // one for the next pending frame to process immediately upon completing detection
318 | // two for the frames that the camera uses to populate future preview images
319 | //
320 | // Through trial and error it appears that two free buffers, in addition to the two buffers
321 | // used in this code, are needed for the camera to work properly. Perhaps the camera has
322 | // one thread for acquiring images, and another thread for calling into user code. If only
323 | // three buffers are used, then the camera will spew thousands of warning messages when
324 | // detection takes a non-trivial amount of time.
325 | camera.setPreviewCallbackWithBuffer(new CameraPreviewCallback());
326 | camera.addCallbackBuffer(createPreviewBuffer(previewSize));
327 | camera.addCallbackBuffer(createPreviewBuffer(previewSize));
328 | camera.addCallbackBuffer(createPreviewBuffer(previewSize));
329 | camera.addCallbackBuffer(createPreviewBuffer(previewSize));
330 |
331 | return camera;
332 | }
333 |
334 | /**
335 | * Gets the id for the camera specified by the direction it is facing. Returns -1 if no such
336 | * camera was found.
337 | *
338 | * @param facing the desired camera (front-facing or rear-facing)
339 | */
340 | private static int getIdForRequestedCamera(int facing) {
341 | CameraInfo cameraInfo = new CameraInfo();
342 | for (int i = 0; i < Camera.getNumberOfCameras(); ++i) {
343 | Camera.getCameraInfo(i, cameraInfo);
344 | if (cameraInfo.facing == facing) {
345 | return i;
346 | }
347 | }
348 | return -1;
349 | }
350 |
351 | /**
352 | * Selects the most suitable preview and picture size, given the desired width and height.
353 | *
354 | *
Even though we only need to find the preview size, it's necessary to find both the preview
355 | * size and the picture size of the camera together, because these need to have the same aspect
356 | * ratio. On some hardware, if you would only set the preview size, you will get a distorted
357 | * image.
358 | *
359 | * @param camera the camera to select a preview size from
360 | * @param desiredWidth the desired width of the camera preview frames
361 | * @param desiredHeight the desired height of the camera preview frames
362 | * @return the selected preview and picture size pair
363 | */
364 | private static SizePair selectSizePair(Camera camera, int desiredWidth, int desiredHeight) {
365 | List validPreviewSizes = generateValidPreviewSizeList(camera);
366 |
367 | // The method for selecting the best size is to minimize the sum of the differences between
368 | // the desired values and the actual values for width and height. This is certainly not the
369 | // only way to select the best size, but it provides a decent tradeoff between using the
370 | // closest aspect ratio vs. using the closest pixel area.
371 | SizePair selectedPair = null;
372 | int minDiff = Integer.MAX_VALUE;
373 | for (SizePair sizePair : validPreviewSizes) {
374 | Size size = sizePair.previewSize();
375 | int diff =
376 | Math.abs(size.getWidth() - desiredWidth) + Math.abs(size.getHeight() - desiredHeight);
377 | if (diff < minDiff) {
378 | selectedPair = sizePair;
379 | minDiff = diff;
380 | }
381 | }
382 |
383 | return selectedPair;
384 | }
385 |
386 | /**
387 | * Stores a preview size and a corresponding same-aspect-ratio picture size. To avoid distorted
388 | * preview images on some devices, the picture size must be set to a size that is the same aspect
389 | * ratio as the preview size or the preview may end up being distorted. If the picture size is
390 | * null, then there is no picture size with the same aspect ratio as the preview size.
391 | */
392 | private static class SizePair {
393 | private final Size preview;
394 | private Size picture;
395 |
396 | SizePair(
397 | android.hardware.Camera.Size previewSize,
398 | @Nullable android.hardware.Camera.Size pictureSize) {
399 | preview = new Size(previewSize.width, previewSize.height);
400 | if (pictureSize != null) {
401 | picture = new Size(pictureSize.width, pictureSize.height);
402 | }
403 | }
404 |
405 | Size previewSize() {
406 | return preview;
407 | }
408 |
409 | @Nullable
410 | Size pictureSize() {
411 | return picture;
412 | }
413 | }
414 |
415 | /**
416 | * Generates a list of acceptable preview sizes. Preview sizes are not acceptable if there is not
417 | * a corresponding picture size of the same aspect ratio. If there is a corresponding picture size
418 | * of the same aspect ratio, the picture size is paired up with the preview size.
419 | *
420 | *
This is necessary because even if we don't use still pictures, the still picture size must
421 | * be set to a size that is the same aspect ratio as the preview size we choose. Otherwise, the
422 | * preview images may be distorted on some devices.
423 | */
424 | private static List generateValidPreviewSizeList(Camera camera) {
425 | Camera.Parameters parameters = camera.getParameters();
426 | List supportedPreviewSizes =
427 | parameters.getSupportedPreviewSizes();
428 | List supportedPictureSizes =
429 | parameters.getSupportedPictureSizes();
430 | List validPreviewSizes = new ArrayList<>();
431 | for (android.hardware.Camera.Size previewSize : supportedPreviewSizes) {
432 | float previewAspectRatio = (float) previewSize.width / (float) previewSize.height;
433 |
434 | // By looping through the picture sizes in order, we favor the higher resolutions.
435 | // We choose the highest resolution in order to support taking the full resolution
436 | // picture later.
437 | for (android.hardware.Camera.Size pictureSize : supportedPictureSizes) {
438 | float pictureAspectRatio = (float) pictureSize.width / (float) pictureSize.height;
439 | if (Math.abs(previewAspectRatio - pictureAspectRatio) < ASPECT_RATIO_TOLERANCE) {
440 | validPreviewSizes.add(new SizePair(previewSize, pictureSize));
441 | break;
442 | }
443 | }
444 | }
445 |
446 | // If there are no picture sizes with the same aspect ratio as any preview sizes, allow all
447 | // of the preview sizes and hope that the camera can handle it. Probably unlikely, but we
448 | // still account for it.
449 | if (validPreviewSizes.size() == 0) {
450 | Log.w(TAG, "No preview sizes have a corresponding same-aspect-ratio picture size");
451 | for (android.hardware.Camera.Size previewSize : supportedPreviewSizes) {
452 | // The null picture size will let us know that we shouldn't set a picture size.
453 | validPreviewSizes.add(new SizePair(previewSize, null));
454 | }
455 | }
456 |
457 | return validPreviewSizes;
458 | }
459 |
460 | /**
461 | * Selects the most suitable preview frames per second range, given the desired frames per second.
462 | *
463 | * @param camera the camera to select a frames per second range from
464 | * @param desiredPreviewFps the desired frames per second for the camera preview frames
465 | * @return the selected preview frames per second range
466 | */
467 | @SuppressLint("InlinedApi")
468 | private static int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {
469 | // The camera API uses integers scaled by a factor of 1000 instead of floating-point frame
470 | // rates.
471 | int desiredPreviewFpsScaled = (int) (desiredPreviewFps * 1000.0f);
472 |
473 | // The method for selecting the best range is to minimize the sum of the differences between
474 | // the desired value and the upper and lower bounds of the range. This may select a range
475 | // that the desired value is outside of, but this is often preferred. For example, if the
476 | // desired frame rate is 29.97, the range (30, 30) is probably more desirable than the
477 | // range (15, 30).
478 | int[] selectedFpsRange = null;
479 | int minDiff = Integer.MAX_VALUE;
480 | List previewFpsRangeList = camera.getParameters().getSupportedPreviewFpsRange();
481 | for (int[] range : previewFpsRangeList) {
482 | int deltaMin = desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
483 | int deltaMax = desiredPreviewFpsScaled - range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
484 | int diff = Math.abs(deltaMin) + Math.abs(deltaMax);
485 | if (diff < minDiff) {
486 | selectedFpsRange = range;
487 | minDiff = diff;
488 | }
489 | }
490 | return selectedFpsRange;
491 | }
492 |
493 | /**
494 | * Calculates the correct rotation for the given camera id and sets the rotation in the
495 | * parameters. It also sets the camera's display orientation and rotation.
496 | *
497 | * @param parameters the camera parameters for which to set the rotation
498 | * @param cameraId the camera id to set rotation based on
499 | */
500 | private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {
501 | WindowManager windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
502 | int degrees = 0;
503 | int rotation = windowManager.getDefaultDisplay().getRotation();
504 | switch (rotation) {
505 | case Surface.ROTATION_0:
506 | degrees = 0;
507 | break;
508 | case Surface.ROTATION_90:
509 | degrees = 90;
510 | break;
511 | case Surface.ROTATION_180:
512 | degrees = 180;
513 | break;
514 | case Surface.ROTATION_270:
515 | degrees = 270;
516 | break;
517 | default:
518 | Log.e(TAG, "Bad rotation value: " + rotation);
519 | }
520 |
521 | CameraInfo cameraInfo = new CameraInfo();
522 | Camera.getCameraInfo(cameraId, cameraInfo);
523 |
524 | int angle;
525 | int displayAngle;
526 | if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
527 | angle = (cameraInfo.orientation + degrees) % 360;
528 | displayAngle = (360 - angle) % 360; // compensate for it being mirrored
529 | } else { // back-facing
530 | angle = (cameraInfo.orientation - degrees + 360) % 360;
531 | displayAngle = angle;
532 | }
533 |
534 | // This corresponds to the rotation constants.
535 | this.rotation = angle / 90;
536 |
537 | camera.setDisplayOrientation(displayAngle);
538 | parameters.setRotation(angle);
539 | }
540 |
541 | /**
542 | * Creates one buffer for the camera preview callback. The size of the buffer is based off of the
543 | * camera preview size and the format of the camera image.
544 | *
545 | * @return a new preview buffer of the appropriate size for the current camera settings
546 | */
547 | @SuppressLint("InlinedApi")
548 | private byte[] createPreviewBuffer(Size previewSize) {
549 | int bitsPerPixel = ImageFormat.getBitsPerPixel(ImageFormat.NV21);
550 | long sizeInBits = (long) previewSize.getHeight() * previewSize.getWidth() * bitsPerPixel;
551 | int bufferSize = (int) Math.ceil(sizeInBits / 8.0d) + 1;
552 |
553 | // Creating the byte array this way and wrapping it, as opposed to using .allocate(),
554 | // should guarantee that there will be an array to work with.
555 | byte[] byteArray = new byte[bufferSize];
556 | ByteBuffer buffer = ByteBuffer.wrap(byteArray);
557 | if (!buffer.hasArray() || (buffer.array() != byteArray)) {
558 | // I don't think that this will ever happen. But if it does, then we wouldn't be
559 | // passing the preview content to the underlying detector later.
560 | throw new IllegalStateException("Failed to create valid buffer for camera source.");
561 | }
562 |
563 | bytesToByteBuffer.put(byteArray, buffer);
564 | return byteArray;
565 | }
566 |
567 | // ==============================================================================================
568 | // Frame processing
569 | // ==============================================================================================
570 |
571 | /** Called when the camera has a new preview frame. */
572 | private class CameraPreviewCallback implements Camera.PreviewCallback {
573 | @Override
574 | public void onPreviewFrame(byte[] data, Camera camera) {
575 | processingRunnable.setNextFrame(data, camera);
576 | }
577 | }
578 |
579 | void setMachineLearningFrameProcessor(VisionImageProcessor processor) {
580 | synchronized (processorLock) {
581 | cleanScreen();
582 | if (frameProcessor != null) {
583 | frameProcessor.stop();
584 | }
585 | frameProcessor = processor;
586 | }
587 | }
588 |
589 | /**
590 | * This runnable controls access to the underlying receiver, calling it to process frames when
591 | * available from the camera. This is designed to run detection on frames as fast as possible
592 | * (i.e., without unnecessary context switching or waiting on the next frame).
593 | *
594 | *
While detection is running on a frame, new frames may be received from the camera. As these
595 | * frames come in, the most recent frame is held onto as pending. As soon as detection and its
596 | * associated processing is done for the previous frame, detection on the mostly recently received
597 | * frame will immediately start on the same thread.
598 | */
599 | private class FrameProcessingRunnable implements Runnable {
600 |
601 | // This lock guards all of the member variables below.
602 | private final Object lock = new Object();
603 | private boolean active = true;
604 |
605 | // These pending variables hold the state associated with the new frame awaiting processing.
606 | private ByteBuffer pendingFrameData;
607 |
608 | FrameProcessingRunnable() {}
609 |
610 | /**
611 | * Releases the underlying receiver. This is only safe to do after the associated thread has
612 | * completed, which is managed in camera source's release method above.
613 | */
614 | @SuppressLint("Assert")
615 | void release() {
616 | assert (processingThread.getState() == State.TERMINATED);
617 | }
618 |
619 | /** Marks the runnable as active/not active. Signals any blocked threads to continue. */
620 | void setActive(boolean active) {
621 | synchronized (lock) {
622 | this.active = active;
623 | lock.notifyAll();
624 | }
625 | }
626 |
627 | /**
628 | * Sets the frame data received from the camera. This adds the previous unused frame buffer (if
629 | * present) back to the camera, and keeps a pending reference to the frame data for future use.
630 | */
631 | void setNextFrame(byte[] data, Camera camera) {
632 | synchronized (lock) {
633 | if (pendingFrameData != null) {
634 | camera.addCallbackBuffer(pendingFrameData.array());
635 | pendingFrameData = null;
636 | }
637 |
638 | if (!bytesToByteBuffer.containsKey(data)) {
639 | Log.d(
640 | TAG,
641 | "Skipping frame. Could not find ByteBuffer associated with the image "
642 | + "data from the camera.");
643 | return;
644 | }
645 |
646 | pendingFrameData = bytesToByteBuffer.get(data);
647 |
648 | // Notify the processor thread if it is waiting on the next frame (see below).
649 | lock.notifyAll();
650 | }
651 | }
652 |
653 | /**
654 | * As long as the processing thread is active, this executes detection on frames continuously.
655 | * The next pending frame is either immediately available or hasn't been received yet. Once it
656 | * is available, we transfer the frame info to local variables and run detection on that frame.
657 | * It immediately loops back for the next frame without pausing.
658 | *
659 | *
If detection takes longer than the time in between new frames from the camera, this will
660 | * mean that this loop will run without ever waiting on a frame, avoiding any context switching
661 | * or frame acquisition time latency.
662 | *
663 | *
If you find that this is using more CPU than you'd like, you should probably decrease the
664 | * FPS setting above to allow for some idle time in between frames.
665 | */
666 | @SuppressLint("InlinedApi")
667 | @SuppressWarnings("GuardedBy")
668 | @Override
669 | public void run() {
670 | ByteBuffer data;
671 |
672 | while (true) {
673 | synchronized (lock) {
674 | while (active && (pendingFrameData == null)) {
675 | try {
676 | // Wait for the next frame to be received from the camera, since we
677 | // don't have it yet.
678 | lock.wait();
679 | } catch (InterruptedException e) {
680 | Log.d(TAG, "Frame processing loop terminated.", e);
681 | return;
682 | }
683 | }
684 |
685 | if (!active) {
686 | // Exit the loop once this camera source is stopped or released. We check
687 | // this here, immediately after the wait() above, to handle the case where
688 | // setActive(false) had been called, triggering the termination of this
689 | // loop.
690 | return;
691 | }
692 |
693 | // Hold onto the frame data locally, so that we can use this for detection
694 | // below. We need to clear pendingFrameData to ensure that this buffer isn't
695 | // recycled back to the camera before we are done using that data.
696 | data = pendingFrameData;
697 | pendingFrameData = null;
698 | }
699 |
700 | // The code below needs to run outside of synchronization, because this will allow
701 | // the camera to add pending frame(s) while we are running detection on the current
702 | // frame.
703 |
704 | try {
705 | synchronized (processorLock) {
706 | Log.d(TAG, "Process an image");
707 | frameProcessor.process(
708 | data,
709 | new FrameMetadata.Builder()
710 | .setWidth(previewSize.getWidth())
711 | .setHeight(previewSize.getHeight())
712 | .setRotation(rotation)
713 | .setCameraFacing(facing)
714 | .build(),
715 | graphicOverlay);
716 | }
717 | } catch (Throwable t) {
718 | Log.e(TAG, "Exception thrown from receiver.", t);
719 | } finally {
720 | camera.addCallbackBuffer(data.array());
721 | }
722 | }
723 | }
724 | }
725 |
726 | /** Cleans up graphicOverlay and child classes can do their cleanups as well . */
727 | private void cleanScreen() {
728 | graphicOverlay.clear();
729 | }
730 | }
731 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/CameraSourcePreview.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.content.Context;
17 | import android.content.res.Configuration;
18 | import android.util.AttributeSet;
19 | import android.util.Log;
20 | import android.view.SurfaceHolder;
21 | import android.view.SurfaceView;
22 | import android.view.ViewGroup;
23 |
24 | import com.google.android.gms.common.images.Size;
25 |
26 | import java.io.IOException;
27 |
28 | /** Preview the camera image in the screen. */
29 | public class CameraSourcePreview extends ViewGroup {
30 | private static final String TAG = "MIDemoApp:Preview";
31 |
32 | private Context context;
33 | private SurfaceView surfaceView;
34 | private boolean startRequested;
35 | private boolean surfaceAvailable;
36 | private CameraSource cameraSource;
37 |
38 | private GraphicOverlay overlay;
39 |
40 | public CameraSourcePreview(Context context, AttributeSet attrs) {
41 | super(context, attrs);
42 | this.context = context;
43 | startRequested = false;
44 | surfaceAvailable = false;
45 |
46 | surfaceView = new SurfaceView(context);
47 | surfaceView.getHolder().addCallback(new SurfaceCallback());
48 | addView(surfaceView);
49 | }
50 |
51 | public void start(CameraSource cameraSource) throws IOException {
52 | if (cameraSource == null) {
53 | stop();
54 | }
55 |
56 | this.cameraSource = cameraSource;
57 |
58 | if (this.cameraSource != null) {
59 | startRequested = true;
60 | startIfReady();
61 | }
62 | }
63 |
64 | public void start(CameraSource cameraSource, GraphicOverlay overlay) throws IOException {
65 | this.overlay = overlay;
66 | start(cameraSource);
67 | }
68 |
69 | public void stop() {
70 | if (cameraSource != null) {
71 | cameraSource.stop();
72 | }
73 | }
74 |
75 | public void release() {
76 | if (cameraSource != null) {
77 | cameraSource.release();
78 | cameraSource = null;
79 | }
80 | }
81 |
82 | private void startIfReady() throws IOException {
83 | if (startRequested && surfaceAvailable) {
84 | cameraSource.start(surfaceView.getHolder());
85 | if (overlay != null) {
86 | Size size = cameraSource.getPreviewSize();
87 | int min = Math.min(size.getWidth(), size.getHeight());
88 | int max = Math.max(size.getWidth(), size.getHeight());
89 | if (isPortraitMode()) {
90 | // Swap width and height sizes when in portrait, since it will be rotated by
91 | // 90 degrees
92 | overlay.setCameraInfo(min, max, cameraSource.getCameraFacing());
93 | } else {
94 | overlay.setCameraInfo(max, min, cameraSource.getCameraFacing());
95 | }
96 | overlay.clear();
97 | }
98 | startRequested = false;
99 | }
100 | }
101 |
102 | private class SurfaceCallback implements SurfaceHolder.Callback {
103 | @Override
104 | public void surfaceCreated(SurfaceHolder surface) {
105 | surfaceAvailable = true;
106 | try {
107 | startIfReady();
108 | } catch (IOException e) {
109 | Log.e(TAG, "Could not start camera source.", e);
110 | }
111 | }
112 |
113 | @Override
114 | public void surfaceDestroyed(SurfaceHolder surface) {
115 | surfaceAvailable = false;
116 | }
117 |
118 | @Override
119 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
120 | }
121 |
122 | @Override
123 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
124 | int width = 320;
125 | int height = 240;
126 | if (cameraSource != null) {
127 | Size size = cameraSource.getPreviewSize();
128 | if (size != null) {
129 | width = size.getWidth();
130 | height = size.getHeight();
131 | }
132 | }
133 |
134 | // Swap width and height sizes when in portrait, since it will be rotated 90 degrees
135 | if (isPortraitMode()) {
136 | int tmp = width;
137 | width = height;
138 | height = tmp;
139 | }
140 |
141 | final int layoutWidth = right - left;
142 | final int layoutHeight = bottom - top;
143 |
144 | // Computes height and width for potentially doing fit width.
145 | int childWidth = layoutWidth;
146 | int childHeight = (int) (((float) layoutWidth / (float) width) * height);
147 |
148 | // If height is too tall using fit width, does fit height instead.
149 | if (childHeight > layoutHeight) {
150 | childHeight = layoutHeight;
151 | childWidth = (int) (((float) layoutHeight / (float) height) * width);
152 | }
153 |
154 | for (int i = 0; i < getChildCount(); ++i) {
155 | getChildAt(i).layout(0, 0, childWidth, childHeight);
156 | Log.d(TAG, "Assigned view: " + i);
157 | }
158 |
159 | try {
160 | startIfReady();
161 | } catch (IOException e) {
162 | Log.e(TAG, "Could not start camera source.", e);
163 | }
164 | }
165 |
166 | private boolean isPortraitMode() {
167 | int orientation = context.getResources().getConfiguration().orientation;
168 | if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
169 | return false;
170 | }
171 | if (orientation == Configuration.ORIENTATION_PORTRAIT) {
172 | return true;
173 | }
174 |
175 | Log.d(TAG, "isPortraitMode returning false by default");
176 | return false;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/ChooserActivity.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.content.Context;
17 | import android.content.Intent;
18 | import android.content.pm.PackageInfo;
19 | import android.content.pm.PackageManager;
20 | import android.os.Bundle;
21 | import android.support.v4.app.ActivityCompat;
22 | import android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback;
23 | import android.support.v4.content.ContextCompat;
24 | import android.support.v7.app.AppCompatActivity;
25 | import android.util.Log;
26 | import android.view.LayoutInflater;
27 | import android.view.View;
28 | import android.view.ViewGroup;
29 | import android.widget.AdapterView;
30 | import android.widget.ArrayAdapter;
31 | import android.widget.Button;
32 | import android.widget.ListView;
33 | import android.widget.TextView;
34 |
35 | import java.util.ArrayList;
36 | import java.util.List;
37 |
38 | /**
39 | * Demo app chooser which takes care of runtime permission requesting and allows you to pick from
40 | * all available testing Activities.
41 | */
42 | public final class ChooserActivity extends AppCompatActivity
43 | implements OnRequestPermissionsResultCallback, AdapterView.OnItemClickListener {
44 | private static final String TAG = "ChooserActivity";
45 | private static final int PERMISSION_REQUESTS = 1;
46 | public Button startButton;
47 |
48 | private static final Class>[] CLASSES =
49 | new Class>[] {
50 | LivePreviewActivity.class//, StillImageActivity.class,
51 | };
52 |
53 | private static final int[] DESCRIPTION_IDS =
54 | new int[] {
55 | R.string.desc_camera_source_activity, R.string.desc_still_image_activity,
56 | };
57 |
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | Log.d(TAG, "onCreate");
62 |
63 | setContentView(R.layout.activity_chooser);
64 |
65 | startButton = (Button) findViewById(R.id.start);
66 |
67 | startButton.setOnClickListener(new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | Class> clicked = CLASSES[0];
71 | startActivity(new Intent( getApplicationContext(), clicked));
72 | }
73 | });
74 |
75 | // Set up ListView and Adapter
76 | ListView listView = (ListView) findViewById(R.id.test_activity_list_view);
77 |
78 | MyArrayAdapter adapter = new MyArrayAdapter(this, android.R.layout.simple_list_item_2, CLASSES);
79 | adapter.setDescriptionIds(DESCRIPTION_IDS);
80 |
81 | listView.setAdapter(adapter);
82 | listView.setOnItemClickListener(this);
83 |
84 | if (!allPermissionsGranted()) {
85 | getRuntimePermissions();
86 | }
87 | }
88 |
89 | @Override
90 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
91 | Class> clicked = CLASSES[position];
92 | startActivity(new Intent(this, clicked));
93 | }
94 |
95 | private String[] getRequiredPermissions() {
96 | try {
97 | PackageInfo info =
98 | this.getPackageManager()
99 | .getPackageInfo(this.getPackageName(), PackageManager.GET_PERMISSIONS);
100 | String[] ps = info.requestedPermissions;
101 | if (ps != null && ps.length > 0) {
102 | return ps;
103 | } else {
104 | return new String[0];
105 | }
106 | } catch (Exception e) {
107 | return new String[0];
108 | }
109 | }
110 |
111 | private boolean allPermissionsGranted() {
112 | for (String permission : getRequiredPermissions()) {
113 | if (!isPermissionGranted(this, permission)) {
114 | return false;
115 | }
116 | }
117 | return true;
118 | }
119 |
120 | private void getRuntimePermissions() {
121 | List allNeededPermissions = new ArrayList<>();
122 | for (String permission : getRequiredPermissions()) {
123 | if (!isPermissionGranted(this, permission)) {
124 | allNeededPermissions.add(permission);
125 | }
126 | }
127 |
128 | if (!allNeededPermissions.isEmpty()) {
129 | ActivityCompat.requestPermissions(
130 | this, allNeededPermissions.toArray(new String[0]), PERMISSION_REQUESTS);
131 | }
132 | }
133 |
134 | private static boolean isPermissionGranted(Context context, String permission) {
135 | if (ContextCompat.checkSelfPermission(context, permission)
136 | == PackageManager.PERMISSION_GRANTED) {
137 | Log.i(TAG, "Permission granted: " + permission);
138 | return true;
139 | }
140 | Log.i(TAG, "Permission NOT granted: " + permission);
141 | return false;
142 | }
143 |
144 | private static class MyArrayAdapter extends ArrayAdapter> {
145 |
146 | private final Context context;
147 | private final Class>[] classes;
148 | private int[] descriptionIds;
149 |
150 | public MyArrayAdapter(Context context, int resource, Class>[] objects) {
151 | super(context, resource, objects);
152 |
153 | this.context = context;
154 | classes = objects;
155 | }
156 |
157 | @Override
158 | public View getView(int position, View convertView, ViewGroup parent) {
159 | View view = convertView;
160 |
161 | if (convertView == null) {
162 | LayoutInflater inflater =
163 | (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
164 | view = inflater.inflate(android.R.layout.simple_list_item_2, null);
165 | }
166 |
167 | // ((TextView) view.findViewById(android.R.id.text1)).setText(classes[position].getSimpleName());
168 | ((TextView) view.findViewById(android.R.id.text1)).setText("START");
169 | ((TextView) view.findViewById(android.R.id.text2)).setText(descriptionIds[position]);
170 |
171 | return view;
172 | }
173 |
174 | public void setDescriptionIds(int[] descriptionIds) {
175 | this.descriptionIds = descriptionIds;
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/FrameMetadata.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | /** Describing a frame info. */
17 | public class FrameMetadata {
18 |
19 | private final int width;
20 | private final int height;
21 | private final int rotation;
22 | private final int cameraFacing;
23 |
24 | public int getWidth() {
25 | return width;
26 | }
27 |
28 | public int getHeight() {
29 | return height;
30 | }
31 |
32 | public int getRotation() {
33 | return rotation;
34 | }
35 |
36 | public int getCameraFacing() {
37 | return cameraFacing;
38 | }
39 |
40 | private FrameMetadata(int width, int height, int rotation, int facing) {
41 | this.width = width;
42 | this.height = height;
43 | this.rotation = rotation;
44 | cameraFacing = facing;
45 | }
46 |
47 | /** Builder of {@link FrameMetadata}. */
48 | public static class Builder {
49 |
50 | private int width;
51 | private int height;
52 | private int rotation;
53 | private int cameraFacing;
54 |
55 | public Builder setWidth(int width) {
56 | this.width = width;
57 | return this;
58 | }
59 |
60 | public Builder setHeight(int height) {
61 | this.height = height;
62 | return this;
63 | }
64 |
65 | public Builder setRotation(int rotation) {
66 | this.rotation = rotation;
67 | return this;
68 | }
69 |
70 | public Builder setCameraFacing(int facing) {
71 | cameraFacing = facing;
72 | return this;
73 | }
74 |
75 | public FrameMetadata build() {
76 | return new FrameMetadata(width, height, rotation, cameraFacing);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/GraphicOverlay.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.content.Context;
17 | import android.graphics.Canvas;
18 | import android.hardware.camera2.CameraCharacteristics;
19 | import android.util.AttributeSet;
20 | import android.view.View;
21 |
22 | import com.google.android.gms.vision.CameraSource;
23 |
24 | import java.util.HashSet;
25 | import java.util.Set;
26 |
27 | /**
28 | * A view which renders a series of custom graphics to be overlayed on top of an associated preview
29 | * (i.e., the camera preview). The creator can add graphics objects, update the objects, and remove
30 | * them, triggering the appropriate drawing and invalidation within the view.
31 | *
32 | *
Supports scaling and mirroring of the graphics relative the camera's preview properties. The
33 | * idea is that detection items are expressed in terms of a preview size, but need to be scaled up
34 | * to the full view size, and also mirrored in the case of the front-facing camera.
35 | *
36 | *
Associated {@link Graphic} items should use the following methods to convert to view
37 | * coordinates for the graphics that are drawn:
38 | *
39 | *
40 | *
{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the
41 | * supplied value from the preview scale to the view scale.
42 | *
{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the
43 | * coordinate from the preview's coordinate system to the view coordinate system.
44 | *
45 | */
46 | public class GraphicOverlay extends View {
47 | private final Object lock = new Object();
48 | private int previewWidth;
49 | private float widthScaleFactor = 1.0f;
50 | private int previewHeight;
51 | private float heightScaleFactor = 1.0f;
52 | private int facing = CameraSource.CAMERA_FACING_BACK;
53 | private Set graphics = new HashSet<>();
54 |
55 | // private int mRatioWidth = 0;
56 | // private int mRatioHeight = 0;
57 |
58 | /**
59 | * Base class for a custom graphics object to be rendered within the graphic overlay. Subclass
60 | * this and implement the {@link Graphic#draw(Canvas)} method to define the graphics element. Add
61 | * instances to the overlay using {@link GraphicOverlay#add(Graphic)}.
62 | */
63 | public abstract static class Graphic {
64 | private GraphicOverlay overlay;
65 |
66 | public Graphic(GraphicOverlay overlay) {
67 | this.overlay = overlay;
68 | }
69 |
70 | /**
71 | * Draw the graphic on the supplied canvas. Drawing should use the following methods to convert
72 | * to view coordinates for the graphics that are drawn:
73 | *
74 | *
75 | *
{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of the
76 | * supplied value from the preview scale to the view scale.
77 | *
{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the
78 | * coordinate from the preview's coordinate system to the view coordinate system.
79 | *
80 | *
81 | * @param canvas drawing canvas
82 | */
83 | public abstract void draw(Canvas canvas);
84 |
85 | /**
86 | * Adjusts a horizontal value of the supplied value from the preview scale to the view scale.
87 | */
88 | public float scaleX(float horizontal) {
89 | return horizontal * overlay.widthScaleFactor;
90 | }
91 |
92 | /** Adjusts a vertical value of the supplied value from the preview scale to the view scale. */
93 | public float scaleY(float vertical) {
94 | return vertical * overlay.heightScaleFactor;
95 | }
96 |
97 | /** Returns the application context of the app. */
98 | public Context getApplicationContext() {
99 | return overlay.getContext().getApplicationContext();
100 | }
101 |
102 | /**
103 | * Adjusts the x coordinate from the preview's coordinate system to the view coordinate system.
104 | */
105 | public float translateX(float x) {
106 | if (overlay.facing == CameraSource.CAMERA_FACING_FRONT) {
107 | return overlay.getWidth() - scaleX(x);
108 | } else {
109 | return scaleX(x);
110 | }
111 | }
112 |
113 | /**
114 | * Adjusts the y coordinate from the preview's coordinate system to the view coordinate system.
115 | */
116 | public float translateY(float y) {
117 | return scaleY(y);
118 | }
119 |
120 | public void postInvalidate() {
121 | overlay.postInvalidate();
122 | }
123 | }
124 |
125 | public GraphicOverlay(Context context, AttributeSet attrs) {
126 | super(context, attrs);
127 | }
128 |
129 | /** Removes all graphics from the overlay. */
130 | public void clear() {
131 | synchronized (lock) {
132 | graphics.clear();
133 | }
134 | postInvalidate();
135 | }
136 |
137 | /** Adds a graphic to the overlay. */
138 | public void add(Graphic graphic) {
139 | synchronized (lock) {
140 | graphics.add(graphic);
141 | }
142 | postInvalidate();
143 | }
144 |
145 | /** Removes a graphic from the overlay. */
146 | public void remove(Graphic graphic) {
147 | synchronized (lock) {
148 | graphics.remove(graphic);
149 | }
150 | postInvalidate();
151 | }
152 |
153 | /**
154 | * Sets the camera attributes for size and facing direction, which informs how to transform image
155 | * coordinates later.
156 | */
157 | public void setCameraInfo(int previewWidth, int previewHeight, int facing) {
158 | synchronized (lock) {
159 | this.previewWidth = previewWidth;
160 | this.previewHeight = previewHeight;
161 | this.facing = facing;
162 | }
163 | postInvalidate();
164 | }
165 |
166 | /** Draws the overlay with its associated graphic objects. */
167 | @Override
168 | protected void onDraw(Canvas canvas) {
169 | super.onDraw(canvas);
170 |
171 | synchronized (lock) {
172 | if ((previewWidth != 0) && (previewHeight != 0)) {
173 | widthScaleFactor = (float) canvas.getWidth() / (float) previewWidth;
174 | heightScaleFactor = (float) canvas.getHeight() / (float) previewHeight;
175 | }
176 |
177 | for (Graphic graphic : graphics) {
178 | graphic.draw(canvas);
179 | }
180 | }
181 | }
182 |
183 | // /**
184 | // * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
185 | // * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
186 | // * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
187 | // *
188 | // * @param width Relative horizontal size
189 | // * @param height Relative vertical size
190 | // */
191 | // public void setAspectRatio(int width, int height) {
192 | // if (width < 0 || height < 0) {
193 | // throw new IllegalArgumentException("Size cannot be negative.");
194 | // }
195 | // mRatioWidth = width;
196 | // mRatioHeight = height;
197 | // requestLayout();
198 | // }
199 | //
200 | // @Override
201 | // protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
202 | // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
203 | // int width = MeasureSpec.getSize(widthMeasureSpec);
204 | // int height = MeasureSpec.getSize(heightMeasureSpec);
205 | // if (0 == mRatioWidth || 0 == mRatioHeight) {
206 | // setMeasuredDimension(width, height);
207 | // } else {
208 | // if (width < height * mRatioWidth / mRatioHeight) {
209 | // setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
210 | // } else {
211 | // setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
212 | // }
213 | // }
214 | // }
215 | }
216 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/LivePreviewActivity.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.content.Context;
17 | import android.content.pm.PackageInfo;
18 | import android.content.pm.PackageManager;
19 | import android.os.Bundle;
20 | import android.support.v4.app.ActivityCompat;
21 | import android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback;
22 | import android.support.v4.content.ContextCompat;
23 | import android.support.v7.app.AppCompatActivity;
24 | import android.util.Log;
25 | import android.view.View;
26 | import android.widget.AdapterView;
27 | import android.widget.AdapterView.OnItemSelectedListener;
28 | import android.widget.ArrayAdapter;
29 | import android.widget.CompoundButton;
30 | import android.widget.Spinner;
31 | import android.widget.ToggleButton;
32 |
33 | import com.google.android.gms.common.annotation.KeepName;
34 | import com.google.firebase.ml.common.FirebaseMLException;
35 | import com.google.firebase.samples.apps.mlkit.barcodescanning.BarcodeScanningProcessor;
36 | import com.google.firebase.samples.apps.mlkit.custommodel.CustomImageClassifierProcessor;
37 | import com.google.firebase.samples.apps.mlkit.facedetection.FaceDetectionProcessor;
38 | import com.google.firebase.samples.apps.mlkit.imagelabeling.ImageLabelingProcessor;
39 | import com.google.firebase.samples.apps.mlkit.textrecognition.TextRecognitionProcessor;
40 |
41 | import java.io.IOException;
42 | import java.util.ArrayList;
43 | import java.util.List;
44 |
45 | /** Demo app showing the various features of ML Kit for Firebase. This class is used to
46 | * set up continuous frame processing on frames from a camera source. */
47 | @KeepName
48 | public final class LivePreviewActivity extends AppCompatActivity
49 | implements OnRequestPermissionsResultCallback,
50 | OnItemSelectedListener,
51 | CompoundButton.OnCheckedChangeListener {
52 | private static final String FACE_DETECTION = "Face Detection";
53 | private static final String TEXT_DETECTION = "Text Detection";
54 | private static final String BARCODE_DETECTION = "Barcode Detection";
55 | private static final String IMAGE_LABEL_DETECTION = "Label Detection";
56 | private static final String CLASSIFICATION = "Classification";
57 | private static final String TAG = "LivePreviewActivity";
58 | private static final int PERMISSION_REQUESTS = 1;
59 |
60 | private CameraSource cameraSource = null;
61 | private CameraSourcePreview preview;
62 | private GraphicOverlay graphicOverlay;
63 | private String selectedModel = FACE_DETECTION;
64 |
65 | @Override
66 | protected void onCreate(Bundle savedInstanceState) {
67 | super.onCreate(savedInstanceState);
68 | Log.d(TAG, "onCreate");
69 |
70 | setContentView(R.layout.activity_live_preview);
71 |
72 | preview = (CameraSourcePreview) findViewById(R.id.firePreview);
73 | if (preview == null) {
74 | Log.d(TAG, "Preview is null");
75 | }
76 | graphicOverlay = (GraphicOverlay) findViewById(R.id.fireFaceOverlay);
77 | if (graphicOverlay == null) {
78 | Log.d(TAG, "graphicOverlay is null");
79 | }
80 |
81 | Spinner spinner = (Spinner) findViewById(R.id.spinner);
82 | List options = new ArrayList<>();
83 | options.add(FACE_DETECTION);
84 | options.add(TEXT_DETECTION);
85 | options.add(BARCODE_DETECTION);
86 | options.add(IMAGE_LABEL_DETECTION);
87 | options.add(CLASSIFICATION);
88 | // Creating adapter for spinner
89 | ArrayAdapter dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);
90 | // Drop down layout style - list view with radio button
91 | dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
92 | // attaching data adapter to spinner
93 | spinner.setAdapter(dataAdapter);
94 | spinner.setOnItemSelectedListener(this);
95 |
96 | ToggleButton facingSwitch = (ToggleButton) findViewById(R.id.facingswitch);
97 | facingSwitch.setOnCheckedChangeListener(this);
98 |
99 | if (allPermissionsGranted()) {
100 | createCameraSource(selectedModel);
101 | } else {
102 | getRuntimePermissions();
103 | }
104 | }
105 |
106 | @Override
107 | public synchronized void onItemSelected(AdapterView> parent, View view, int pos, long id) {
108 | // An item was selected. You can retrieve the selected item using
109 | // parent.getItemAtPosition(pos)
110 | selectedModel = parent.getItemAtPosition(pos).toString();
111 | Log.d(TAG, "Selected model: " + selectedModel);
112 | preview.stop();
113 | if (allPermissionsGranted()) {
114 | createCameraSource(selectedModel);
115 | startCameraSource();
116 | } else {
117 | getRuntimePermissions();
118 | }
119 | }
120 |
121 | @Override
122 | public void onNothingSelected(AdapterView> parent) {
123 | // Do nothing.
124 | }
125 |
126 | @Override
127 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
128 | Log.d(TAG, "Set facing");
129 | if (cameraSource != null) {
130 | if (isChecked) {
131 | cameraSource.setFacing(CameraSource.CAMERA_FACING_FRONT);
132 | } else {
133 | cameraSource.setFacing(CameraSource.CAMERA_FACING_BACK);
134 | }
135 | }
136 | preview.stop();
137 | startCameraSource();
138 | }
139 |
140 | private void createCameraSource(String model) {
141 | // If there's no existing cameraSource, create one.
142 | if (cameraSource == null) {
143 | cameraSource = new CameraSource(this, graphicOverlay);
144 | }
145 |
146 | try {
147 | switch (model) {
148 | case CLASSIFICATION:
149 | Log.i(TAG, "Using Custom Image Classifier Processor");
150 | cameraSource.setMachineLearningFrameProcessor(new CustomImageClassifierProcessor(this));
151 | break;
152 | case TEXT_DETECTION:
153 | Log.i(TAG, "Using Text Detector Processor");
154 | cameraSource.setMachineLearningFrameProcessor(new TextRecognitionProcessor());
155 | break;
156 | case FACE_DETECTION:
157 | Log.i(TAG, "Using Face Detector Processor");
158 | cameraSource.setMachineLearningFrameProcessor(new FaceDetectionProcessor());
159 | break;
160 | case BARCODE_DETECTION:
161 | Log.i(TAG, "Using Barcode Detector Processor");
162 | cameraSource.setMachineLearningFrameProcessor(new BarcodeScanningProcessor());
163 | break;
164 | case IMAGE_LABEL_DETECTION:
165 | Log.i(TAG, "Using Image Label Detector Processor");
166 | cameraSource.setMachineLearningFrameProcessor(new ImageLabelingProcessor());
167 | break;
168 | default:
169 | Log.e(TAG, "Unknown model: " + model);
170 | }
171 | } catch (FirebaseMLException e) {
172 | Log.e(TAG, "can not create camera source: " + model);
173 | }
174 | }
175 |
176 | /**
177 | * Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet
178 | * (e.g., because onResume was called before the camera source was created), this will be called
179 | * again when the camera source is created.
180 | */
181 | private void startCameraSource() {
182 | if (cameraSource != null) {
183 | try {
184 | if (preview == null) {
185 | Log.d(TAG, "resume: Preview is null");
186 | }
187 | if (graphicOverlay == null) {
188 | Log.d(TAG, "resume: graphOverlay is null");
189 | }
190 | preview.start(cameraSource, graphicOverlay);
191 | } catch (IOException e) {
192 | Log.e(TAG, "Unable to start camera source.", e);
193 | cameraSource.release();
194 | cameraSource = null;
195 | }
196 | }
197 | }
198 |
199 | @Override
200 | public void onResume() {
201 | super.onResume();
202 | Log.d(TAG, "onResume");
203 | startCameraSource();
204 | }
205 |
206 | /** Stops the camera. */
207 | @Override
208 | protected void onPause() {
209 | super.onPause();
210 | preview.stop();
211 | }
212 |
213 | @Override
214 | public void onDestroy() {
215 | super.onDestroy();
216 | if (cameraSource != null) {
217 | cameraSource.release();
218 | }
219 | }
220 |
221 | private String[] getRequiredPermissions() {
222 | try {
223 | PackageInfo info =
224 | this.getPackageManager()
225 | .getPackageInfo(this.getPackageName(), PackageManager.GET_PERMISSIONS);
226 | String[] ps = info.requestedPermissions;
227 | if (ps != null && ps.length > 0) {
228 | return ps;
229 | } else {
230 | return new String[0];
231 | }
232 | } catch (Exception e) {
233 | return new String[0];
234 | }
235 | }
236 |
237 | private boolean allPermissionsGranted() {
238 | for (String permission : getRequiredPermissions()) {
239 | if (!isPermissionGranted(this, permission)) {
240 | return false;
241 | }
242 | }
243 | return true;
244 | }
245 |
246 | private void getRuntimePermissions() {
247 | List allNeededPermissions = new ArrayList<>();
248 | for (String permission : getRequiredPermissions()) {
249 | if (!isPermissionGranted(this, permission)) {
250 | allNeededPermissions.add(permission);
251 | }
252 | }
253 |
254 | if (!allNeededPermissions.isEmpty()) {
255 | ActivityCompat.requestPermissions(
256 | this, allNeededPermissions.toArray(new String[0]), PERMISSION_REQUESTS);
257 | }
258 | }
259 |
260 | @Override
261 | public void onRequestPermissionsResult(
262 | int requestCode, String[] permissions, int[] grantResults) {
263 | Log.i(TAG, "Permission granted!");
264 | if (allPermissionsGranted()) {
265 | createCameraSource(selectedModel);
266 | }
267 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
268 | }
269 |
270 | private static boolean isPermissionGranted(Context context, String permission) {
271 | if (ContextCompat.checkSelfPermission(context, permission)
272 | == PackageManager.PERMISSION_GRANTED) {
273 | Log.i(TAG, "Permission granted: " + permission);
274 | return true;
275 | }
276 | Log.i(TAG, "Permission NOT granted: " + permission);
277 | return false;
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/StillImageActivity.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.content.ContentValues;
17 | import android.content.Intent;
18 | import android.content.res.Configuration;
19 | import android.graphics.Bitmap;
20 | import android.net.Uri;
21 | import android.os.Bundle;
22 | import android.provider.MediaStore;
23 | import android.support.v7.app.AppCompatActivity;
24 | import android.util.Log;
25 | import android.util.Pair;
26 | import android.view.MenuInflater;
27 | import android.view.MenuItem;
28 | import android.view.View;
29 | import android.view.View.OnClickListener;
30 | import android.widget.AdapterView;
31 | import android.widget.AdapterView.OnItemSelectedListener;
32 | import android.widget.ArrayAdapter;
33 | import android.widget.Button;
34 | import android.widget.ImageView;
35 | import android.widget.PopupMenu;
36 | import android.widget.PopupMenu.OnMenuItemClickListener;
37 | import android.widget.Spinner;
38 |
39 | import com.google.android.gms.common.annotation.KeepName;
40 | import com.google.firebase.samples.apps.mlkit.cloudimagelabeling.CloudImageLabelingProcessor;
41 | import com.google.firebase.samples.apps.mlkit.cloudlandmarkrecognition.CloudLandmarkRecognitionProcessor;
42 | import com.google.firebase.samples.apps.mlkit.cloudtextrecognition.CloudDocumentTextRecognitionProcessor;
43 |
44 |
45 | import com.google.firebase.samples.apps.mlkit.cloudtextrecognition.CloudTextRecognitionProcessor;
46 |
47 | import java.io.IOException;
48 | import java.util.ArrayList;
49 | import java.util.List;
50 |
51 | /** Activity demonstrating different image detector features with a still image from camera. */
52 | @KeepName
53 | public final class StillImageActivity extends AppCompatActivity {
54 |
55 | private static final String TAG = "StillImageActivity";
56 |
57 | private static final String CLOUD_LABEL_DETECTION = "Cloud Label";
58 | private static final String CLOUD_LANDMARK_DETECTION = "Landmark";
59 | private static final String CLOUD_TEXT_DETECTION = "Cloud Text";
60 | private static final String CLOUD_DOCUMENT_TEXT_DETECTION = "Doc Text";
61 |
62 | private static final String SIZE_PREVIEW = "w:max"; // Available on-screen width.
63 | private static final String SIZE_1024_768 = "w:1024"; // ~1024*768 in a normal ratio
64 | private static final String SIZE_640_480 = "w:640"; // ~640*480 in a normal ratio
65 |
66 | private static final String KEY_IMAGE_URI = "com.googletest.firebase.ml.demo.KEY_IMAGE_URI";
67 | private static final String KEY_IMAGE_MAX_WIDTH =
68 | "com.googletest.firebase.ml.demo.KEY_IMAGE_MAX_WIDTH";
69 | private static final String KEY_IMAGE_MAX_HEIGHT =
70 | "com.googletest.firebase.ml.demo.KEY_IMAGE_MAX_HEIGHT";
71 | private static final String KEY_SELECTED_SIZE =
72 | "com.googletest.firebase.ml.demo.KEY_SELECTED_SIZE";
73 |
74 | private static final int REQUEST_IMAGE_CAPTURE = 1001;
75 | private static final int REQUEST_CHOOSE_IMAGE = 1002;
76 |
77 | private Button getImageButton;
78 | private ImageView preview;
79 | private GraphicOverlay graphicOverlay;
80 | private String selectedMode = CLOUD_LABEL_DETECTION;
81 | private String selectedSize = SIZE_PREVIEW;
82 |
83 | boolean isLandScape;
84 |
85 | private Uri imageUri;
86 | // Max width (portrait mode)
87 | private Integer imageMaxWidth;
88 | // Max height (portrait mode)
89 | private Integer imageMaxHeight;
90 | private Bitmap bitmapForDetection;
91 | private VisionImageProcessor imageProcessor;
92 |
93 | @Override
94 | protected void onCreate(Bundle savedInstanceState) {
95 | super.onCreate(savedInstanceState);
96 |
97 | setContentView(R.layout.activity_still_image);
98 |
99 | getImageButton = (Button) findViewById(R.id.getImageButton);
100 | getImageButton.setOnClickListener(
101 | new OnClickListener() {
102 | @Override
103 | public void onClick(View view) {
104 | // Menu for selecting either: a) take new photo b) select from existing
105 | PopupMenu popup = new PopupMenu(StillImageActivity.this, view);
106 | popup.setOnMenuItemClickListener(
107 | new OnMenuItemClickListener() {
108 | @Override
109 | public boolean onMenuItemClick(MenuItem menuItem) {
110 | switch (menuItem.getItemId()) {
111 | case R.id.select_images_from_local:
112 | startChooseImageIntentForResult();
113 | return true;
114 | case R.id.take_photo_using_camera:
115 | startCameraIntentForResult();
116 | return true;
117 | default:
118 | return false;
119 | }
120 | }
121 | });
122 |
123 | MenuInflater inflater = popup.getMenuInflater();
124 | inflater.inflate(R.menu.camera_button_menu, popup.getMenu());
125 | popup.show();
126 | }
127 | });
128 | preview = (ImageView) findViewById(R.id.previewPane);
129 | if (preview == null) {
130 | Log.d(TAG, "Preview is null");
131 | }
132 | graphicOverlay = (GraphicOverlay) findViewById(R.id.previewOverlay);
133 | if (graphicOverlay == null) {
134 | Log.d(TAG, "graphicOverlay is null");
135 | }
136 |
137 | populateFeatureSelector();
138 | populateSizeSelector();
139 |
140 | createImageProcessor();
141 |
142 | isLandScape =
143 | (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
144 |
145 | if (savedInstanceState != null) {
146 | imageUri = savedInstanceState.getParcelable(KEY_IMAGE_URI);
147 | imageMaxWidth = savedInstanceState.getInt(KEY_IMAGE_MAX_WIDTH);
148 | imageMaxHeight = savedInstanceState.getInt(KEY_IMAGE_MAX_HEIGHT);
149 | selectedSize = savedInstanceState.getString(KEY_SELECTED_SIZE);
150 |
151 | if (imageUri != null) {
152 | tryReloadAndDetectInImage();
153 | }
154 | }
155 | }
156 |
157 | private void populateFeatureSelector() {
158 | Spinner featureSpinner = (Spinner) findViewById(R.id.featureSelector);
159 | List options = new ArrayList<>();
160 | options.add(CLOUD_LABEL_DETECTION);
161 | options.add(CLOUD_LANDMARK_DETECTION);
162 | options.add(CLOUD_TEXT_DETECTION);
163 | options.add(CLOUD_DOCUMENT_TEXT_DETECTION);
164 | // Creating adapter for featureSpinner
165 | ArrayAdapter dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);
166 | // Drop down layout style - list view with radio button
167 | dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
168 | // attaching data adapter to spinner
169 | featureSpinner.setAdapter(dataAdapter);
170 | featureSpinner.setOnItemSelectedListener(
171 | new OnItemSelectedListener() {
172 |
173 | @Override
174 | public void onItemSelected(
175 | AdapterView> parentView, View selectedItemView, int pos, long id) {
176 | selectedMode = parentView.getItemAtPosition(pos).toString();
177 | createImageProcessor();
178 | tryReloadAndDetectInImage();
179 | }
180 |
181 | @Override
182 | public void onNothingSelected(AdapterView> arg0) {}
183 | });
184 | }
185 |
186 | private void populateSizeSelector() {
187 | Spinner sizeSpinner = (Spinner) findViewById(R.id.sizeSelector);
188 | List options = new ArrayList<>();
189 | options.add(SIZE_PREVIEW);
190 | options.add(SIZE_1024_768);
191 | options.add(SIZE_640_480);
192 |
193 | // Creating adapter for featureSpinner
194 | ArrayAdapter dataAdapter = new ArrayAdapter<>(this, R.layout.spinner_style, options);
195 | // Drop down layout style - list view with radio button
196 | dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
197 | // attaching data adapter to spinner
198 | sizeSpinner.setAdapter(dataAdapter);
199 | sizeSpinner.setOnItemSelectedListener(
200 | new OnItemSelectedListener() {
201 |
202 | @Override
203 | public void onItemSelected(
204 | AdapterView> parentView, View selectedItemView, int pos, long id) {
205 | selectedSize = parentView.getItemAtPosition(pos).toString();
206 | tryReloadAndDetectInImage();
207 | }
208 |
209 | @Override
210 | public void onNothingSelected(AdapterView> arg0) {}
211 | });
212 | }
213 |
214 | @Override
215 | public void onSaveInstanceState(Bundle outState) {
216 | super.onSaveInstanceState(outState);
217 |
218 | outState.putParcelable(KEY_IMAGE_URI, imageUri);
219 | if (imageMaxWidth != null) {
220 | outState.putInt(KEY_IMAGE_MAX_WIDTH, imageMaxWidth);
221 | }
222 | if (imageMaxHeight != null) {
223 | outState.putInt(KEY_IMAGE_MAX_HEIGHT, imageMaxHeight);
224 | }
225 | outState.putString(KEY_SELECTED_SIZE, selectedSize);
226 | }
227 |
228 | private void startCameraIntentForResult() {
229 | // Clean up last time's image
230 | imageUri = null;
231 | preview.setImageBitmap(null);
232 |
233 | Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
234 | if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
235 | ContentValues values = new ContentValues();
236 | values.put(MediaStore.Images.Media.TITLE, "New Picture");
237 | values.put(MediaStore.Images.Media.DESCRIPTION, "From Camera");
238 | imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
239 | takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
240 | startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
241 | }
242 | }
243 |
244 | private void startChooseImageIntentForResult() {
245 | Intent intent = new Intent();
246 | intent.setType("image/*");
247 | intent.setAction(Intent.ACTION_GET_CONTENT);
248 | startActivityForResult(Intent.createChooser(intent, "Select Picture"), REQUEST_CHOOSE_IMAGE);
249 | }
250 |
251 | @Override
252 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
253 | if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
254 | tryReloadAndDetectInImage();
255 | } else if (requestCode == REQUEST_CHOOSE_IMAGE && resultCode == RESULT_OK) {
256 | // In this case, imageUri is returned by the chooser, save it.
257 | imageUri = data.getData();
258 | tryReloadAndDetectInImage();
259 | }
260 | }
261 |
262 | private void tryReloadAndDetectInImage() {
263 | try {
264 | if (imageUri == null) {
265 | return;
266 | }
267 |
268 | // Clear the overlay first
269 | graphicOverlay.clear();
270 |
271 | Bitmap imageBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
272 |
273 | // Get the dimensions of the View
274 | Pair targetedSize = getTargetedWidthHeight();
275 |
276 | int targetWidth = targetedSize.first;
277 | int maxHeight = targetedSize.second;
278 |
279 | // Determine how much to scale down the image
280 | float scaleFactor =
281 | Math.max(
282 | (float) imageBitmap.getWidth() / (float) targetWidth,
283 | (float) imageBitmap.getHeight() / (float) maxHeight);
284 |
285 | Bitmap resizedBitmap =
286 | Bitmap.createScaledBitmap(
287 | imageBitmap,
288 | (int) (imageBitmap.getWidth() / scaleFactor),
289 | (int) (imageBitmap.getHeight() / scaleFactor),
290 | true);
291 |
292 | preview.setImageBitmap(resizedBitmap);
293 | bitmapForDetection = resizedBitmap;
294 |
295 | imageProcessor.process(bitmapForDetection, graphicOverlay);
296 | } catch (IOException e) {
297 | Log.e(TAG, "Error retrieving saved image");
298 | }
299 | }
300 |
301 | // Returns max image width, always for portrait mode. Caller needs to swap width / height for
302 | // landscape mode.
303 | private Integer getImageMaxWidth() {
304 | if (imageMaxWidth == null) {
305 | // Calculate the max width in portrait mode. This is done lazily since we need to wait for
306 | // a UI layout pass to get the right values. So delay it to first time image rendering time.
307 | if (isLandScape) {
308 | imageMaxWidth =
309 | ((View) preview.getParent()).getHeight() - findViewById(R.id.controlPanel).getHeight();
310 | } else {
311 | imageMaxWidth = ((View) preview.getParent()).getWidth();
312 | }
313 | }
314 |
315 | return imageMaxWidth;
316 | }
317 |
318 | // Returns max image height, always for portrait mode. Caller needs to swap width / height for
319 | // landscape mode.
320 | private Integer getImageMaxHeight() {
321 | if (imageMaxHeight == null) {
322 | // Calculate the max width in portrait mode. This is done lazily since we need to wait for
323 | // a UI layout pass to get the right values. So delay it to first time image rendering time.
324 | if (isLandScape) {
325 | imageMaxHeight = ((View) preview.getParent()).getWidth();
326 | } else {
327 | imageMaxHeight =
328 | ((View) preview.getParent()).getHeight() - findViewById(R.id.controlPanel).getHeight();
329 | }
330 | }
331 |
332 | return imageMaxHeight;
333 | }
334 |
335 | // Gets the targeted width / height.
336 | private Pair getTargetedWidthHeight() {
337 | int targetWidth;
338 | int targetHeight;
339 |
340 | switch (selectedSize) {
341 | case SIZE_PREVIEW:
342 | int maxWidthForPortraitMode = getImageMaxWidth();
343 | int maxHeightForPortraitMode = getImageMaxHeight();
344 | targetWidth = isLandScape ? maxHeightForPortraitMode : maxWidthForPortraitMode;
345 | targetHeight = isLandScape ? maxWidthForPortraitMode : maxHeightForPortraitMode;
346 | break;
347 | case SIZE_640_480:
348 | targetWidth = isLandScape ? 640 : 480;
349 | targetHeight = isLandScape ? 480 : 640;
350 | break;
351 | case SIZE_1024_768:
352 | targetWidth = isLandScape ? 1024 : 768;
353 | targetHeight = isLandScape ? 768 : 1024;
354 | break;
355 | default:
356 | throw new IllegalStateException("Unknown size");
357 | }
358 |
359 | return new Pair<>(targetWidth, targetHeight);
360 | }
361 |
362 | private void createImageProcessor() {
363 | switch (selectedMode) {
364 | case CLOUD_LABEL_DETECTION:
365 | imageProcessor = new CloudImageLabelingProcessor();
366 | break;
367 | case CLOUD_LANDMARK_DETECTION:
368 | imageProcessor = new CloudLandmarkRecognitionProcessor();
369 | break;
370 | case CLOUD_TEXT_DETECTION:
371 | imageProcessor = new CloudTextRecognitionProcessor();
372 | break;
373 | case CLOUD_DOCUMENT_TEXT_DETECTION:
374 | imageProcessor = new CloudDocumentTextRecognitionProcessor();
375 | break;
376 | default:
377 | throw new IllegalStateException("Unknown selectedMode: " + selectedMode);
378 | }
379 | }
380 | }
381 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionImageProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.graphics.Bitmap;
17 | import android.media.Image;
18 |
19 | import com.google.firebase.ml.common.FirebaseMLException;
20 |
21 | import java.nio.ByteBuffer;
22 |
23 | /** An inferface to process the images with different ML Kit detectors and custom image models. */
24 | public interface VisionImageProcessor {
25 |
26 | /** Processes the images with the underlying machine learning models. */
27 | void process(ByteBuffer data, FrameMetadata frameMetadata, GraphicOverlay graphicOverlay)
28 | throws FirebaseMLException;
29 |
30 | /** Processes the bitmap images. */
31 | void process(Bitmap bitmap, GraphicOverlay graphicOverlay);
32 |
33 | /** Processes the images. */
34 | void process(Image bitmap, int rotation, GraphicOverlay graphicOverlay);
35 |
36 | /** Stops the underlying machine learning model and release resources. */
37 | void stop();
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/VisionProcessorBase.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit;
15 |
16 | import android.graphics.Bitmap;
17 | import android.media.Image;
18 | import android.support.annotation.NonNull;
19 |
20 | import com.google.android.gms.tasks.OnFailureListener;
21 | import com.google.android.gms.tasks.OnSuccessListener;
22 | import com.google.android.gms.tasks.Task;
23 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
24 | import com.google.firebase.ml.vision.common.FirebaseVisionImageMetadata;
25 |
26 | import java.nio.ByteBuffer;
27 | import java.util.concurrent.atomic.AtomicBoolean;
28 |
29 | /**
30 | * Abstract base class for ML Kit frame processors. Subclasses need to implement {@link
31 | * #onSuccess(T, FrameMetadata, GraphicOverlay)} to define what they want to with the detection
32 | * results and {@link #detectInImage(FirebaseVisionImage)} to specify the detector object.
33 | *
34 | * @param The type of the detected feature.
35 | */
36 | public abstract class VisionProcessorBase implements VisionImageProcessor {
37 |
38 | // Whether we should ignore process(). This is usually caused by feeding input data faster than
39 | // the model can handle.
40 | private final AtomicBoolean shouldThrottle = new AtomicBoolean(false);
41 |
42 | public VisionProcessorBase() {
43 | }
44 |
45 | @Override
46 | public void process(
47 | ByteBuffer data, final FrameMetadata frameMetadata, final GraphicOverlay
48 | graphicOverlay) {
49 | if (shouldThrottle.get()) {
50 | return;
51 | }
52 | FirebaseVisionImageMetadata metadata =
53 | new FirebaseVisionImageMetadata.Builder()
54 | .setFormat(FirebaseVisionImageMetadata.IMAGE_FORMAT_NV21)
55 | .setWidth(frameMetadata.getWidth())
56 | .setHeight(frameMetadata.getHeight())
57 | .setRotation(frameMetadata.getRotation())
58 | .build();
59 |
60 | detectInVisionImage(
61 | FirebaseVisionImage.fromByteBuffer(data, metadata), frameMetadata, graphicOverlay);
62 | }
63 |
64 | // Bitmap version
65 | @Override
66 | public void process(Bitmap bitmap, final GraphicOverlay
67 | graphicOverlay) {
68 | if (shouldThrottle.get()) {
69 | return;
70 | }
71 | detectInVisionImage(FirebaseVisionImage.fromBitmap(bitmap), null, graphicOverlay);
72 | }
73 |
74 | /**
75 | * Detects feature from given media.Image
76 | *
77 | * @return created FirebaseVisionImage
78 | */
79 | @Override
80 | public void process(Image image, int rotation, final GraphicOverlay graphicOverlay) {
81 | if (shouldThrottle.get()) {
82 | return;
83 | }
84 | // This is for overlay display's usage
85 | FrameMetadata frameMetadata =
86 | new FrameMetadata.Builder().setWidth(image.getWidth()).setHeight(image.getHeight
87 | ()).build();
88 | FirebaseVisionImage fbVisionImage =
89 | FirebaseVisionImage.fromMediaImage(image, rotation);
90 | detectInVisionImage(fbVisionImage, frameMetadata, graphicOverlay);
91 | }
92 |
93 | private void detectInVisionImage(
94 | FirebaseVisionImage image,
95 | final FrameMetadata metadata,
96 | final GraphicOverlay graphicOverlay) {
97 | detectInImage(image)
98 | .addOnSuccessListener(
99 | new OnSuccessListener() {
100 | @Override
101 | public void onSuccess(T results) {
102 | shouldThrottle.set(false);
103 | VisionProcessorBase.this.onSuccess(results, metadata,
104 | graphicOverlay);
105 | }
106 | })
107 | .addOnFailureListener(
108 | new OnFailureListener() {
109 | @Override
110 | public void onFailure(@NonNull Exception e) {
111 | shouldThrottle.set(false);
112 | VisionProcessorBase.this.onFailure(e);
113 | }
114 | });
115 | // Begin throttling until this frame of input has been processed, either in onSuccess or
116 | // onFailure.
117 | shouldThrottle.set(true);
118 | }
119 |
120 | @Override
121 | public void stop() {
122 | }
123 |
124 | protected abstract Task detectInImage(FirebaseVisionImage image);
125 |
126 | protected abstract void onSuccess(
127 | @NonNull T results,
128 | @NonNull FrameMetadata frameMetadata,
129 | @NonNull GraphicOverlay graphicOverlay);
130 |
131 | protected abstract void onFailure(@NonNull Exception e);
132 | }
133 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.barcodescanning;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 | import android.graphics.RectF;
20 |
21 | import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode;
22 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
23 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
24 |
25 | /** Graphic instance for rendering Barcode position and content information in an overlay view. */
26 | public class BarcodeGraphic extends Graphic {
27 |
28 | private static final int TEXT_COLOR = Color.WHITE;
29 | private static final float TEXT_SIZE = 54.0f;
30 | private static final float STROKE_WIDTH = 4.0f;
31 |
32 | private final Paint rectPaint;
33 | private final Paint barcodePaint;
34 | private final FirebaseVisionBarcode barcode;
35 |
36 | BarcodeGraphic(GraphicOverlay overlay, FirebaseVisionBarcode barcode) {
37 | super(overlay);
38 |
39 | this.barcode = barcode;
40 |
41 | rectPaint = new Paint();
42 | rectPaint.setColor(TEXT_COLOR);
43 | rectPaint.setStyle(Paint.Style.STROKE);
44 | rectPaint.setStrokeWidth(STROKE_WIDTH);
45 |
46 | barcodePaint = new Paint();
47 | barcodePaint.setColor(TEXT_COLOR);
48 | barcodePaint.setTextSize(TEXT_SIZE);
49 | // Redraw the overlay, as this graphic has been added.
50 | postInvalidate();
51 | }
52 |
53 | /**
54 | * Draws the barcode block annotations for position, size, and raw value on the supplied canvas.
55 | */
56 | @Override
57 | public void draw(Canvas canvas) {
58 | if (barcode == null) {
59 | throw new IllegalStateException("Attempting to draw a null barcode.");
60 | }
61 |
62 | // Draws the bounding box around the BarcodeBlock.
63 | RectF rect = new RectF(barcode.getBoundingBox());
64 | rect.left = translateX(rect.left);
65 | rect.top = translateY(rect.top);
66 | rect.right = translateX(rect.right);
67 | rect.bottom = translateY(rect.bottom);
68 | canvas.drawRect(rect, rectPaint);
69 |
70 | // Renders the barcode at the bottom of the box.
71 | canvas.drawText(barcode.getRawValue(), rect.left, rect.bottom, barcodePaint);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/barcodescanning/BarcodeScanningProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.barcodescanning;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcode;
22 | import com.google.firebase.ml.vision.barcode.FirebaseVisionBarcodeDetector;
23 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
24 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
25 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
26 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
27 |
28 | import java.io.IOException;
29 | import java.util.List;
30 |
31 | /** Barcode Detector Demo. */
32 | public class BarcodeScanningProcessor extends VisionProcessorBase> {
33 |
34 | private static final String TAG = "BarcodeScanningProcessor";
35 |
36 | private final FirebaseVisionBarcodeDetector detector;
37 |
38 | public BarcodeScanningProcessor() {
39 | // Note that if you know which format of barcode your app is dealing with, detection will be
40 | // faster to specify the supported barcode formats one by one, e.g.
41 | // new FirebaseVisionBarcodeDetectorOptions.Builder()
42 | // .setBarcodeFormats(irebaseVisionBarcode.FORMAT_QR_CODE)
43 | // .build();
44 | detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
45 | }
46 |
47 | @Override
48 | public void stop() {
49 | try {
50 | detector.close();
51 | } catch (IOException e) {
52 | Log.e(TAG, "Exception thrown while trying to close Barcode Detector: " + e);
53 | }
54 | }
55 |
56 | @Override
57 | protected Task> detectInImage(FirebaseVisionImage image) {
58 | return detector.detectInImage(image);
59 | }
60 |
61 | @Override
62 | protected void onSuccess(
63 | @NonNull List barcodes,
64 | @NonNull FrameMetadata frameMetadata,
65 | @NonNull GraphicOverlay graphicOverlay) {
66 | graphicOverlay.clear();
67 | for (int i = 0; i < barcodes.size(); ++i) {
68 | FirebaseVisionBarcode barcode = barcodes.get(i);
69 | BarcodeGraphic barcodeGraphic = new BarcodeGraphic(graphicOverlay, barcode);
70 | graphicOverlay.add(barcodeGraphic);
71 | }
72 | }
73 |
74 | @Override
75 | protected void onFailure(@NonNull Exception e) {
76 | Log.e(TAG, "Barcode detection failed " + e);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudImageLabelingProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudimagelabeling;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.cloud.FirebaseVisionCloudDetectorOptions;
22 | import com.google.firebase.ml.vision.cloud.label.FirebaseVisionCloudLabel;
23 | import com.google.firebase.ml.vision.cloud.label.FirebaseVisionCloudLabelDetector;
24 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
25 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
26 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
27 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
28 |
29 | import java.util.ArrayList;
30 | import java.util.List;
31 |
32 | /** Cloud Label Detector Demo. */
33 | public class CloudImageLabelingProcessor
34 | extends VisionProcessorBase> {
35 | private static final String TAG = "CloudImageLabelingProcessor";
36 |
37 | private final FirebaseVisionCloudLabelDetector detector;
38 |
39 | public CloudImageLabelingProcessor() {
40 | FirebaseVisionCloudDetectorOptions options =
41 | new FirebaseVisionCloudDetectorOptions.Builder()
42 | .setMaxResults(10)
43 | .setModelType(FirebaseVisionCloudDetectorOptions.STABLE_MODEL)
44 | .build();
45 |
46 | detector = FirebaseVision.getInstance().getVisionCloudLabelDetector(options);
47 | }
48 |
49 | @Override
50 | protected Task> detectInImage(FirebaseVisionImage image) {
51 | return detector.detectInImage(image);
52 | }
53 |
54 | @Override
55 | protected void onSuccess(
56 | @NonNull List labels,
57 | @NonNull FrameMetadata frameMetadata,
58 | @NonNull GraphicOverlay graphicOverlay) {
59 | graphicOverlay.clear();
60 | Log.d(TAG, "cloud label size: " + labels.size());
61 | List labelsStr = new ArrayList<>();
62 | for (int i = 0; i < labels.size(); ++i) {
63 | FirebaseVisionCloudLabel label = labels.get(i);
64 | Log.d(TAG, "cloud label: " + label);
65 | if (label.getLabel() != null) {
66 | labelsStr.add((label.getLabel()));
67 | }
68 | }
69 | CloudLabelGraphic cloudLabelGraphic = new CloudLabelGraphic(graphicOverlay);
70 | graphicOverlay.add(cloudLabelGraphic);
71 | cloudLabelGraphic.updateLabel(labelsStr);
72 | }
73 |
74 | @Override
75 | protected void onFailure(@NonNull Exception e) {
76 | Log.e(TAG, "Cloud Label detection failed " + e);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudimagelabeling/CloudLabelGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudimagelabeling;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 |
20 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
21 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
22 |
23 | import java.util.List;
24 |
25 | /** Graphic instance for rendering detected label. */
26 | public class CloudLabelGraphic extends Graphic {
27 | private final Paint textPaint;
28 | private final GraphicOverlay overlay;
29 |
30 | private List labels;
31 |
32 | CloudLabelGraphic(GraphicOverlay overlay) {
33 | super(overlay);
34 | this.overlay = overlay;
35 | textPaint = new Paint();
36 | textPaint.setColor(Color.WHITE);
37 | textPaint.setTextSize(60.0f);
38 | }
39 |
40 | synchronized void updateLabel(List labels) {
41 | this.labels = labels;
42 | postInvalidate();
43 | }
44 |
45 | @Override
46 | public synchronized void draw(Canvas canvas) {
47 | float x = overlay.getWidth() / 4.0f;
48 | float y = overlay.getHeight() / 4.0f;
49 |
50 | for (String label : labels) {
51 | canvas.drawText(label, x, y, textPaint);
52 | y = y - 62.0f;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudlandmarkrecognition;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 | import android.graphics.RectF;
20 |
21 | import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmark;
22 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
23 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
24 |
25 | /** Graphic instance for rendering detected landmark. */
26 | public class CloudLandmarkGraphic extends Graphic {
27 | private static final int TEXT_COLOR = Color.WHITE;
28 | private static final float TEXT_SIZE = 54.0f;
29 | private static final float STROKE_WIDTH = 4.0f;
30 |
31 | private final Paint rectPaint;
32 | private final Paint landmarkPaint;
33 | private FirebaseVisionCloudLandmark landmark;
34 |
35 | CloudLandmarkGraphic(GraphicOverlay overlay) {
36 | super(overlay);
37 |
38 | rectPaint = new Paint();
39 | rectPaint.setColor(TEXT_COLOR);
40 | rectPaint.setStyle(Paint.Style.STROKE);
41 | rectPaint.setStrokeWidth(STROKE_WIDTH);
42 |
43 | landmarkPaint = new Paint();
44 | landmarkPaint.setColor(TEXT_COLOR);
45 | landmarkPaint.setTextSize(TEXT_SIZE);
46 | }
47 |
48 | /**
49 | * Updates the landmark instance from the detection of the most recent frame. Invalidates the
50 | * relevant portions of the overlay to trigger a redraw.
51 | */
52 | void updateLandmark(FirebaseVisionCloudLandmark landmark) {
53 | this.landmark = landmark;
54 | postInvalidate();
55 | }
56 |
57 | /**
58 | * Draws the landmark block annotations for position, size, and raw value on the supplied canvas.
59 | */
60 | @Override
61 | public void draw(Canvas canvas) {
62 | if (landmark == null) {
63 | throw new IllegalStateException("Attempting to draw a null landmark.");
64 | }
65 | if (landmark.getLandmark() == null || landmark.getBoundingBox() == null) {
66 | return;
67 | }
68 |
69 | // Draws the bounding box around the LandmarkBlock.
70 | RectF rect = new RectF(landmark.getBoundingBox());
71 | rect.left = translateX(rect.left);
72 | rect.top = translateY(rect.top);
73 | rect.right = translateX(rect.right);
74 | rect.bottom = translateY(rect.bottom);
75 | canvas.drawRect(rect, rectPaint);
76 |
77 | // Renders the landmark at the bottom of the box.
78 | canvas.drawText(landmark.getLandmark(), rect.left, rect.bottom, landmarkPaint);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudlandmarkrecognition/CloudLandmarkRecognitionProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudlandmarkrecognition;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.cloud.FirebaseVisionCloudDetectorOptions;
22 | import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmark;
23 | import com.google.firebase.ml.vision.cloud.landmark.FirebaseVisionCloudLandmarkDetector;
24 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
25 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
26 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
27 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
28 |
29 | import java.util.List;
30 |
31 | /** Cloud Landmark Detector Demo. */
32 | public class CloudLandmarkRecognitionProcessor
33 | extends VisionProcessorBase> {
34 | private static final String TAG = "CloudLandmarkRecognitionProcessor";
35 |
36 | private final FirebaseVisionCloudLandmarkDetector detector;
37 |
38 | public CloudLandmarkRecognitionProcessor() {
39 | super();
40 | FirebaseVisionCloudDetectorOptions options =
41 | new FirebaseVisionCloudDetectorOptions.Builder()
42 | .setMaxResults(10)
43 | .setModelType(FirebaseVisionCloudDetectorOptions.STABLE_MODEL)
44 | .build();
45 |
46 | detector = FirebaseVision.getInstance().getVisionCloudLandmarkDetector(options);
47 | }
48 |
49 | @Override
50 | protected Task> detectInImage(FirebaseVisionImage image) {
51 | return detector.detectInImage(image);
52 | }
53 |
54 | @Override
55 | protected void onSuccess(
56 | @NonNull List landmarks,
57 | @NonNull FrameMetadata frameMetadata,
58 | @NonNull GraphicOverlay graphicOverlay) {
59 | graphicOverlay.clear();
60 | Log.d(TAG, "cloud landmark size: " + landmarks.size());
61 | for (int i = 0; i < landmarks.size(); ++i) {
62 | FirebaseVisionCloudLandmark landmark = landmarks.get(i);
63 | Log.d(TAG, "cloud landmark: " + landmark);
64 | CloudLandmarkGraphic cloudLandmarkGraphic = new CloudLandmarkGraphic(graphicOverlay);
65 | graphicOverlay.add(cloudLandmarkGraphic);
66 | cloudLandmarkGraphic.updateLandmark(landmark);
67 | }
68 | }
69 |
70 | @Override
71 | protected void onFailure(@NonNull Exception e) {
72 | Log.e(TAG, "Cloud Landmark detection failed " + e);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudDocumentTextRecognitionProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudtextrecognition;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.cloud.text.FirebaseVisionCloudDocumentTextDetector;
22 | import com.google.firebase.ml.vision.cloud.text.FirebaseVisionCloudText;
23 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
24 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
25 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
26 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
27 |
28 | /** Processor for the cloud document text detector demo. */
29 | public class CloudDocumentTextRecognitionProcessor
30 | extends VisionProcessorBase {
31 |
32 | private static final String TAG = "CloudDocumentTextRecognitionProcessor";
33 |
34 | private final FirebaseVisionCloudDocumentTextDetector detector;
35 |
36 | public CloudDocumentTextRecognitionProcessor() {
37 | super();
38 | detector = FirebaseVision.getInstance().getVisionCloudDocumentTextDetector();
39 | }
40 |
41 | @Override
42 | protected Task detectInImage(FirebaseVisionImage image) {
43 | return detector.detectInImage(image);
44 | }
45 |
46 | @Override
47 | protected void onSuccess(
48 | @NonNull FirebaseVisionCloudText text,
49 | @NonNull FrameMetadata frameMetadata,
50 | @NonNull GraphicOverlay graphicOverlay) {
51 | graphicOverlay.clear();
52 | Log.d(TAG, "detected text is: " + text.getText());
53 | CloudTextGraphic textGraphic = new CloudTextGraphic(graphicOverlay, text);
54 | graphicOverlay.add(textGraphic);
55 | }
56 |
57 | @Override
58 | protected void onFailure(@NonNull Exception e) {
59 | Log.w(TAG, "Cloud Document Text detection failed." + e);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudtextrecognition;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 |
20 | import com.google.firebase.ml.vision.cloud.text.FirebaseVisionCloudText;
21 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
22 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
23 |
24 | /**
25 | * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic
26 | * overlay view.
27 | */
28 | public class CloudTextGraphic extends Graphic {
29 | private static final int TEXT_COLOR = Color.WHITE;
30 | private static final float TEXT_SIZE = 54.0f;
31 | private static final float STROKE_WIDTH = 4.0f;
32 |
33 | private final Paint rectPaint;
34 | private final Paint textPaint;
35 | private final FirebaseVisionCloudText text;
36 | private final GraphicOverlay overlay;
37 |
38 | CloudTextGraphic(GraphicOverlay overlay, FirebaseVisionCloudText text) {
39 | super(overlay);
40 |
41 | this.text = text;
42 | this.overlay = overlay;
43 |
44 | rectPaint = new Paint();
45 | rectPaint.setColor(TEXT_COLOR);
46 | rectPaint.setStyle(Paint.Style.STROKE);
47 | rectPaint.setStrokeWidth(STROKE_WIDTH);
48 |
49 | textPaint = new Paint();
50 | textPaint.setColor(TEXT_COLOR);
51 | textPaint.setTextSize(TEXT_SIZE);
52 | // Redraw the overlay, as this graphic has been added.
53 | postInvalidate();
54 | }
55 |
56 | /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */
57 | @Override
58 | public void draw(Canvas canvas) {
59 | if (text == null) {
60 | throw new IllegalStateException("Attempting to draw a null text.");
61 | }
62 |
63 | float x = overlay.getWidth() / 4.0f;
64 | float y = overlay.getHeight() / 4.0f;
65 |
66 | canvas.drawText(text.getText(), x, y, textPaint);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/cloudtextrecognition/CloudTextRecognitionProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.cloudtextrecognition;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.cloud.text.FirebaseVisionCloudText;
22 | import com.google.firebase.ml.vision.cloud.text.FirebaseVisionCloudTextDetector;
23 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
24 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
25 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
26 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
27 |
28 | /** Processor for the cloud text detector demo. */
29 | public class CloudTextRecognitionProcessor extends VisionProcessorBase {
30 |
31 | private static final String TAG = "CloudTextRecognitionProcessor";
32 |
33 | private final FirebaseVisionCloudTextDetector detector;
34 |
35 | public CloudTextRecognitionProcessor() {
36 | super();
37 | detector = FirebaseVision.getInstance().getVisionCloudTextDetector();
38 | }
39 |
40 | @Override
41 | protected Task detectInImage(FirebaseVisionImage image) {
42 | return detector.detectInImage(image);
43 | }
44 |
45 | @Override
46 | protected void onSuccess(
47 | @NonNull FirebaseVisionCloudText text,
48 | @NonNull FrameMetadata frameMetadata,
49 | @NonNull GraphicOverlay graphicOverlay) {
50 | graphicOverlay.clear();
51 | Log.d(TAG, "detected text is: " + text.getText());
52 | CloudTextGraphic textGraphic = new CloudTextGraphic(graphicOverlay, text);
53 | graphicOverlay.add(textGraphic);
54 | }
55 |
56 | @Override
57 | protected void onFailure(@NonNull Exception e) {
58 | Log.w(TAG, "Cloud Text detection failed." + e);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifier.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.custommodel;
15 |
16 | import android.app.Activity;
17 | import android.graphics.Bitmap;
18 | import android.graphics.BitmapFactory;
19 | import android.graphics.ImageFormat;
20 | import android.graphics.Rect;
21 | import android.graphics.YuvImage;
22 | import android.os.SystemClock;
23 | import android.util.Log;
24 |
25 | import com.google.android.gms.tasks.Continuation;
26 | import com.google.android.gms.tasks.Task;
27 | import com.google.android.gms.tasks.Tasks;
28 | import com.google.firebase.ml.common.FirebaseMLException;
29 | import com.google.firebase.ml.custom.FirebaseModelDataType;
30 | import com.google.firebase.ml.custom.FirebaseModelInputOutputOptions;
31 | import com.google.firebase.ml.custom.FirebaseModelInputs;
32 | import com.google.firebase.ml.custom.FirebaseModelInterpreter;
33 | import com.google.firebase.ml.custom.FirebaseModelOptions;
34 | import com.google.firebase.ml.custom.FirebaseModelOutputs;
35 |
36 | import java.io.BufferedReader;
37 | import java.io.ByteArrayOutputStream;
38 | import java.io.IOException;
39 | import java.io.InputStreamReader;
40 | import java.nio.ByteBuffer;
41 | import java.nio.ByteOrder;
42 | import java.util.AbstractMap;
43 | import java.util.ArrayList;
44 | import java.util.Comparator;
45 | import java.util.List;
46 | import java.util.Map;
47 | import java.util.PriorityQueue;
48 |
49 | /** A {@code FirebaseModelInterpreter} based image classifier. */
50 | public class CustomImageClassifier {
51 |
52 | /** Tag for the {@link Log}. */
53 | private static final String TAG = "MLKitDemoApp:Classifier";
54 |
55 | /** Name of the model file stored in Assets. */
56 | private static final String MODEL_PATH = "mobilenet_quant_v1_224.tflite";
57 |
58 | /** Name of the label file stored in Assets. */
59 | private static final String LABEL_PATH = "labels.txt";
60 |
61 | /** Number of results to show in the UI. */
62 | private static final int RESULTS_TO_SHOW = 3;
63 |
64 | /** Dimensions of inputs. */
65 | private static final int DIM_BATCH_SIZE = 1;
66 |
67 | private static final int DIM_PIXEL_SIZE = 3;
68 |
69 | private static final int DIM_IMG_SIZE_X = 224;
70 | private static final int DIM_IMG_SIZE_Y = 224;
71 |
72 | /* Preallocated buffers for storing image data in. */
73 | private final int[] intValues = new int[DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y];
74 |
75 | /** An instance of the driver class to run model inference with Firebase. */
76 | private final FirebaseModelInterpreter interpreter;
77 |
78 | /** Data configuration of input & output data of model. */
79 | private final FirebaseModelInputOutputOptions dataOptions;
80 |
81 | /** Labels corresponding to the output of the vision model. */
82 | private final List labelList;
83 |
84 | private final PriorityQueue> sortedLabels =
85 | new PriorityQueue<>(
86 | RESULTS_TO_SHOW,
87 | new Comparator>() {
88 | @Override
89 | public int compare(Map.Entry o1, Map.Entry o2) {
90 | return (o1.getValue()).compareTo(o2.getValue());
91 | }
92 | });
93 |
94 | /** Initializes an {@code CustomImageClassifier}. */
95 | CustomImageClassifier(Activity activity) throws FirebaseMLException {
96 | FirebaseModelOptions modelOptions =
97 | new FirebaseModelOptions.Builder()
98 | .setCloudModelName("mobilenet_v1")
99 | .setLocalModelName(MODEL_PATH)
100 | .build();
101 | interpreter = FirebaseModelInterpreter.getInstance(modelOptions);
102 | labelList = loadLabelList(activity);
103 | Log.d(TAG, "Created a Custom Image Classifier.");
104 | int[] inputDims = {DIM_BATCH_SIZE, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, DIM_PIXEL_SIZE};
105 | int[] outputDims = {1, labelList.size()};
106 | dataOptions =
107 | new FirebaseModelInputOutputOptions.Builder()
108 | .setInputFormat(0, FirebaseModelDataType.BYTE, inputDims)
109 | .setOutputFormat(0, FirebaseModelDataType.BYTE, outputDims)
110 | .build();
111 | Log.d(TAG, "Configured input & output data for the custom image classifier.");
112 | }
113 |
114 | /** Classifies a frame from the preview stream. */
115 | Task> classifyFrame(ByteBuffer buffer, int width, int height)
116 | throws FirebaseMLException {
117 | if (interpreter == null) {
118 | Log.e(TAG, "Image classifier has not been initialized; Skipped.");
119 | List uninitialized = new ArrayList<>();
120 | uninitialized.add("Uninitialized Classifier.");
121 | Tasks.forResult(uninitialized);
122 | }
123 | // Create input data.
124 | ByteBuffer imgData = convertBitmapToByteBuffer(buffer, width, height);
125 |
126 | FirebaseModelInputs inputs = new FirebaseModelInputs.Builder().add(imgData).build();
127 | // Here's where the magic happens!!
128 | return interpreter
129 | .run(inputs, dataOptions)
130 | .continueWith(
131 | new Continuation>() {
132 | @Override
133 | public List then(Task task) throws Exception {
134 | byte[][] labelProbArray = task.getResult().getOutput(0);
135 | return printTopKLabels(labelProbArray);
136 | }
137 | });
138 | }
139 |
140 | /** Reads label list from Assets. */
141 | private List loadLabelList(Activity activity) {
142 | List labelList = new ArrayList<>();
143 | try (BufferedReader reader =
144 | new BufferedReader(new InputStreamReader(activity.getAssets().open(LABEL_PATH)))) {
145 | String line;
146 | while ((line = reader.readLine()) != null) {
147 | labelList.add(line);
148 | }
149 | } catch (IOException e) {
150 | Log.e(TAG, "Failed to read label list.", e);
151 | }
152 | return labelList;
153 | }
154 |
155 | /** Writes Image data into a {@code ByteBuffer}. */
156 | private synchronized ByteBuffer convertBitmapToByteBuffer(
157 | ByteBuffer buffer, int width, int height) {
158 | ByteBuffer imgData =
159 | ByteBuffer.allocateDirect(
160 | DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);
161 | imgData.order(ByteOrder.nativeOrder());
162 | Bitmap bitmap = createResizedBitmap(buffer, width, height);
163 | imgData.rewind();
164 | bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
165 | // Convert the image to int points.
166 | int pixel = 0;
167 | long startTime = SystemClock.uptimeMillis();
168 | for (int i = 0; i < DIM_IMG_SIZE_X; ++i) {
169 | for (int j = 0; j < DIM_IMG_SIZE_Y; ++j) {
170 | final int val = intValues[pixel++];
171 | imgData.put((byte) ((val >> 16) & 0xFF));
172 | imgData.put((byte) ((val >> 8) & 0xFF));
173 | imgData.put((byte) (val & 0xFF));
174 | }
175 | }
176 | long endTime = SystemClock.uptimeMillis();
177 | Log.d(TAG, "Timecost to put values into ByteBuffer: " + (endTime - startTime));
178 | return imgData;
179 | }
180 |
181 | /** Resizes image data from {@code ByteBuffer}. */
182 | private Bitmap createResizedBitmap(ByteBuffer buffer, int width, int height) {
183 | YuvImage img = new YuvImage(buffer.array(), ImageFormat.NV21, width, height, null);
184 | ByteArrayOutputStream out = new ByteArrayOutputStream();
185 | img.compressToJpeg(new Rect(0, 0, img.getWidth(), img.getHeight()), 50, out);
186 | byte[] imageBytes = out.toByteArray();
187 | Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
188 | return Bitmap.createScaledBitmap(bitmap, DIM_IMG_SIZE_X, DIM_IMG_SIZE_Y, true);
189 | }
190 |
191 | /** Prints top-K labels, to be shown in UI as the results. */
192 | private synchronized List printTopKLabels(byte[][] labelProbArray) {
193 | for (int i = 0; i < labelList.size(); ++i) {
194 | sortedLabels.add(
195 | new AbstractMap.SimpleEntry<>(labelList.get(i), (labelProbArray[0][i] & 0xff) / 255.0f));
196 | if (sortedLabels.size() > RESULTS_TO_SHOW) {
197 | sortedLabels.poll();
198 | }
199 | }
200 | List result = new ArrayList<>();
201 | final int size = sortedLabels.size();
202 | for (int i = 0; i < size; ++i) {
203 | Map.Entry label = sortedLabels.poll();
204 | result.add(label.getKey() + ":" + label.getValue());
205 | }
206 | return result;
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/CustomImageClassifierProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.custommodel;
15 |
16 | import android.app.Activity;
17 | import android.graphics.Bitmap;
18 | import android.media.Image;
19 |
20 | import com.google.android.gms.tasks.OnSuccessListener;
21 | import com.google.firebase.ml.common.FirebaseMLException;
22 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
23 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
24 | import com.google.firebase.samples.apps.mlkit.VisionImageProcessor;
25 |
26 | import java.nio.ByteBuffer;
27 | import java.util.List;
28 |
29 | /** Custom Image Classifier Demo. */
30 | public class CustomImageClassifierProcessor implements VisionImageProcessor {
31 |
32 | private final CustomImageClassifier classifier;
33 | private final Activity activity;
34 |
35 | public CustomImageClassifierProcessor(Activity activity) throws FirebaseMLException {
36 | this.activity = activity;
37 | classifier = new CustomImageClassifier(activity);
38 | }
39 |
40 | @Override
41 | public void process(
42 | ByteBuffer data, FrameMetadata frameMetadata, final GraphicOverlay graphicOverlay)
43 | throws FirebaseMLException {
44 | classifier
45 | .classifyFrame(data, frameMetadata.getWidth(), frameMetadata.getHeight())
46 | .addOnSuccessListener(
47 | activity,
48 | new OnSuccessListener>() {
49 | @Override
50 | public void onSuccess(List result) {
51 | LabelGraphic labelGraphic = new LabelGraphic(graphicOverlay);
52 | graphicOverlay.clear();
53 | graphicOverlay.add(labelGraphic);
54 | labelGraphic.updateLabel(result);
55 | }
56 | });
57 | }
58 |
59 | @Override
60 | public void process(Bitmap bitmap, GraphicOverlay graphicOverlay) {
61 | // nop
62 | }
63 |
64 | @Override
65 | public void process(Image bitmap, int rotation, GraphicOverlay graphicOverlay) {
66 | // nop
67 |
68 | }
69 |
70 | @Override
71 | public void stop() {}
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/custommodel/LabelGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.custommodel;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 |
20 |
21 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
22 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
23 |
24 | import java.util.List;
25 |
26 | /** Graphic instance for rendering image labels. */
27 | public class LabelGraphic extends Graphic {
28 |
29 | private final Paint textPaint;
30 | private final GraphicOverlay overlay;
31 |
32 | private List labels;
33 |
34 | LabelGraphic(GraphicOverlay overlay) {
35 | super(overlay);
36 | this.overlay = overlay;
37 | textPaint = new Paint();
38 | textPaint.setColor(Color.WHITE);
39 | textPaint.setTextSize(60.0f);
40 | }
41 |
42 | synchronized void updateLabel(List labels) {
43 | this.labels = labels;
44 | postInvalidate();
45 | }
46 |
47 | @Override
48 | public synchronized void draw(Canvas canvas) {
49 | float x = overlay.getWidth() / 4.0f;
50 | float y = overlay.getHeight() / 4.0f;
51 |
52 | for (String label : labels) {
53 | canvas.drawText(label, x, y, textPaint);
54 | y = y - 62.0f;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceDetectionProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.facedetection;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
22 | import com.google.firebase.ml.vision.face.FirebaseVisionFace;
23 | import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetector;
24 | import com.google.firebase.ml.vision.face.FirebaseVisionFaceDetectorOptions;
25 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
26 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
27 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
28 |
29 | import java.io.IOException;
30 | import java.util.List;
31 |
32 | /** Face Detector Demo. */
33 | public class FaceDetectionProcessor extends VisionProcessorBase> {
34 |
35 | private static final String TAG = "FaceDetectionProcessor";
36 |
37 | private final FirebaseVisionFaceDetector detector;
38 |
39 | public FaceDetectionProcessor() {
40 | FirebaseVisionFaceDetectorOptions options =
41 | new FirebaseVisionFaceDetectorOptions.Builder()
42 | .setClassificationType(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
43 | .setTrackingEnabled(true)
44 | .build();
45 |
46 | detector = FirebaseVision.getInstance().getVisionFaceDetector(options);
47 | }
48 |
49 | @Override
50 | public void stop() {
51 | try {
52 | detector.close();
53 | } catch (IOException e) {
54 | Log.e(TAG, "Exception thrown while trying to close Face Detector: " + e);
55 | }
56 | }
57 |
58 | @Override
59 | protected Task> detectInImage(FirebaseVisionImage image) {
60 | return detector.detectInImage(image);
61 | }
62 |
63 | @Override
64 | protected void onSuccess(
65 | @NonNull List faces,
66 | @NonNull FrameMetadata frameMetadata,
67 | @NonNull GraphicOverlay graphicOverlay) {
68 | graphicOverlay.clear();
69 | for (int i = 0; i < faces.size(); ++i) {
70 | FirebaseVisionFace face = faces.get(i);
71 | FaceGraphic faceGraphic = new FaceGraphic(graphicOverlay);
72 | graphicOverlay.add(faceGraphic);
73 | faceGraphic.updateFace(face, frameMetadata.getCameraFacing());
74 | }
75 | }
76 |
77 | @Override
78 | protected void onFailure(@NonNull Exception e) {
79 | Log.e(TAG, "Face detection failed " + e);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/facedetection/FaceGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package com.google.firebase.samples.apps.mlkit.facedetection;
16 |
17 | import android.graphics.Canvas;
18 | import android.graphics.Color;
19 | import android.graphics.Paint;
20 |
21 | import com.google.android.gms.vision.CameraSource;
22 | import com.google.firebase.ml.vision.face.FirebaseVisionFace;
23 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
24 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
25 |
26 | /**
27 | * Graphic instance for rendering face position, orientation, and landmarks within an associated
28 | * graphic overlay view.
29 | */
30 | public class FaceGraphic extends Graphic {
31 | private static final float FACE_POSITION_RADIUS = 10.0f;
32 | private static final float ID_TEXT_SIZE = 40.0f;
33 | private static final float ID_Y_OFFSET = 50.0f;
34 | private static final float ID_X_OFFSET = -50.0f;
35 | private static final float BOX_STROKE_WIDTH = 5.0f;
36 |
37 | private static final int[] COLOR_CHOICES = {
38 | Color.BLUE //, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.RED, Color.WHITE, Color.YELLOW
39 | };
40 | private static int currentColorIndex = 0;
41 |
42 | private int facing;
43 |
44 | private final Paint facePositionPaint;
45 | private final Paint idPaint;
46 | private final Paint boxPaint;
47 |
48 | private volatile FirebaseVisionFace firebaseVisionFace;
49 |
50 | public FaceGraphic(GraphicOverlay overlay) {
51 | super(overlay);
52 |
53 | currentColorIndex = (currentColorIndex + 1) % COLOR_CHOICES.length;
54 | final int selectedColor = COLOR_CHOICES[currentColorIndex];
55 |
56 | facePositionPaint = new Paint();
57 | facePositionPaint.setColor(selectedColor);
58 |
59 | idPaint = new Paint();
60 | idPaint.setColor(selectedColor);
61 | idPaint.setTextSize(ID_TEXT_SIZE);
62 |
63 | boxPaint = new Paint();
64 | boxPaint.setColor(selectedColor);
65 | boxPaint.setStyle(Paint.Style.STROKE);
66 | boxPaint.setStrokeWidth(BOX_STROKE_WIDTH);
67 | }
68 |
69 | /**
70 | * Updates the face instance from the detection of the most recent frame. Invalidates the relevant
71 | * portions of the overlay to trigger a redraw.
72 | */
73 | public void updateFace(FirebaseVisionFace face, int facing) {
74 | firebaseVisionFace = face;
75 | this.facing = facing;
76 | postInvalidate();
77 | }
78 |
79 | /** Draws the face annotations for position on the supplied canvas. */
80 | @Override
81 | public void draw(Canvas canvas) {
82 | FirebaseVisionFace face = firebaseVisionFace;
83 | if (face == null) {
84 | return;
85 | }
86 |
87 | // Draws a circle at the position of the detected face, with the face's track id below.
88 | float x = translateX(face.getBoundingBox().centerX());
89 | float y = translateY(face.getBoundingBox().centerY());
90 | canvas.drawCircle(x, y, FACE_POSITION_RADIUS, facePositionPaint);
91 | canvas.drawText("id: " + face.getTrackingId(), x + ID_X_OFFSET, y + ID_Y_OFFSET, idPaint);
92 | canvas.drawText(
93 | "happiness: " + String.format("%.2f", face.getSmilingProbability()),
94 | x + ID_X_OFFSET * 3,
95 | y - ID_Y_OFFSET,
96 | idPaint);
97 | if (facing == CameraSource.CAMERA_FACING_FRONT) {
98 | canvas.drawText(
99 | "right eye: " + String.format("%.2f", face.getRightEyeOpenProbability()),
100 | x - ID_X_OFFSET,
101 | y,
102 | idPaint);
103 | canvas.drawText(
104 | "left eye: " + String.format("%.2f", face.getLeftEyeOpenProbability()),
105 | x + ID_X_OFFSET * 6,
106 | y,
107 | idPaint);
108 | } else {
109 | canvas.drawText(
110 | "left eye: " + String.format("%.2f", face.getLeftEyeOpenProbability()),
111 | x - ID_X_OFFSET,
112 | y,
113 | idPaint);
114 | canvas.drawText(
115 | "right eye: " + String.format("%.2f", face.getRightEyeOpenProbability()),
116 | x + ID_X_OFFSET * 6,
117 | y,
118 | idPaint);
119 | }
120 |
121 | // Draws a bounding box around the face.
122 | float xOffset = scaleX(face.getBoundingBox().width() / 2.0f);
123 | float yOffset = scaleY(face.getBoundingBox().height() / 2.0f);
124 | float left = x - xOffset;
125 | float top = y - yOffset;
126 | float right = x + xOffset;
127 | float bottom = y + yOffset;
128 | canvas.drawRect(left, top, right, bottom, boxPaint);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/ImageLabelingProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.imagelabeling;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
22 | import com.google.firebase.ml.vision.label.FirebaseVisionLabel;
23 | import com.google.firebase.ml.vision.label.FirebaseVisionLabelDetector;
24 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
25 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
26 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
27 |
28 | import java.io.IOException;
29 | import java.util.List;
30 |
31 | /** Custom Image Classifier Demo. */
32 | public class ImageLabelingProcessor extends VisionProcessorBase> {
33 |
34 | private static final String TAG = "ImageLabelingProcessor";
35 |
36 | private final FirebaseVisionLabelDetector detector;
37 |
38 | public ImageLabelingProcessor() {
39 | detector = FirebaseVision.getInstance().getVisionLabelDetector();
40 | }
41 |
42 | @Override
43 | public void stop() {
44 | try {
45 | detector.close();
46 | } catch (IOException e) {
47 | Log.e(TAG, "Exception thrown while trying to close Text Detector: " + e);
48 | }
49 | }
50 |
51 | @Override
52 | protected Task> detectInImage(FirebaseVisionImage image) {
53 | return detector.detectInImage(image);
54 | }
55 |
56 | @Override
57 | protected void onSuccess(
58 | @NonNull List labels,
59 | @NonNull FrameMetadata frameMetadata,
60 | @NonNull GraphicOverlay graphicOverlay) {
61 | graphicOverlay.clear();
62 | LabelGraphic labelGraphic = new LabelGraphic(graphicOverlay, labels);
63 | graphicOverlay.add(labelGraphic);
64 | }
65 |
66 | @Override
67 | protected void onFailure(@NonNull Exception e) {
68 | Log.w(TAG, "Label detection failed." + e);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/imagelabeling/LabelGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.imagelabeling;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 |
20 | import com.google.firebase.ml.vision.label.FirebaseVisionLabel;
21 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
22 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
23 |
24 | import java.util.List;
25 |
26 | /** Graphic instance for rendering a label within an associated graphic overlay view. */
27 | public class LabelGraphic extends Graphic {
28 |
29 | private final Paint textPaint;
30 | private final GraphicOverlay overlay;
31 |
32 | private final List labels;
33 |
34 | LabelGraphic(GraphicOverlay overlay, List labels) {
35 | super(overlay);
36 | this.overlay = overlay;
37 | this.labels = labels;
38 | textPaint = new Paint();
39 | textPaint.setColor(Color.WHITE);
40 | textPaint.setTextSize(60.0f);
41 | postInvalidate();
42 | }
43 |
44 | @Override
45 | public synchronized void draw(Canvas canvas) {
46 | float x = overlay.getWidth() / 4.0f;
47 | float y = overlay.getHeight() / 2.0f;
48 |
49 | for (FirebaseVisionLabel label : labels) {
50 | canvas.drawText(label.getLabel(), x, y, textPaint);
51 | y = y - 62.0f;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextGraphic.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.textrecognition;
15 |
16 | import android.graphics.Canvas;
17 | import android.graphics.Color;
18 | import android.graphics.Paint;
19 | import android.graphics.RectF;
20 |
21 | import com.google.firebase.ml.vision.text.FirebaseVisionText;
22 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
23 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay.Graphic;
24 |
25 | /**
26 | * Graphic instance for rendering TextBlock position, size, and ID within an associated graphic
27 | * overlay view.
28 | */
29 | public class TextGraphic extends Graphic {
30 |
31 | private static final int TEXT_COLOR = Color.WHITE;
32 | private static final float TEXT_SIZE = 54.0f;
33 | private static final float STROKE_WIDTH = 4.0f;
34 |
35 | private final Paint rectPaint;
36 | private final Paint textPaint;
37 | private final FirebaseVisionText.Element text;
38 |
39 | TextGraphic(GraphicOverlay overlay, FirebaseVisionText.Element text) {
40 | super(overlay);
41 |
42 | this.text = text;
43 |
44 | rectPaint = new Paint();
45 | rectPaint.setColor(TEXT_COLOR);
46 | rectPaint.setStyle(Paint.Style.STROKE);
47 | rectPaint.setStrokeWidth(STROKE_WIDTH);
48 |
49 | textPaint = new Paint();
50 | textPaint.setColor(TEXT_COLOR);
51 | textPaint.setTextSize(TEXT_SIZE);
52 | // Redraw the overlay, as this graphic has been added.
53 | postInvalidate();
54 | }
55 |
56 | /** Draws the text block annotations for position, size, and raw value on the supplied canvas. */
57 | @Override
58 | public void draw(Canvas canvas) {
59 | if (text == null) {
60 | throw new IllegalStateException("Attempting to draw a null text.");
61 | }
62 |
63 | // Draws the bounding box around the TextBlock.
64 | RectF rect = new RectF(text.getBoundingBox());
65 | rect.left = translateX(rect.left);
66 | rect.top = translateY(rect.top);
67 | rect.right = translateX(rect.right);
68 | rect.bottom = translateY(rect.bottom);
69 | canvas.drawRect(rect, rectPaint);
70 |
71 | // Renders the text at the bottom of the box.
72 | canvas.drawText(text.getText(), rect.left, rect.bottom, textPaint);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/google/firebase/samples/apps/mlkit/textrecognition/TextRecognitionProcessor.java:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | package com.google.firebase.samples.apps.mlkit.textrecognition;
15 |
16 | import android.support.annotation.NonNull;
17 | import android.util.Log;
18 |
19 | import com.google.android.gms.tasks.Task;
20 | import com.google.firebase.ml.vision.FirebaseVision;
21 | import com.google.firebase.ml.vision.common.FirebaseVisionImage;
22 | import com.google.firebase.ml.vision.text.FirebaseVisionText;
23 | import com.google.firebase.ml.vision.text.FirebaseVisionTextDetector;
24 | import com.google.firebase.samples.apps.mlkit.FrameMetadata;
25 | import com.google.firebase.samples.apps.mlkit.GraphicOverlay;
26 | import com.google.firebase.samples.apps.mlkit.VisionProcessorBase;
27 |
28 | import java.io.IOException;
29 | import java.util.List;
30 |
31 | /** Processor for the text recognition demo. */
32 | public class TextRecognitionProcessor extends VisionProcessorBase {
33 |
34 | private static final String TAG = "TextRecognitionProcessor";
35 |
36 | private final FirebaseVisionTextDetector detector;
37 |
38 | public TextRecognitionProcessor() {
39 | detector = FirebaseVision.getInstance().getVisionTextDetector();
40 | }
41 |
42 | @Override
43 | public void stop() {
44 | try {
45 | detector.close();
46 | } catch (IOException e) {
47 | Log.e(TAG, "Exception thrown while trying to close Text Detector: " + e);
48 | }
49 | }
50 |
51 | @Override
52 | protected Task detectInImage(FirebaseVisionImage image) {
53 | return detector.detectInImage(image);
54 | }
55 |
56 | @Override
57 | protected void onSuccess(
58 | @NonNull FirebaseVisionText results,
59 | @NonNull FrameMetadata frameMetadata,
60 | @NonNull GraphicOverlay graphicOverlay) {
61 | graphicOverlay.clear();
62 | List blocks = results.getBlocks();
63 | for (int i = 0; i < blocks.size(); i++) {
64 | List lines = blocks.get(i).getLines();
65 | for (int j = 0; j < lines.size(); j++) {
66 | List elements = lines.get(j).getElements();
67 | for (int k = 0; k < elements.size(); k++) {
68 | GraphicOverlay.Graphic textGraphic = new TextGraphic(graphicOverlay, elements.get(k));
69 | graphicOverlay.add(textGraphic);
70 |
71 | }
72 | }
73 | }
74 | }
75 |
76 | @Override
77 | protected void onFailure(@NonNull Exception e) {
78 | Log.w(TAG, "Text detection failed." + e);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-hdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_switch_camera_white_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_switch_camera_white_48dp_inset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-hdpi/ic_switch_camera_white_48dp_inset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/tile.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-hdpi/tile.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-mdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_switch_camera_white_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_switch_camera_white_48dp_inset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-mdpi/ic_switch_camera_white_48dp_inset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xhdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_switch_camera_white_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_switch_camera_white_48dp_inset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xhdpi/ic_switch_camera_white_48dp_inset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_action_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xxhdpi/ic_action_info.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_switch_camera_white_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_switch_camera_white_48dp_inset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xxhdpi/ic_switch_camera_white_48dp_inset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_switch_camera_white_48dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_switch_camera_white_48dp_inset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable-xxxhdpi/ic_switch_camera_white_48dp_inset.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/flip_cam_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable/flip_cam_512.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/mlkit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/drawable/mlkit.png
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_live_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
20 |
21 |
22 |
23 |
30 |
31 |
36 |
37 |
44 |
45 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_chooser.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
16 |
17 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_live_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
18 |
19 |
26 |
27 |
28 |
35 |
36 |
44 |
45 |
51 |
52 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_still_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
20 |
21 |
22 |
23 |
30 |
31 |
39 |
40 |
45 |
46 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/spinner_style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toggle_style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/camera_button_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #cc4285f4
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ML Kit
4 | Picture
5 |
6 | HDR Viewfinder Demo:\n\n
7 |
8 | Tap viewfinder to switch modes.\n\n
9 |
10 | Normal: Standard camera preview\n
11 | Split: Manual exposure control\n
12 | HDR: Fused HDR viewfinder\n\n
13 |
14 | Swipe up/down in Split/HDR modes to change manual exposure
15 | values.\n\n
16 |
17 | The left half of the viewfinder controls exposure time for
18 | even-numbered frames, and the right half of the viewfinder
19 | controls exposure time for odd-numbered frames
20 |
21 |
22 | Info
23 |
24 | This sample app requires camera access in order to
25 | demo the API.
26 | No back-facing sufficiently capable camera available!
27 | Camera is disabled by device policy
28 | Camera was disconnected before it was opened
29 | Camera service reported an error
30 | Unknown camera error: %s
31 | You\'ve denied a permission that the app
32 | needs for core functionality. If you selected "don\'t ask again" in the past then
33 | you need to use Settings to re-enable the permission.
34 |
35 | OK
36 | Settings
37 | Access to the camera is needed for detection
38 | This application cannot run because it does not have the camera permission. The application will now exit.
39 | Face detector dependencies cannot be downloaded due to low device storage
40 | Front
41 | Back
42 | Real-time Face Detection: MLKIT
43 | Vision detectors demo with a still image
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/app/src/screen.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.2'
11 | classpath 'com.google.gms:google-services:3.2.0'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | maven {url "/Users/gkal/Downloads/fbml-sdk/m2repository"}
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitjamuar/android-firebase-mlkit/dddc7109ba623534f254e2505a04a9d8918315f8/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Apr 29 22:29:13 EDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------