├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── jarRepositories.xml ├── misc.xml └── runConfigurations.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── say │ │ └── pytorchkotlindemo │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── model_1.pt │ ├── java │ │ └── com │ │ │ └── say │ │ │ └── pytorchkotlindemo │ │ │ ├── AnalysisResult.kt │ │ │ ├── Constants.kt │ │ │ ├── ImageClassificationOperation.kt │ │ │ ├── Listeners.kt │ │ │ ├── LiveDataViewModel.kt │ │ │ ├── MainActivity.kt │ │ │ └── Utils.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── say │ └── pytorchkotlindemo │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | 87 | # vscode local history 88 | /.history/ 89 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Vortana Say 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PytorchKotlinDemo 2 | 3 | This is an Android project written in Kotlin to show a simple image classification application that uses Android PyTorch API and a trained PyTorch model. 4 | 5 | In this demo application, user can either upload a picture or take photo. Then run the image analysis on the picture. 6 | 7 | ## Architecture 8 | 9 | I followed one of the [android google architecture component sample](https://github.com/android/architecture-components-samples/tree/master/LiveDataSample). 10 | 11 | This sample showcases the following Architecture Components: 12 | 13 | * [LiveData](https://developer.android.com/reference/android/arch/lifecycle/LiveData.html) 14 | * [ViewModels](https://developer.android.com/reference/android/arch/lifecycle/ViewModel.html) 15 | * [Data Binding](https://developer.android.com/topic/libraries/data-binding) 16 | 17 | ## Serialize a PyTorch model 18 | 19 | In [Android demo github](https://github.com/pytorch/android-demo-app), it describe in detail how the PyTorch model generated. 20 | 21 | We cannot use the saved model directly in the notebook, we need to serialize that saved model. 22 | 23 | In the Jupyter notebook where I trained the model, I can do the following 24 | 25 | 26 | ``` 27 | //load the model 28 | ckp_path = './best_model.pt' 29 | if(use_cuda): 30 | checkpoint = torch.load(ckp_path) 31 | else: 32 | checkpoint = torch.load(ckp_path, map_location=torch.device('cpu')) 33 | loaded_model.load_state_dict(checkpoint['state_dict']) 34 | ``` 35 | 36 | ``` 37 | //serialize the model 38 | loaded_model.eval() 39 | example = torch.rand(1, 3, 224, 224) 40 | if use_cuda: 41 | example = example.cuda() 42 | traced_script_module = torch.jit.trace(loaded_model, example) 43 | traced_script_module.save("./serialized_model.pt") 44 | ``` 45 | 46 | After this operations, we should have a usable model, serialized_model.pt. 47 | 48 | ## References 49 | 50 | [Android demo github](https://github.com/pytorch/android-demo-app) 51 | 52 | [PyTorch Mobile](https://pytorch.org/mobile/home/) 53 | 54 | [android google architecture component sample](https://github.com/android/architecture-components-samples/tree/master/LiveDataSample) 55 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-kapt' 4 | apply plugin: 'kotlin-android-extensions' 5 | 6 | android { 7 | compileSdkVersion 29 8 | buildToolsVersion "29.0.2" 9 | defaultConfig { 10 | applicationId "com.say.pytorchkotlindemo" 11 | minSdkVersion 21 12 | targetSdkVersion 29 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | 30 | kotlinOptions { 31 | jvmTarget = JavaVersion.VERSION_1_8.toString() 32 | } 33 | 34 | dataBinding{ 35 | enabled=true 36 | } 37 | } 38 | 39 | dependencies { 40 | def lifecycle_version = "2.2.0" 41 | def activity_version = "1.1.0" 42 | def arch_core_version = "2.1.0" 43 | def core_ktx_version = "1.1.0" 44 | def dexter_version = "6.0.2" 45 | def pytorch_version = "1.4.0" 46 | 47 | implementation fileTree(dir: 'libs', include: ['*.jar']) 48 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 49 | implementation 'androidx.appcompat:appcompat:1.1.0' 50 | implementation 'androidx.core:core-ktx:1.1.0' 51 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 52 | testImplementation 'junit:junit:4.12' 53 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 54 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 55 | implementation "com.karumi:dexter:$dexter_version" 56 | //core 57 | implementation "androidx.core:core-ktx:$core_ktx_version" 58 | // ViewModel 59 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" 60 | // LiveData 61 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" 62 | // activity 63 | implementation "androidx.activity:activity-ktx:$activity_version" 64 | // runtime 65 | implementation "androidx.arch.core:core-runtime:$arch_core_version" 66 | 67 | implementation "org.pytorch:pytorch_android:$pytorch_version" 68 | implementation "org.pytorch:pytorch_android_torchvision:$pytorch_version" 69 | } 70 | -------------------------------------------------------------------------------- /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/androidTest/java/com/say/pytorchkotlindemo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.say.pytorchkotlindemo", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/assets/model_1.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/assets/model_1.pt -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/AnalysisResult.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | class AnalysisResult( 4 | val topNClassNames: Array, 5 | val topNScores: FloatArray, 6 | val moduleForwardDuration: Long, 7 | val analysisDuration: Long 8 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | object Constants { 4 | var IMAGE_NET_CLASSNAME = arrayOf( 5 | "tench, Tinca tinca", 6 | "goldfish, Carassius auratus", 7 | "great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias", 8 | "tiger shark, Galeocerdo cuvieri", 9 | "hammerhead, hammerhead shark", 10 | "electric ray, crampfish, numbfish, torpedo", 11 | "stingray", 12 | "cock", 13 | "hen", 14 | "ostrich, Struthio camelus", 15 | "brambling, Fringilla montifringilla", 16 | "goldfinch, Carduelis carduelis", 17 | "house finch, linnet, Carpodacus mexicanus", 18 | "junco, snowbird", 19 | "indigo bunting, indigo finch, indigo bird, Passerina cyanea", 20 | "robin, American robin, Turdus migratorius", 21 | "bulbul", 22 | "jay", 23 | "magpie", 24 | "chickadee", 25 | "water ouzel, dipper", 26 | "kite", 27 | "bald eagle, American eagle, Haliaeetus leucocephalus", 28 | "vulture", 29 | "great grey owl, great gray owl, Strix nebulosa", 30 | "European fire salamander, Salamandra salamandra", 31 | "common newt, Triturus vulgaris", 32 | "eft", 33 | "spotted salamander, Ambystoma maculatum", 34 | "axolotl, mud puppy, Ambystoma mexicanum", 35 | "bullfrog, Rana catesbeiana", 36 | "tree frog, tree-frog", 37 | "tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui", 38 | "loggerhead, loggerhead turtle, Caretta caretta", 39 | "leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea", 40 | "mud turtle", 41 | "terrapin", 42 | "box turtle, box tortoise", 43 | "banded gecko", 44 | "common iguana, iguana, Iguana iguana", 45 | "American chameleon, anole, Anolis carolinensis", 46 | "whiptail, whiptail lizard", 47 | "agama", 48 | "frilled lizard, Chlamydosaurus kingi", 49 | "alligator lizard", 50 | "Gila monster, Heloderma suspectum", 51 | "green lizard, Lacerta viridis", 52 | "African chameleon, Chamaeleo chamaeleon", 53 | "Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis", 54 | "African crocodile, Nile crocodile, Crocodylus niloticus", 55 | "American alligator, Alligator mississipiensis", 56 | "triceratops", 57 | "thunder snake, worm snake, Carphophis amoenus", 58 | "ringneck snake, ring-necked snake, ring snake", 59 | "hognose snake, puff adder, sand viper", 60 | "green snake, grass snake", 61 | "king snake, kingsnake", 62 | "garter snake, grass snake", 63 | "water snake", 64 | "vine snake", 65 | "night snake, Hypsiglena torquata", 66 | "boa constrictor, Constrictor constrictor", 67 | "rock python, rock snake, Python sebae", 68 | "Indian cobra, Naja naja", 69 | "green mamba", 70 | "sea snake", 71 | "horned viper, cerastes, sand viper, horned asp, Cerastes cornutus", 72 | "diamondback, diamondback rattlesnake, Crotalus adamanteus", 73 | "sidewinder, horned rattlesnake, Crotalus cerastes", 74 | "trilobite", 75 | "harvestman, daddy longlegs, Phalangium opilio", 76 | "scorpion", 77 | "black and gold garden spider, Argiope aurantia", 78 | "barn spider, Araneus cavaticus", 79 | "garden spider, Aranea diademata", 80 | "black widow, Latrodectus mactans", 81 | "tarantula", 82 | "wolf spider, hunting spider", 83 | "tick", 84 | "centipede", 85 | "black grouse", 86 | "ptarmigan", 87 | "ruffed grouse, partridge, Bonasa umbellus", 88 | "prairie chicken, prairie grouse, prairie fowl", 89 | "peacock", 90 | "quail", 91 | "partridge", 92 | "African grey, African gray, Psittacus erithacus", 93 | "macaw", 94 | "sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita", 95 | "lorikeet", 96 | "coucal", 97 | "bee eater", 98 | "hornbill", 99 | "hummingbird", 100 | "jacamar", 101 | "toucan", 102 | "drake", 103 | "red-breasted merganser, Mergus serrator", 104 | "goose", 105 | "black swan, Cygnus atratus", 106 | "tusker", 107 | "echidna, spiny anteater, anteater", 108 | "platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus", 109 | "wallaby, brush kangaroo", 110 | "koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus", 111 | "wombat", 112 | "jellyfish", 113 | "sea anemone, anemone", 114 | "brain coral", 115 | "flatworm, platyhelminth", 116 | "nematode, nematode worm, roundworm", 117 | "conch", 118 | "snail", 119 | "slug", 120 | "sea slug, nudibranch", 121 | "chiton, coat-of-mail shell, sea cradle, polyplacophore", 122 | "chambered nautilus, pearly nautilus, nautilus", 123 | "Dungeness crab, Cancer magister", 124 | "rock crab, Cancer irroratus", 125 | "fiddler crab", 126 | "king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica", 127 | "American lobster, Northern lobster, Maine lobster, Homarus americanus", 128 | "spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish", 129 | "crayfish, crawfish, crawdad, crawdaddy", 130 | "hermit crab", 131 | "isopod", 132 | "white stork, Ciconia ciconia", 133 | "black stork, Ciconia nigra", 134 | "spoonbill", 135 | "flamingo", 136 | "little blue heron, Egretta caerulea", 137 | "American egret, great white heron, Egretta albus", 138 | "bittern", 139 | "crane", 140 | "limpkin, Aramus pictus", 141 | "European gallinule, Porphyrio porphyrio", 142 | "American coot, marsh hen, mud hen, water hen, Fulica americana", 143 | "bustard", 144 | "ruddy turnstone, Arenaria interpres", 145 | "red-backed sandpiper, dunlin, Erolia alpina", 146 | "redshank, Tringa totanus", 147 | "dowitcher", 148 | "oystercatcher, oyster catcher", 149 | "pelican", 150 | "king penguin, Aptenodytes patagonica", 151 | "albatross, mollymawk", 152 | "grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus", 153 | "killer whale, killer, orca, grampus, sea wolf, Orcinus orca", 154 | "dugong, Dugong dugon", 155 | "sea lion", 156 | "Chihuahua", 157 | "Japanese spaniel", 158 | "Maltese dog, Maltese terrier, Maltese", 159 | "Pekinese, Pekingese, Peke", 160 | "Shih-Tzu", 161 | "Blenheim spaniel", 162 | "papillon", 163 | "toy terrier", 164 | "Rhodesian ridgeback", 165 | "Afghan hound, Afghan", 166 | "basset, basset hound", 167 | "beagle", 168 | "bloodhound, sleuthhound", 169 | "bluetick", 170 | "black-and-tan coonhound", 171 | "Walker hound, Walker foxhound", 172 | "English foxhound", 173 | "redbone", 174 | "borzoi, Russian wolfhound", 175 | "Irish wolfhound", 176 | "Italian greyhound", 177 | "whippet", 178 | "Ibizan hound, Ibizan Podenco", 179 | "Norwegian elkhound, elkhound", 180 | "otterhound, otter hound", 181 | "Saluki, gazelle hound", 182 | "Scottish deerhound, deerhound", 183 | "Weimaraner", 184 | "Staffordshire bullterrier, Staffordshire bull terrier", 185 | "American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier", 186 | "Bedlington terrier", 187 | "Border terrier", 188 | "Kerry blue terrier", 189 | "Irish terrier", 190 | "Norfolk terrier", 191 | "Norwich terrier", 192 | "Yorkshire terrier", 193 | "wire-haired fox terrier", 194 | "Lakeland terrier", 195 | "Sealyham terrier, Sealyham", 196 | "Airedale, Airedale terrier", 197 | "cairn, cairn terrier", 198 | "Australian terrier", 199 | "Dandie Dinmont, Dandie Dinmont terrier", 200 | "Boston bull, Boston terrier", 201 | "miniature schnauzer", 202 | "giant schnauzer", 203 | "standard schnauzer", 204 | "Scotch terrier, Scottish terrier, Scottie", 205 | "Tibetan terrier, chrysanthemum dog", 206 | "silky terrier, Sydney silky", 207 | "soft-coated wheaten terrier", 208 | "West Highland white terrier", 209 | "Lhasa, Lhasa apso", 210 | "flat-coated retriever", 211 | "curly-coated retriever", 212 | "golden retriever", 213 | "Labrador retriever", 214 | "Chesapeake Bay retriever", 215 | "German short-haired pointer", 216 | "vizsla, Hungarian pointer", 217 | "English setter", 218 | "Irish setter, red setter", 219 | "Gordon setter", 220 | "Brittany spaniel", 221 | "clumber, clumber spaniel", 222 | "English springer, English springer spaniel", 223 | "Welsh springer spaniel", 224 | "cocker spaniel, English cocker spaniel, cocker", 225 | "Sussex spaniel", 226 | "Irish water spaniel", 227 | "kuvasz", 228 | "schipperke", 229 | "groenendael", 230 | "malinois", 231 | "briard", 232 | "kelpie", 233 | "komondor", 234 | "Old English sheepdog, bobtail", 235 | "Shetland sheepdog, Shetland sheep dog, Shetland", 236 | "collie", 237 | "Border collie", 238 | "Bouvier des Flandres, Bouviers des Flandres", 239 | "Rottweiler", 240 | "German shepherd, German shepherd dog, German police dog, alsatian", 241 | "Doberman, Doberman pinscher", 242 | "miniature pinscher", 243 | "Greater Swiss Mountain dog", 244 | "Bernese mountain dog", 245 | "Appenzeller", 246 | "EntleBucher", 247 | "boxer", 248 | "bull mastiff", 249 | "Tibetan mastiff", 250 | "French bulldog", 251 | "Great Dane", 252 | "Saint Bernard, St Bernard", 253 | "Eskimo dog, husky", 254 | "malamute, malemute, Alaskan malamute", 255 | "Siberian husky", 256 | "dalmatian, coach dog, carriage dog", 257 | "affenpinscher, monkey pinscher, monkey dog", 258 | "basenji", 259 | "pug, pug-dog", 260 | "Leonberg", 261 | "Newfoundland, Newfoundland dog", 262 | "Great Pyrenees", 263 | "Samoyed, Samoyede", 264 | "Pomeranian", 265 | "chow, chow chow", 266 | "keeshond", 267 | "Brabancon griffon", 268 | "Pembroke, Pembroke Welsh corgi", 269 | "Cardigan, Cardigan Welsh corgi", 270 | "toy poodle", 271 | "miniature poodle", 272 | "standard poodle", 273 | "Mexican hairless", 274 | "timber wolf, grey wolf, gray wolf, Canis lupus", 275 | "white wolf, Arctic wolf, Canis lupus tundrarum", 276 | "red wolf, maned wolf, Canis rufus, Canis niger", 277 | "coyote, prairie wolf, brush wolf, Canis latrans", 278 | "dingo, warrigal, warragal, Canis dingo", 279 | "dhole, Cuon alpinus", 280 | "African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus", 281 | "hyena, hyaena", 282 | "red fox, Vulpes vulpes", 283 | "kit fox, Vulpes macrotis", 284 | "Arctic fox, white fox, Alopex lagopus", 285 | "grey fox, gray fox, Urocyon cinereoargenteus", 286 | "tabby, tabby cat", 287 | "tiger cat", 288 | "Persian cat", 289 | "Siamese cat, Siamese", 290 | "Egyptian cat", 291 | "cougar, puma, catamount, mountain lion, painter, panther, Felis concolor", 292 | "lynx, catamount", 293 | "leopard, Panthera pardus", 294 | "snow leopard, ounce, Panthera uncia", 295 | "jaguar, panther, Panthera onca, Felis onca", 296 | "lion, king of beasts, Panthera leo", 297 | "tiger, Panthera tigris", 298 | "cheetah, chetah, Acinonyx jubatus", 299 | "brown bear, bruin, Ursus arctos", 300 | "American black bear, black bear, Ursus americanus, Euarctos americanus", 301 | "ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus", 302 | "sloth bear, Melursus ursinus, Ursus ursinus", 303 | "mongoose", 304 | "meerkat, mierkat", 305 | "tiger beetle", 306 | "ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle", 307 | "ground beetle, carabid beetle", 308 | "long-horned beetle, longicorn, longicorn beetle", 309 | "leaf beetle, chrysomelid", 310 | "dung beetle", 311 | "rhinoceros beetle", 312 | "weevil", 313 | "fly", 314 | "bee", 315 | "ant, emmet, pismire", 316 | "grasshopper, hopper", 317 | "cricket", 318 | "walking stick, walkingstick, stick insect", 319 | "cockroach, roach", 320 | "mantis, mantid", 321 | "cicada, cicala", 322 | "leafhopper", 323 | "lacewing, lacewing fly", 324 | "dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk", 325 | "damselfly", 326 | "admiral", 327 | "ringlet, ringlet butterfly", 328 | "monarch, monarch butterfly, milkweed butterfly, Danaus plexippus", 329 | "cabbage butterfly", 330 | "sulphur butterfly, sulfur butterfly", 331 | "lycaenid, lycaenid butterfly", 332 | "starfish, sea star", 333 | "sea urchin", 334 | "sea cucumber, holothurian", 335 | "wood rabbit, cottontail, cottontail rabbit", 336 | "hare", 337 | "Angora, Angora rabbit", 338 | "hamster", 339 | "porcupine, hedgehog", 340 | "fox squirrel, eastern fox squirrel, Sciurus niger", 341 | "marmot", 342 | "beaver", 343 | "guinea pig, Cavia cobaya", 344 | "sorrel", 345 | "zebra", 346 | "hog, pig, grunter, squealer, Sus scrofa", 347 | "wild boar, boar, Sus scrofa", 348 | "warthog", 349 | "hippopotamus, hippo, river horse, Hippopotamus amphibius", 350 | "ox", 351 | "water buffalo, water ox, Asiatic buffalo, Bubalus bubalis", 352 | "bison", 353 | "ram, tup", 354 | "bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis", 355 | "ibex, Capra ibex", 356 | "hartebeest", 357 | "impala, Aepyceros melampus", 358 | "gazelle", 359 | "Arabian camel, dromedary, Camelus dromedarius", 360 | "llama", 361 | "weasel", 362 | "mink", 363 | "polecat, fitch, foulmart, foumart, Mustela putorius", 364 | "black-footed ferret, ferret, Mustela nigripes", 365 | "otter", 366 | "skunk, polecat, wood pussy", 367 | "badger", 368 | "armadillo", 369 | "three-toed sloth, ai, Bradypus tridactylus", 370 | "orangutan, orang, orangutang, Pongo pygmaeus", 371 | "gorilla, Gorilla gorilla", 372 | "chimpanzee, chimp, Pan troglodytes", 373 | "gibbon, Hylobates lar", 374 | "siamang, Hylobates syndactylus, Symphalangus syndactylus", 375 | "guenon, guenon monkey", 376 | "patas, hussar monkey, Erythrocebus patas", 377 | "baboon", 378 | "macaque", 379 | "langur", 380 | "colobus, colobus monkey", 381 | "proboscis monkey, Nasalis larvatus", 382 | "marmoset", 383 | "capuchin, ringtail, Cebus capucinus", 384 | "howler monkey, howler", 385 | "titi, titi monkey", 386 | "spider monkey, Ateles geoffroyi", 387 | "squirrel monkey, Saimiri sciureus", 388 | "Madagascar cat, ring-tailed lemur, Lemur catta", 389 | "indri, indris, Indri indri, Indri brevicaudatus", 390 | "Indian elephant, Elephas maximus", 391 | "African elephant, Loxodonta africana", 392 | "lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens", 393 | "giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca", 394 | "barracouta, snoek", 395 | "eel", 396 | "coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch", 397 | "rock beauty, Holocanthus tricolor", 398 | "anemone fish", 399 | "sturgeon", 400 | "gar, garfish, garpike, billfish, Lepisosteus osseus", 401 | "lionfish", 402 | "puffer, pufferfish, blowfish, globefish", 403 | "abacus", 404 | "abaya", 405 | "academic gown, academic robe, judge's robe", 406 | "accordion, piano accordion, squeeze box", 407 | "acoustic guitar", 408 | "aircraft carrier, carrier, flattop, attack aircraft carrier", 409 | "airliner", 410 | "airship, dirigible", 411 | "altar", 412 | "ambulance", 413 | "amphibian, amphibious vehicle", 414 | "analog clock", 415 | "apiary, bee house", 416 | "apron", 417 | "ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin", 418 | "assault rifle, assault gun", 419 | "backpack, back pack, knapsack, packsack, rucksack, haversack", 420 | "bakery, bakeshop, bakehouse", 421 | "balance beam, beam", 422 | "balloon", 423 | "ballpoint, ballpoint pen, ballpen, Biro", 424 | "Band Aid", 425 | "banjo", 426 | "bannister, banister, balustrade, balusters, handrail", 427 | "barbell", 428 | "barber chair", 429 | "barbershop", 430 | "barn", 431 | "barometer", 432 | "barrel, cask", 433 | "barrow, garden cart, lawn cart, wheelbarrow", 434 | "baseball", 435 | "basketball", 436 | "bassinet", 437 | "bassoon", 438 | "bathing cap, swimming cap", 439 | "bath towel", 440 | "bathtub, bathing tub, bath, tub", 441 | "beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon", 442 | "beacon, lighthouse, beacon light, pharos", 443 | "beaker", 444 | "bearskin, busby, shako", 445 | "beer bottle", 446 | "beer glass", 447 | "bell cote, bell cot", 448 | "bib", 449 | "bicycle-built-for-two, tandem bicycle, tandem", 450 | "bikini, two-piece", 451 | "binder, ring-binder", 452 | "binoculars, field glasses, opera glasses", 453 | "birdhouse", 454 | "boathouse", 455 | "bobsled, bobsleigh, bob", 456 | "bolo tie, bolo, bola tie, bola", 457 | "bonnet, poke bonnet", 458 | "bookcase", 459 | "bookshop, bookstore, bookstall", 460 | "bottlecap", 461 | "bow", 462 | "bow tie, bow-tie, bowtie", 463 | "brass, memorial tablet, plaque", 464 | "brassiere, bra, bandeau", 465 | "breakwater, groin, groyne, mole, bulwark, seawall, jetty", 466 | "breastplate, aegis, egis", 467 | "broom", 468 | "bucket, pail", 469 | "buckle", 470 | "bulletproof vest", 471 | "bullet train, bullet", 472 | "butcher shop, meat market", 473 | "cab, hack, taxi, taxicab", 474 | "caldron, cauldron", 475 | "candle, taper, wax light", 476 | "cannon", 477 | "canoe", 478 | "can opener, tin opener", 479 | "cardigan", 480 | "car mirror", 481 | "carousel, carrousel, merry-go-round, roundabout, whirligig", 482 | "carpenter's kit, tool kit", 483 | "carton", 484 | "car wheel", 485 | "cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM", 486 | "cassette", 487 | "cassette player", 488 | "castle", 489 | "catamaran", 490 | "CD player", 491 | "cello, violoncello", 492 | "cellular telephone, cellular phone, cellphone, cell, mobile phone", 493 | "chain", 494 | "chainlink fence", 495 | "chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour", 496 | "chain saw, chainsaw", 497 | "chest", 498 | "chiffonier, commode", 499 | "chime, bell, gong", 500 | "china cabinet, china closet", 501 | "Christmas stocking", 502 | "church, church building", 503 | "cinema, movie theater, movie theatre, movie house, picture palace", 504 | "cleaver, meat cleaver, chopper", 505 | "cliff dwelling", 506 | "cloak", 507 | "clog, geta, patten, sabot", 508 | "cocktail shaker", 509 | "coffee mug", 510 | "coffeepot", 511 | "coil, spiral, volute, whorl, helix", 512 | "combination lock", 513 | "computer keyboard, keypad", 514 | "confectionery, confectionary, candy store", 515 | "container ship, containership, container vessel", 516 | "convertible", 517 | "corkscrew, bottle screw", 518 | "cornet, horn, trumpet, trump", 519 | "cowboy boot", 520 | "cowboy hat, ten-gallon hat", 521 | "cradle", 522 | "crane", 523 | "crash helmet", 524 | "crate", 525 | "crib, cot", 526 | "Crock Pot", 527 | "croquet ball", 528 | "crutch", 529 | "cuirass", 530 | "dam, dike, dyke", 531 | "desk", 532 | "desktop computer", 533 | "dial telephone, dial phone", 534 | "diaper, nappy, napkin", 535 | "digital clock", 536 | "digital watch", 537 | "dining table, board", 538 | "dishrag, dishcloth", 539 | "dishwasher, dish washer, dishwashing machine", 540 | "disk brake, disc brake", 541 | "dock, dockage, docking facility", 542 | "dogsled, dog sled, dog sleigh", 543 | "dome", 544 | "doormat, welcome mat", 545 | "drilling platform, offshore rig", 546 | "drum, membranophone, tympan", 547 | "drumstick", 548 | "dumbbell", 549 | "Dutch oven", 550 | "electric fan, blower", 551 | "electric guitar", 552 | "electric locomotive", 553 | "entertainment center", 554 | "envelope", 555 | "espresso maker", 556 | "face powder", 557 | "feather boa, boa", 558 | "file, file cabinet, filing cabinet", 559 | "fireboat", 560 | "fire engine, fire truck", 561 | "fire screen, fireguard", 562 | "flagpole, flagstaff", 563 | "flute, transverse flute", 564 | "folding chair", 565 | "football helmet", 566 | "forklift", 567 | "fountain", 568 | "fountain pen", 569 | "four-poster", 570 | "freight car", 571 | "French horn, horn", 572 | "frying pan, frypan, skillet", 573 | "fur coat", 574 | "garbage truck, dustcart", 575 | "gasmask, respirator, gas helmet", 576 | "gas pump, gasoline pump, petrol pump, island dispenser", 577 | "goblet", 578 | "go-kart", 579 | "golf ball", 580 | "golfcart, golf cart", 581 | "gondola", 582 | "gong, tam-tam", 583 | "gown", 584 | "grand piano, grand", 585 | "greenhouse, nursery, glasshouse", 586 | "grille, radiator grille", 587 | "grocery store, grocery, food market, market", 588 | "guillotine", 589 | "hair slide", 590 | "hair spray", 591 | "half track", 592 | "hammer", 593 | "hamper", 594 | "hand blower, blow dryer, blow drier, hair dryer, hair drier", 595 | "hand-held computer, hand-held microcomputer", 596 | "handkerchief, hankie, hanky, hankey", 597 | "hard disc, hard disk, fixed disk", 598 | "harmonica, mouth organ, harp, mouth harp", 599 | "harp", 600 | "harvester, reaper", 601 | "hatchet", 602 | "holster", 603 | "home theater, home theatre", 604 | "honeycomb", 605 | "hook, claw", 606 | "hoopskirt, crinoline", 607 | "horizontal bar, high bar", 608 | "horse cart, horse-cart", 609 | "hourglass", 610 | "iPod", 611 | "iron, smoothing iron", 612 | "jack-o'-lantern", 613 | "jean, blue jean, denim", 614 | "jeep, landrover", 615 | "jersey, T-shirt, tee shirt", 616 | "jigsaw puzzle", 617 | "jinrikisha, ricksha, rickshaw", 618 | "joystick", 619 | "kimono", 620 | "knee pad", 621 | "knot", 622 | "lab coat, laboratory coat", 623 | "ladle", 624 | "lampshade, lamp shade", 625 | "laptop, laptop computer", 626 | "lawn mower, mower", 627 | "lens cap, lens cover", 628 | "letter opener, paper knife, paperknife", 629 | "library", 630 | "lifeboat", 631 | "lighter, light, igniter, ignitor", 632 | "limousine, limo", 633 | "liner, ocean liner", 634 | "lipstick, lip rouge", 635 | "Loafer", 636 | "lotion", 637 | "loudspeaker, speaker, speaker unit, loudspeaker system, speaker system", 638 | "loupe, jeweler's loupe", 639 | "lumbermill, sawmill", 640 | "magnetic compass", 641 | "mailbag, postbag", 642 | "mailbox, letter box", 643 | "maillot", 644 | "maillot, tank suit", 645 | "manhole cover", 646 | "maraca", 647 | "marimba, xylophone", 648 | "mask", 649 | "matchstick", 650 | "maypole", 651 | "maze, labyrinth", 652 | "measuring cup", 653 | "medicine chest, medicine cabinet", 654 | "megalith, megalithic structure", 655 | "microphone, mike", 656 | "microwave, microwave oven", 657 | "military uniform", 658 | "milk can", 659 | "minibus", 660 | "miniskirt, mini", 661 | "minivan", 662 | "missile", 663 | "mitten", 664 | "mixing bowl", 665 | "mobile home, manufactured home", 666 | "Model T", 667 | "modem", 668 | "monastery", 669 | "monitor", 670 | "moped", 671 | "mortar", 672 | "mortarboard", 673 | "mosque", 674 | "mosquito net", 675 | "motor scooter, scooter", 676 | "mountain bike, all-terrain bike, off-roader", 677 | "mountain tent", 678 | "mouse, computer mouse", 679 | "mousetrap", 680 | "moving van", 681 | "muzzle", 682 | "nail", 683 | "neck brace", 684 | "necklace", 685 | "nipple", 686 | "notebook, notebook computer", 687 | "obelisk", 688 | "oboe, hautboy, hautbois", 689 | "ocarina, sweet potato", 690 | "odometer, hodometer, mileometer, milometer", 691 | "oil filter", 692 | "organ, pipe organ", 693 | "oscilloscope, scope, cathode-ray oscilloscope, CRO", 694 | "overskirt", 695 | "oxcart", 696 | "oxygen mask", 697 | "packet", 698 | "paddle, boat paddle", 699 | "paddlewheel, paddle wheel", 700 | "padlock", 701 | "paintbrush", 702 | "pajama, pyjama, pj's, jammies", 703 | "palace", 704 | "panpipe, pandean pipe, syrinx", 705 | "paper towel", 706 | "parachute, chute", 707 | "parallel bars, bars", 708 | "park bench", 709 | "parking meter", 710 | "passenger car, coach, carriage", 711 | "patio, terrace", 712 | "pay-phone, pay-station", 713 | "pedestal, plinth, footstall", 714 | "pencil box, pencil case", 715 | "pencil sharpener", 716 | "perfume, essence", 717 | "Petri dish", 718 | "photocopier", 719 | "pick, plectrum, plectron", 720 | "pickelhaube", 721 | "picket fence, paling", 722 | "pickup, pickup truck", 723 | "pier", 724 | "piggy bank, penny bank", 725 | "pill bottle", 726 | "pillow", 727 | "ping-pong ball", 728 | "pinwheel", 729 | "pirate, pirate ship", 730 | "pitcher, ewer", 731 | "plane, carpenter's plane, woodworking plane", 732 | "planetarium", 733 | "plastic bag", 734 | "plate rack", 735 | "plow, plough", 736 | "plunger, plumber's helper", 737 | "Polaroid camera, Polaroid Land camera", 738 | "pole", 739 | "police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria", 740 | "poncho", 741 | "pool table, billiard table, snooker table", 742 | "pop bottle, soda bottle", 743 | "pot, flowerpot", 744 | "potter's wheel", 745 | "power drill", 746 | "prayer rug, prayer mat", 747 | "printer", 748 | "prison, prison house", 749 | "projectile, missile", 750 | "projector", 751 | "puck, hockey puck", 752 | "punching bag, punch bag, punching ball, punchball", 753 | "purse", 754 | "quill, quill pen", 755 | "quilt, comforter, comfort, puff", 756 | "racer, race car, racing car", 757 | "racket, racquet", 758 | "radiator", 759 | "radio, wireless", 760 | "radio telescope, radio reflector", 761 | "rain barrel", 762 | "recreational vehicle, RV, R.V.", 763 | "reel", 764 | "reflex camera", 765 | "refrigerator, icebox", 766 | "remote control, remote", 767 | "restaurant, eating house, eating place, eatery", 768 | "revolver, six-gun, six-shooter", 769 | "rifle", 770 | "rocking chair, rocker", 771 | "rotisserie", 772 | "rubber eraser, rubber, pencil eraser", 773 | "rugby ball", 774 | "rule, ruler", 775 | "running shoe", 776 | "safe", 777 | "safety pin", 778 | "saltshaker, salt shaker", 779 | "sandal", 780 | "sarong", 781 | "sax, saxophone", 782 | "scabbard", 783 | "scale, weighing machine", 784 | "school bus", 785 | "schooner", 786 | "scoreboard", 787 | "screen, CRT screen", 788 | "screw", 789 | "screwdriver", 790 | "seat belt, seatbelt", 791 | "sewing machine", 792 | "shield, buckler", 793 | "shoe shop, shoe-shop, shoe store", 794 | "shoji", 795 | "shopping basket", 796 | "shopping cart", 797 | "shovel", 798 | "shower cap", 799 | "shower curtain", 800 | "ski", 801 | "ski mask", 802 | "sleeping bag", 803 | "slide rule, slipstick", 804 | "sliding door", 805 | "slot, one-armed bandit", 806 | "snorkel", 807 | "snowmobile", 808 | "snowplow, snowplough", 809 | "soap dispenser", 810 | "soccer ball", 811 | "sock", 812 | "solar dish, solar collector, solar furnace", 813 | "sombrero", 814 | "soup bowl", 815 | "space bar", 816 | "space heater", 817 | "space shuttle", 818 | "spatula", 819 | "speedboat", 820 | "spider web, spider's web", 821 | "spindle", 822 | "sports car, sport car", 823 | "spotlight, spot", 824 | "stage", 825 | "steam locomotive", 826 | "steel arch bridge", 827 | "steel drum", 828 | "stethoscope", 829 | "stole", 830 | "stone wall", 831 | "stopwatch, stop watch", 832 | "stove", 833 | "strainer", 834 | "streetcar, tram, tramcar, trolley, trolley car", 835 | "stretcher", 836 | "studio couch, day bed", 837 | "stupa, tope", 838 | "submarine, pigboat, sub, U-boat", 839 | "suit, suit of clothes", 840 | "sundial", 841 | "sunglass", 842 | "sunglasses, dark glasses, shades", 843 | "sunscreen, sunblock, sun blocker", 844 | "suspension bridge", 845 | "swab, swob, mop", 846 | "sweatshirt", 847 | "swimming trunks, bathing trunks", 848 | "swing", 849 | "switch, electric switch, electrical switch", 850 | "syringe", 851 | "table lamp", 852 | "tank, army tank, armored combat vehicle, armoured combat vehicle", 853 | "tape player", 854 | "teapot", 855 | "teddy, teddy bear", 856 | "television, television system", 857 | "tennis ball", 858 | "thatch, thatched roof", 859 | "theater curtain, theatre curtain", 860 | "thimble", 861 | "thresher, thrasher, threshing machine", 862 | "throne", 863 | "tile roof", 864 | "toaster", 865 | "tobacco shop, tobacconist shop, tobacconist", 866 | "toilet seat", 867 | "torch", 868 | "totem pole", 869 | "tow truck, tow car, wrecker", 870 | "toyshop", 871 | "tractor", 872 | "trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi", 873 | "tray", 874 | "trench coat", 875 | "tricycle, trike, velocipede", 876 | "trimaran", 877 | "tripod", 878 | "triumphal arch", 879 | "trolleybus, trolley coach, trackless trolley", 880 | "trombone", 881 | "tub, vat", 882 | "turnstile", 883 | "typewriter keyboard", 884 | "umbrella", 885 | "unicycle, monocycle", 886 | "upright, upright piano", 887 | "vacuum, vacuum cleaner", 888 | "vase", 889 | "vault", 890 | "velvet", 891 | "vending machine", 892 | "vestment", 893 | "viaduct", 894 | "violin, fiddle", 895 | "volleyball", 896 | "waffle iron", 897 | "wall clock", 898 | "wallet, billfold, notecase, pocketbook", 899 | "wardrobe, closet, press", 900 | "warplane, military plane", 901 | "washbasin, handbasin, washbowl, lavabo, wash-hand basin", 902 | "washer, automatic washer, washing machine", 903 | "water bottle", 904 | "water jug", 905 | "water tower", 906 | "whiskey jug", 907 | "whistle", 908 | "wig", 909 | "window screen", 910 | "window shade", 911 | "Windsor tie", 912 | "wine bottle", 913 | "wing", 914 | "wok", 915 | "wooden spoon", 916 | "wool, woolen, woollen", 917 | "worm fence, snake fence, snake-rail fence, Virginia fence", 918 | "wreck", 919 | "yawl", 920 | "yurt", 921 | "web site, website, internet site, site", 922 | "comic book", 923 | "crossword puzzle, crossword", 924 | "street sign", 925 | "traffic light, traffic signal, stoplight", 926 | "book jacket, dust cover, dust jacket, dust wrapper", 927 | "menu", 928 | "plate", 929 | "guacamole", 930 | "consomme", 931 | "hot pot, hotpot", 932 | "trifle", 933 | "ice cream, icecream", 934 | "ice lolly, lolly, lollipop, popsicle", 935 | "French loaf", 936 | "bagel, beigel", 937 | "pretzel", 938 | "cheeseburger", 939 | "hotdog, hot dog, red hot", 940 | "mashed potato", 941 | "head cabbage", 942 | "broccoli", 943 | "cauliflower", 944 | "zucchini, courgette", 945 | "spaghetti squash", 946 | "acorn squash", 947 | "butternut squash", 948 | "cucumber, cuke", 949 | "artichoke, globe artichoke", 950 | "bell pepper", 951 | "cardoon", 952 | "mushroom", 953 | "Granny Smith", 954 | "strawberry", 955 | "orange", 956 | "lemon", 957 | "fig", 958 | "pineapple, ananas", 959 | "banana", 960 | "jackfruit, jak, jack", 961 | "custard apple", 962 | "pomegranate", 963 | "hay", 964 | "carbonara", 965 | "chocolate sauce, chocolate syrup", 966 | "dough", 967 | "meat loaf, meatloaf", 968 | "pizza, pizza pie", 969 | "potpie", 970 | "burrito", 971 | "red wine", 972 | "espresso", 973 | "cup", 974 | "eggnog", 975 | "alp", 976 | "bubble", 977 | "cliff, drop, drop-off", 978 | "coral reef", 979 | "geyser", 980 | "lakeside, lakeshore", 981 | "promontory, headland, head, foreland", 982 | "sandbar, sand bar", 983 | "seashore, coast, seacoast, sea-coast", 984 | "valley, vale", 985 | "volcano", 986 | "ballplayer, baseball player", 987 | "groom, bridegroom", 988 | "scuba diver", 989 | "rapeseed", 990 | "daisy", 991 | "yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum", 992 | "corn", 993 | "acorn", 994 | "hip, rose hip, rosehip", 995 | "buckeye, horse chestnut, conker", 996 | "coral fungus", 997 | "agaric", 998 | "gyromitra", 999 | "stinkhorn, carrion fungus", 1000 | "earthstar", 1001 | "hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa", 1002 | "bolete", 1003 | "ear, spike, capitulum", 1004 | "toilet tissue, toilet paper, bathroom tissue" 1005 | ) 1006 | } 1007 | -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/ImageClassificationOperation.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import android.graphics.Bitmap 4 | import android.os.SystemClock 5 | import android.util.Log 6 | import androidx.lifecycle.LiveData 7 | import androidx.lifecycle.MutableLiveData 8 | import kotlinx.coroutines.CoroutineDispatcher 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.withContext 11 | import org.pytorch.IValue 12 | import org.pytorch.Module 13 | import org.pytorch.Tensor 14 | import org.pytorch.torchvision.TensorImageUtils 15 | 16 | const val TOP_K = 3 17 | 18 | class ImageClassificationOperation(private val ioDispatcher: CoroutineDispatcher) : ImageAnalysis { 19 | private var analyzeImageErrorState: Boolean = false 20 | private var module: Module? = null 21 | private var inputTensor: Tensor? = null 22 | 23 | private val _result = MutableLiveData(AnalysisResult(arrayOf("Result"), floatArrayOf(0F), 0, 0)) 24 | override val result: LiveData = _result 25 | 26 | override suspend fun analyzeImage( 27 | bitmap: Bitmap, 28 | moduleFileAbsoluteFilePath: String 29 | ) { 30 | // Force Main thread 31 | withContext(Dispatchers.Main) { 32 | _result.value = AnalysisResult(arrayOf("Analyse Image..."), floatArrayOf(0F), 0, 0) 33 | _result.value = analyseImageImpl(bitmap, moduleFileAbsoluteFilePath) 34 | } 35 | } 36 | 37 | private suspend fun analyseImageImpl( 38 | bitmap: Bitmap, 39 | moduleFileAbsoluteFilePath: String 40 | ): AnalysisResult? = withContext(ioDispatcher) { 41 | if (analyzeImageErrorState) { 42 | null 43 | } 44 | 45 | try { 46 | 47 | module = Module.load(moduleFileAbsoluteFilePath) 48 | 49 | val startTime = SystemClock.elapsedRealtime() 50 | 51 | inputTensor = TensorImageUtils.bitmapToFloat32Tensor( 52 | bitmap, 53 | TensorImageUtils.TORCHVISION_NORM_MEAN_RGB, 54 | TensorImageUtils.TORCHVISION_NORM_STD_RGB 55 | ) 56 | 57 | val moduleForwardStartTime = SystemClock.elapsedRealtime() 58 | val outputTensor = module?.forward(IValue.from(inputTensor))?.toTensor() 59 | val moduleForwardDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime 60 | 61 | val scores = outputTensor?.dataAsFloatArray 62 | scores?.let { 63 | val ixs = Utils.topK(scores, TOP_K) 64 | val topKClassNames = Array(TOP_K) { i -> (i * i).toString() } 65 | val topKScores = FloatArray(TOP_K) 66 | for (i in 0 until TOP_K) { 67 | val ix = ixs[i] 68 | if (ix <= Constants.IMAGE_NET_CLASSNAME.size) { 69 | topKClassNames[i] = Constants.IMAGE_NET_CLASSNAME[ix] 70 | } 71 | topKScores[i] = scores[ix] 72 | } 73 | val analysisDuration = SystemClock.elapsedRealtime() - startTime 74 | AnalysisResult( 75 | topKClassNames, 76 | topKScores, 77 | moduleForwardDuration, 78 | analysisDuration 79 | ) 80 | } 81 | } catch (e: Exception) { 82 | Log.e("TAG", "Error during image analysis", e) 83 | analyzeImageErrorState = true 84 | AnalysisResult( 85 | arrayOf("Error during image analysis " + e.message), 86 | floatArrayOf(0F), 87 | 0, 88 | 0 89 | ) 90 | null 91 | } 92 | } 93 | } 94 | 95 | interface ImageAnalysis { 96 | val result: LiveData 97 | suspend fun analyzeImage( 98 | bitmap: Bitmap, 99 | moduleFileAbsoluteFilePath: String 100 | ) 101 | } -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/Listeners.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import android.content.Intent 4 | import android.provider.MediaStore 5 | import androidx.appcompat.app.AlertDialog 6 | import androidx.appcompat.app.AppCompatActivity 7 | 8 | class Listeners(private val activity: AppCompatActivity) { 9 | 10 | fun showPictureDialog() { 11 | val pictureDialog = AlertDialog.Builder(activity) 12 | pictureDialog.setTitle("Select Action") 13 | val pictureDialogItems = arrayOf("Select photo from gallery", "Capture photo from camera") 14 | pictureDialog.setItems( 15 | pictureDialogItems 16 | ) { _, which -> 17 | when (which) { 18 | 0 -> choosePhotoFromGallary() 19 | 1 -> takePhotoFromCamera() 20 | } 21 | } 22 | pictureDialog.show() 23 | } 24 | 25 | private fun takePhotoFromCamera() { 26 | val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) 27 | activity.startActivityForResult(intent, CAMERA) 28 | } 29 | 30 | private fun choosePhotoFromGallary() { 31 | val galleryIntent = Intent( 32 | Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI 33 | ) 34 | 35 | activity.startActivityForResult(galleryIntent, GALLERY) 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/LiveDataViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import android.app.Application 4 | import android.graphics.drawable.BitmapDrawable 5 | import android.widget.ImageView 6 | import androidx.lifecycle.AndroidViewModel 7 | import androidx.lifecycle.ViewModel 8 | import androidx.lifecycle.ViewModelProvider 9 | import androidx.lifecycle.viewModelScope 10 | import com.say.pytorchkotlindemo.Utils.assetFilePath 11 | import kotlinx.coroutines.Dispatchers 12 | import kotlinx.coroutines.launch 13 | import java.io.File 14 | 15 | class LiveDataViewModel( 16 | private val app: Application, 17 | private val imageAnalysis: ImageAnalysis 18 | ) : AndroidViewModel(app) { 19 | 20 | private var moduleAssetName: String = "model_1.pt" 21 | 22 | fun analyseTheImage(imageView: ImageView) { 23 | viewModelScope.launch { 24 | val drawable = imageView.drawable as BitmapDrawable 25 | val bitmap = drawable.bitmap 26 | val moduleFileAbsoluteFilePath = File( 27 | assetFilePath(app, moduleAssetName) 28 | ).absolutePath 29 | imageAnalysis.analyzeImage(bitmap, moduleFileAbsoluteFilePath) 30 | } 31 | } 32 | 33 | val result = imageAnalysis.result 34 | } 35 | 36 | /** 37 | * Factory for [LiveDataViewModel]. 38 | */ 39 | class LiveDataVMFactory(private val application: Application) : 40 | ViewModelProvider.AndroidViewModelFactory(application) { 41 | 42 | private val imageClassificationOperation = ImageClassificationOperation(Dispatchers.IO) 43 | 44 | override fun create(modelClass: Class): T { 45 | @Suppress("UNCHECKED_CAST") 46 | return LiveDataViewModel( 47 | application, imageClassificationOperation 48 | ) as T 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import android.Manifest 4 | import android.content.Intent 5 | import android.graphics.Bitmap 6 | import android.graphics.ImageDecoder 7 | import android.os.Build 8 | import android.os.Bundle 9 | import android.provider.MediaStore 10 | import android.widget.Toast 11 | import androidx.activity.viewModels 12 | import androidx.appcompat.app.AppCompatActivity 13 | import androidx.databinding.DataBindingUtil 14 | import com.karumi.dexter.Dexter 15 | import com.karumi.dexter.MultiplePermissionsReport 16 | import com.karumi.dexter.PermissionToken 17 | import com.karumi.dexter.listener.PermissionRequest 18 | import com.karumi.dexter.listener.multi.MultiplePermissionsListener 19 | import com.say.pytorchkotlindemo.databinding.ActivityMainBinding 20 | import kotlinx.android.synthetic.main.activity_main.* 21 | import java.io.IOException 22 | 23 | const val GALLERY = 1 24 | const val CAMERA = 2 25 | 26 | class MainActivity : AppCompatActivity() { 27 | 28 | private val viewModel: LiveDataViewModel by viewModels { LiveDataVMFactory(application) } 29 | 30 | override fun onCreate(savedInstanceState: Bundle?) { 31 | super.onCreate(savedInstanceState) 32 | 33 | requestMultiplePermissions() 34 | 35 | // Obtain binding object using the Data Binding library 36 | val binding = DataBindingUtil.setContentView( 37 | this, R.layout.activity_main 38 | ) 39 | 40 | // Set the LifecycleOwner to be able to observe LiveData objects 41 | binding.lifecycleOwner = this 42 | 43 | // Bind ViewModel 44 | binding.viewModel = viewModel 45 | binding.listeners = Listeners(this) 46 | } 47 | 48 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 49 | super.onActivityResult(requestCode, resultCode, data) 50 | if (resultCode == RESULT_CANCELED) { 51 | return 52 | } 53 | if (requestCode == GALLERY) { 54 | if (data != null) { 55 | val contentURI = data.data 56 | try { 57 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { 58 | val bitmap = 59 | MediaStore.Images.Media.getBitmap(this.contentResolver, contentURI) 60 | Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT).show() 61 | iv.setImageBitmap(bitmap) 62 | } else { 63 | contentURI?.let { 64 | val source = ImageDecoder.createSource(this.contentResolver, it) 65 | val bitmap = ImageDecoder.decodeBitmap(source) 66 | Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT) 67 | .show() 68 | iv.setImageBitmap(bitmap) 69 | } 70 | } 71 | } catch (e: IOException) { 72 | e.printStackTrace() 73 | Toast.makeText(this@MainActivity, "Failed!", Toast.LENGTH_SHORT).show() 74 | } 75 | 76 | } 77 | 78 | } else if (requestCode == CAMERA) { 79 | val thumbnail = data?.extras?.get("data") as Bitmap 80 | iv.setImageBitmap(thumbnail) 81 | Toast.makeText(this@MainActivity, "Image Saved!", Toast.LENGTH_SHORT).show() 82 | } 83 | } 84 | 85 | private fun requestMultiplePermissions() { 86 | Dexter.withActivity(this) 87 | .withPermissions( 88 | Manifest.permission.CAMERA, 89 | Manifest.permission.READ_EXTERNAL_STORAGE 90 | ) 91 | .withListener(object : MultiplePermissionsListener { 92 | override fun onPermissionsChecked(report: MultiplePermissionsReport?) { 93 | // check if all permissions are granted 94 | if (report?.areAllPermissionsGranted()!!) { 95 | Toast.makeText( 96 | applicationContext, 97 | "All permissions are granted by user!", 98 | Toast.LENGTH_SHORT 99 | ).show() 100 | } 101 | 102 | // check for permanent denial of any permission 103 | if (report.isAnyPermissionPermanentlyDenied) { 104 | // show alert dialog navigating to Settings 105 | //openSettingsDialog() 106 | Toast.makeText( 107 | applicationContext, 108 | "openSettingsDialog! ", 109 | Toast.LENGTH_SHORT 110 | ) 111 | .show() 112 | } 113 | } 114 | 115 | override fun onPermissionRationaleShouldBeShown( 116 | permissions: MutableList?, 117 | token: PermissionToken? 118 | ) { 119 | token?.continuePermissionRequest() 120 | } 121 | }) 122 | .withErrorListener { 123 | Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT) 124 | .show() 125 | } 126 | .onSameThread() 127 | .check() 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/say/pytorchkotlindemo/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import java.io.File 6 | import java.io.FileOutputStream 7 | import java.io.IOException 8 | import java.util.* 9 | 10 | object Utils { 11 | fun assetFilePath(context: Context, assetName: String): String? { 12 | val file = File(context.filesDir, assetName) 13 | 14 | try { 15 | context.assets.open(assetName).use { `is` -> 16 | FileOutputStream(file).use { os -> 17 | val buffer = ByteArray(4 * 1024) 18 | while (true) { 19 | val length = `is`.read(buffer) 20 | if (length <= 0) 21 | break 22 | os.write(buffer, 0, length) 23 | } 24 | os.flush() 25 | os.close() 26 | } 27 | return file.absolutePath 28 | } 29 | } catch (e: IOException) { 30 | Log.e("pytorchandroid", "Error process asset $assetName to file path") 31 | } 32 | 33 | return null 34 | } 35 | 36 | fun topK(a: FloatArray, topk: Int): IntArray { 37 | val values = FloatArray(topk) 38 | Arrays.fill(values, -java.lang.Float.MAX_VALUE) 39 | val ixs = IntArray(topk) 40 | Arrays.fill(ixs, -1) 41 | 42 | for (i in a.indices) { 43 | for (j in 0 until topk) { 44 | if (a[i] > values[j]) { 45 | for (k in topk - 1 downTo j + 1) { 46 | values[k] = values[k - 1] 47 | ixs[k] = ixs[k - 1] 48 | } 49 | values[j] = a[i] 50 | ixs[j] = i 51 | break 52 | } 53 | } 54 | } 55 | return ixs 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /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/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/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 20 | 21 | 32 | 33 | 44 | 45 | 57 | 58 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /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/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PytorchKotlinDemo 3 | Select or Capture Image 4 | Tell me 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/say/pytorchkotlindemo/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.say.pytorchkotlindemo 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.72' 5 | repositories { 6 | google() 7 | jcenter() 8 | 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:4.0.0' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 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 | 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 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vsay01/PytorchKotlinDemo/7d348823352f7d22a91c7960e9401d98b6e04c95/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Feb 01 03:55:51 CST 2020 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-6.1.1-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 | rootProject.name='PytorchKotlinDemo' 3 | --------------------------------------------------------------------------------