diff --git a/mace/examples/android/.gitignore b/mace/examples/android/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..39fb081a42a86ccf8f9cf99dbccc8bdf7c828bce --- /dev/null +++ b/mace/examples/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/mace/examples/android/README_zh.md b/mace/examples/android/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..eedbc7aa3108604cae69c3074c7293ad7ec16380 --- /dev/null +++ b/mace/examples/android/README_zh.md @@ -0,0 +1,15 @@ +# mace demo使用方法 + +* 使用前需要生成静态库和头文件,具体参考[文档](docs) + * 把mace/public目录下的mace.h和mace_runtime.h拷贝到macelibrary/src/main/cpp/include下面 + * 把生成的mace/codegen/engine/mace_engine_factory.h拷贝到macelibrary/src/main/cpp/include下面 + * 静态库的路径是在mace/build/demo_app_models/lib/下 +* 使用android studio 导入项目,然后运行install run +* 还可以使用gradle命令(需要安装gradle)生成apk 具体命令例如:./gradlew assemble(或者Release|Debug) + +## 交流与反馈 +* 欢迎通过Github Issues提交问题报告与建议 +* QQ群: 756046893 + +## License +[Apache License 2.0](LICENSE). diff --git a/mace/examples/android/app/.gitignore b/mace/examples/android/app/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9 --- /dev/null +++ b/mace/examples/android/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mace/examples/android/app/build.gradle b/mace/examples/android/app/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..b9101ae015408ba68c81700254a728c98f1f5ced --- /dev/null +++ b/mace/examples/android/app/build.gradle @@ -0,0 +1,76 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 26 + defaultConfig { + applicationId "com.xiaomi.mace.demo" + minSdkVersion 23 + targetSdkVersion 26 + versionCode 1 + versionName "1.0" + } + + signingConfigs { + release { + storeFile file("mace_demo.jks") + keyAlias "keyAlias" + keyPassword "maceAndroid" + storePassword "maceAndroid" + } + debug { + storeFile file("mace_demo.jks") + keyAlias "keyAlias" + keyPassword "maceAndroid" + storePassword "maceAndroid" + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + } + + flavorDimensions "mace" + productFlavors { + app { + dimension "mace" + } + } + + sourceSets { + main { + jniLibs.srcDirs = ["libs"] + jni.srcDirs = ['src/main/jni', 'src/main/jni/'] + } + } + + applicationVariants.all { variant -> + if (variant.buildType.name != "release") { + return + } + def outputFolder = file("build/output/apk") + + variant.outputs.all {output -> + def name = output.outputFile.name + def newName = "Mace_" + new Date().format("yyyyMMdd_HHmm") + "_" + defaultConfig.versionName + "_" + variant.flavorName + ".apk" + copy { + from output.outputFile.parent + into outputFolder + include name + rename(name, newName) + } + } + } + +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'com.android.support:appcompat-v7:26.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.0' + implementation project(':macelibrary') + implementation 'org.greenrobot:eventbus:3.1.1' +} diff --git a/mace/examples/android/app/mace_demo.jks b/mace/examples/android/app/mace_demo.jks new file mode 100644 index 0000000000000000000000000000000000000000..a661209e040fad686ff74b38790db38de588eaf5 Binary files /dev/null and b/mace/examples/android/app/mace_demo.jks differ diff --git a/mace/examples/android/app/src/main/AndroidManifest.xml b/mace/examples/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..e289b8122a26fc6e3b5bada3530d62ca653af647 --- /dev/null +++ b/mace/examples/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mace/examples/android/app/src/main/assets/BUILD b/mace/examples/android/app/src/main/assets/BUILD new file mode 100644 index 0000000000000000000000000000000000000000..c827de7be1807679c423ff5e9251ed1f9b9cce9d --- /dev/null +++ b/mace/examples/android/app/src/main/assets/BUILD @@ -0,0 +1,15 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # Apache 2.0 + +# It is necessary to use this filegroup rather than globbing the files in this +# folder directly the examples/android:tensorflow_demo target due to the fact +# that assets_dir is necessarily set to "" there (to allow using other +# arbitrary targets as assets). +filegroup( + name = "asset_files", + srcs = glob( + ["**/*"], + exclude = ["BUILD"], + ), +) diff --git a/mace/examples/android/app/src/main/assets/cacheLabel.txt b/mace/examples/android/app/src/main/assets/cacheLabel.txt new file mode 100644 index 0000000000000000000000000000000000000000..b52daf9a9db2a494e3e48e408f01b18e490bec24 --- /dev/null +++ b/mace/examples/android/app/src/main/assets/cacheLabel.txt @@ -0,0 +1,1001 @@ +background +tench +goldfish +great white shark +tiger shark +hammerhead +electric ray +stingray +cock +hen +ostrich +brambling +goldfinch +house finch +junco +indigo bunting +robin +bulbul +jay +magpie +chickadee +water ouzel +kite +bald eagle +vulture +great grey owl +European fire salamander +common newt +eft +spotted salamander +axolotl +bullfrog +tree frog +tailed frog +loggerhead +leatherback turtle +mud turtle +terrapin +box turtle +banded gecko +common iguana +American chameleon +whiptail +agama +frilled lizard +alligator lizard +Gila monster +green lizard +African chameleon +Komodo dragon +African crocodile +American alligator +triceratops +thunder snake +ringneck snake +hognose snake +green snake +king snake +garter snake +water snake +vine snake +night snake +boa constrictor +rock python +Indian cobra +green mamba +sea snake +horned viper +diamondback +sidewinder +trilobite +harvestman +scorpion +black and gold garden spider +barn spider +garden spider +black widow +tarantula +wolf spider +tick +centipede +black grouse +ptarmigan +ruffed grouse +prairie chicken +peacock +quail +partridge +African grey +macaw +sulphur-crested cockatoo +lorikeet +coucal +bee eater +hornbill +hummingbird +jacamar +toucan +drake +red-breasted merganser +goose +black swan +tusker +echidna +platypus +wallaby +koala +wombat +jellyfish +sea anemone +brain coral +flatworm +nematode +conch +snail +slug +sea slug +chiton +chambered nautilus +Dungeness crab +rock crab +fiddler crab +king crab +American lobster +spiny lobster +crayfish +hermit crab +isopod +white stork +black stork +spoonbill +flamingo +little blue heron +American egret +bittern +crane +limpkin +European gallinule +American coot +bustard +ruddy turnstone +red-backed sandpiper +redshank +dowitcher +oystercatcher +pelican +king penguin +albatross +grey whale +killer whale +dugong +sea lion +Chihuahua +Japanese spaniel +Maltese dog +Pekinese +Shih-Tzu +Blenheim spaniel +papillon +toy terrier +Rhodesian ridgeback +Afghan hound +basset +beagle +bloodhound +bluetick +black-and-tan coonhound +Walker hound +English foxhound +redbone +borzoi +Irish wolfhound +Italian greyhound +whippet +Ibizan hound +Norwegian elkhound +otterhound +Saluki +Scottish deerhound +Weimaraner +Staffordshire bullterrier +American Staffordshire terrier +Bedlington terrier +Border terrier +Kerry blue terrier +Irish terrier +Norfolk terrier +Norwich terrier +Yorkshire terrier +wire-haired fox terrier +Lakeland terrier +Sealyham terrier +Airedale +cairn +Australian terrier +Dandie Dinmont +Boston bull +miniature schnauzer +giant schnauzer +standard schnauzer +Scotch terrier +Tibetan terrier +silky terrier +soft-coated wheaten terrier +West Highland white terrier +Lhasa +flat-coated retriever +curly-coated retriever +golden retriever +Labrador retriever +Chesapeake Bay retriever +German short-haired pointer +vizsla +English setter +Irish setter +Gordon setter +Brittany spaniel +clumber +English springer +Welsh springer spaniel +cocker spaniel +Sussex spaniel +Irish water spaniel +kuvasz +schipperke +groenendael +malinois +briard +kelpie +komondor +Old English sheepdog +Shetland sheepdog +collie +Border collie +Bouvier des Flandres +Rottweiler +German shepherd +Doberman +miniature pinscher +Greater Swiss Mountain dog +Bernese mountain dog +Appenzeller +EntleBucher +boxer +bull mastiff +Tibetan mastiff +French bulldog +Great Dane +Saint Bernard +Eskimo dog +malamute +Siberian husky +dalmatian +affenpinscher +basenji +pug +Leonberg +Newfoundland +Great Pyrenees +Samoyed +Pomeranian +chow +keeshond +Brabancon griffon +Pembroke +Cardigan +toy poodle +miniature poodle +standard poodle +Mexican hairless +timber wolf +white wolf +red wolf +coyote +dingo +dhole +African hunting dog +hyena +red fox +kit fox +Arctic fox +grey fox +tabby +tiger cat +Persian cat +Siamese cat +Egyptian cat +cougar +lynx +leopard +snow leopard +jaguar +lion +tiger +cheetah +brown bear +American black bear +ice bear +sloth bear +mongoose +meerkat +tiger beetle +ladybug +ground beetle +long-horned beetle +leaf beetle +dung beetle +rhinoceros beetle +weevil +fly +bee +ant +grasshopper +cricket +walking stick +cockroach +mantis +cicada +leafhopper +lacewing +dragonfly +damselfly +admiral +ringlet +monarch +cabbage butterfly +sulphur butterfly +lycaenid +starfish +sea urchin +sea cucumber +wood rabbit +hare +Angora +hamster +porcupine +fox squirrel +marmot +beaver +guinea pig +sorrel +zebra +hog +wild boar +warthog +hippopotamus +ox +water buffalo +bison +ram +bighorn +ibex +hartebeest +impala +gazelle +Arabian camel +llama +weasel +mink +polecat +black-footed ferret +otter +skunk +badger +armadillo +three-toed sloth +orangutan +gorilla +chimpanzee +gibbon +siamang +guenon +patas +baboon +macaque +langur +colobus +proboscis monkey +marmoset +capuchin +howler monkey +titi +spider monkey +squirrel monkey +Madagascar cat +indri +Indian elephant +African elephant +lesser panda +giant panda +barracouta +eel +coho +rock beauty +anemone fish +sturgeon +gar +lionfish +puffer +abacus +abaya +academic gown +accordion +acoustic guitar +aircraft carrier +airliner +airship +altar +ambulance +amphibian +analog clock +apiary +apron +ashcan +assault rifle +backpack +bakery +balance beam +balloon +ballpoint +Band Aid +banjo +bannister +barbell +barber chair +barbershop +barn +barometer +barrel +barrow +baseball +basketball +bassinet +bassoon +bathing cap +bath towel +bathtub +beach wagon +beacon +beaker +bearskin +beer bottle +beer glass +bell cote +bib +bicycle-built-for-two +bikini +binder +binoculars +birdhouse +boathouse +bobsled +bolo tie +bonnet +bookcase +bookshop +bottlecap +bow +bow tie +brass +brassiere +breakwater +breastplate +broom +bucket +buckle +bulletproof vest +bullet train +butcher shop +cab +caldron +candle +cannon +canoe +can opener +cardigan +car mirror +carousel +carpenter's kit +carton +car wheel +cash machine +cassette +cassette player +castle +catamaran +CD player +cello +cellular telephone +chain +chainlink fence +chain mail +chain saw +chest +chiffonier +chime +china cabinet +Christmas stocking +church +cinema +cleaver +cliff dwelling +cloak +clog +cocktail shaker +coffee mug +coffeepot +coil +combination lock +computer keyboard +confectionery +container ship +convertible +corkscrew +cornet +cowboy boot +cowboy hat +cradle +crane +crash helmet +crate +crib +Crock Pot +croquet ball +crutch +cuirass +dam +desk +desktop computer +dial telephone +diaper +digital clock +digital watch +dining table +dishrag +dishwasher +disk brake +dock +dogsled +dome +doormat +drilling platform +drum +drumstick +dumbbell +Dutch oven +electric fan +electric guitar +electric locomotive +entertainment center +envelope +espresso maker +face powder +feather boa +file +fireboat +fire engine +fire screen +flagpole +flute +folding chair +football helmet +forklift +fountain +fountain pen +four-poster +freight car +French horn +frying pan +fur coat +garbage truck +gasmask +gas pump +goblet +go-kart +golf ball +golfcart +gondola +gong +gown +grand piano +greenhouse +grille +grocery store +guillotine +hair slide +hair spray +half track +hammer +hamper +hand blower +hand-held computer +handkerchief +hard disc +harmonica +harp +harvester +hatchet +holster +home theater +honeycomb +hook +hoopskirt +horizontal bar +horse cart +hourglass +iPod +iron +jack-o'-lantern +jean +jeep +jersey +jigsaw puzzle +jinrikisha +joystick +kimono +knee pad +knot +lab coat +ladle +lampshade +laptop +lawn mower +lens cap +letter opener +library +lifeboat +lighter +limousine +liner +lipstick +Loafer +lotion +loudspeaker +loupe +lumbermill +magnetic compass +mailbag +mailbox +maillot +maillot +manhole cover +maraca +marimba +mask +matchstick +maypole +maze +measuring cup +medicine chest +megalith +microphone +microwave +military uniform +milk can +minibus +miniskirt +minivan +missile +mitten +mixing bowl +mobile home +Model T +modem +monastery +monitor +moped +mortar +mortarboard +mosque +mosquito net +motor scooter +mountain bike +mountain tent +mouse +mousetrap +moving van +muzzle +nail +neck brace +necklace +nipple +notebook +obelisk +oboe +ocarina +odometer +oil filter +organ +oscilloscope +overskirt +oxcart +oxygen mask +packet +paddle +paddlewheel +padlock +paintbrush +pajama +palace +panpipe +paper towel +parachute +parallel bars +park bench +parking meter +passenger car +patio +pay-phone +pedestal +pencil box +pencil sharpener +perfume +Petri dish +photocopier +pick +pickelhaube +picket fence +pickup +pier +piggy bank +pill bottle +pillow +ping-pong ball +pinwheel +pirate +pitcher +plane +planetarium +plastic bag +plate rack +plow +plunger +Polaroid camera +pole +police van +poncho +pool table +pop bottle +pot +potter's wheel +power drill +prayer rug +printer +prison +projectile +projector +puck +punching bag +purse +quill +quilt +racer +racket +radiator +radio +radio telescope +rain barrel +recreational vehicle +reel +reflex camera +refrigerator +remote control +restaurant +revolver +rifle +rocking chair +rotisserie +rubber eraser +rugby ball +rule +running shoe +safe +safety pin +saltshaker +sandal +sarong +sax +scabbard +scale +school bus +schooner +scoreboard +screen +screw +screwdriver +seat belt +sewing machine +shield +shoe shop +shoji +shopping basket +shopping cart +shovel +shower cap +shower curtain +ski +ski mask +sleeping bag +slide rule +sliding door +slot +snorkel +snowmobile +snowplow +soap dispenser +soccer ball +sock +solar dish +sombrero +soup bowl +space bar +space heater +space shuttle +spatula +speedboat +spider web +spindle +sports car +spotlight +stage +steam locomotive +steel arch bridge +steel drum +stethoscope +stole +stone wall +stopwatch +stove +strainer +streetcar +stretcher +studio couch +stupa +submarine +suit +sundial +sunglass +sunglasses +sunscreen +suspension bridge +swab +sweatshirt +swimming trunks +swing +switch +syringe +table lamp +tank +tape player +teapot +teddy +television +tennis ball +thatch +theater curtain +thimble +thresher +throne +tile roof +toaster +tobacco shop +toilet seat +torch +totem pole +tow truck +toyshop +tractor +trailer truck +tray +trench coat +tricycle +trimaran +tripod +triumphal arch +trolleybus +trombone +tub +turnstile +typewriter keyboard +umbrella +unicycle +upright +vacuum +vase +vault +velvet +vending machine +vestment +viaduct +violin +volleyball +waffle iron +wall clock +wallet +wardrobe +warplane +washbasin +washer +water bottle +water jug +water tower +whiskey jug +whistle +wig +window screen +window shade +Windsor tie +wine bottle +wing +wok +wooden spoon +wool +worm fence +wreck +yawl +yurt +web site +comic book +crossword puzzle +street sign +traffic light +book jacket +menu +plate +guacamole +consomme +hot pot +trifle +ice cream +ice lolly +French loaf +bagel +pretzel +cheeseburger +hotdog +mashed potato +head cabbage +broccoli +cauliflower +zucchini +spaghetti squash +acorn squash +butternut squash +cucumber +artichoke +bell pepper +cardoon +mushroom +Granny Smith +strawberry +orange +lemon +fig +pineapple +banana +jackfruit +custard apple +pomegranate +hay +carbonara +chocolate sauce +dough +meat loaf +pizza +potpie +burrito +red wine +espresso +cup +eggnog +alp +bubble +cliff +coral reef +geyser +lakeside +promontory +sandbar +seashore +valley +volcano +ballplayer +groom +scuba diver +rapeseed +daisy +yellow lady's slipper +corn +acorn +hip +buckeye +coral fungus +agaric +gyromitra +stinkhorn +earthstar +hen-of-the-woods +bolete +ear +toilet tissue \ No newline at end of file diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/AppModel.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/AppModel.java new file mode 100644 index 0000000000000000000000000000000000000000..c43f6266eeffcb66b4d5725023282c481f2cbf82 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/AppModel.java @@ -0,0 +1,75 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo; + +import android.os.Handler; +import android.os.HandlerThread; +import android.util.Log; + +import com.xiaomi.mace.JniMaceUtils; +import com.xiaomi.mace.demo.camera.MessageEvent; +import com.xiaomi.mace.demo.result.InitData; +import com.xiaomi.mace.demo.result.LabelCache; +import com.xiaomi.mace.demo.result.ResultData; + +import org.greenrobot.eventbus.EventBus; + +public class AppModel { + + private Handler mJniThread; + public static AppModel instance = new AppModel(); + private AppModel() { + HandlerThread thread = new HandlerThread("jniThread"); + thread.start(); + mJniThread = new Handler(thread.getLooper()); + } + + public void maceMobilenetSetAttrs(final InitData initData) { + mJniThread.post(new Runnable() { + @Override + public void run() { + int result = JniMaceUtils.maceMobilenetSetAttrs( + initData.getOmpNumThreads(), initData.getCpuAffinityPolicy(), + initData.getGpuPerfHint(), initData.getGpuPriorityHint(), + initData.getKernelPath()); + Log.i("APPModel", "maceMobilenetSetAttrs result = " + result); + } + }); + } + + public void maceMobilenetCreateEngine(final InitData initData) { + mJniThread.post(new Runnable() { + @Override + public void run() { + JniMaceUtils.maceMobilenetCreateEngine(initData.getModel(), initData.getDevice()); + } + }); + } + + public void maceMobilenetClassify(final float[] input) { + mJniThread.post(new Runnable() { + @Override + public void run() { + long start = System.currentTimeMillis(); + float[] result = JniMaceUtils.maceMobilenetClassify(input); + + final ResultData resultData = LabelCache.instance().getResultFirst(result); + resultData.costTime = System.currentTimeMillis() - start; + EventBus.getDefault().post(new MessageEvent.MaceResultEvent(resultData)); + } + }); + } + +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraActivity.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..ae38719062cbe10facd9f6f5a98ad8a1461d08a7 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraActivity.java @@ -0,0 +1,180 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo; + +import android.app.Activity; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + + +import com.xiaomi.mace.demo.camera.CameraEngage; +import com.xiaomi.mace.demo.camera.CameraTextureView; +import com.xiaomi.mace.demo.camera.ContextMenuDialog; + +import com.xiaomi.mace.demo.camera.MessageEvent; +import com.xiaomi.mace.demo.result.InitData; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.Arrays; +import java.util.List; + +public class CameraActivity extends Activity implements View.OnClickListener { + + CameraEngage mCameraEngage; + ImageView mPictureResult; + Button mSelectMode; + Button mSelectPhoneType; + CameraTextureView mCameraTextureView; + private TextView mResultView; + private InitData initData = new InitData(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + setContentView(R.layout.activity_camera); + mPictureResult = findViewById(R.id.iv_picture); + mResultView = findViewById(R.id.tv_show_result); + mCameraTextureView = findViewById(R.id.camera_texture); + mCameraEngage = CameraFactory.genCameEngage(mCameraTextureView); + + mSelectMode = findViewById(R.id.tv_select_mode); + mSelectMode.setOnClickListener(this); + + mSelectPhoneType = findViewById(R.id.tv_select_phone_type); + mSelectPhoneType.setOnClickListener(this); + initJni(); + initView(); + + } + + @Override + protected void onStart() { + super.onStart(); + EventBus.getDefault().register(this); + } + + @Override + protected void onStop() { + super.onStop(); + EventBus.getDefault().unregister(this); + } + + private void initView() { + mSelectMode.setText(initData.getModel()); + mSelectPhoneType.setText(initData.getDevice()); + } + + @Override + protected void onResume() { + super.onResume(); + mCameraEngage.onResume(); + } + + + @Override + protected void onPause() { + super.onPause(); + mCameraEngage.onPause(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPicture(MessageEvent.PicEvent picEvent) { + if (picEvent != null && picEvent.getBitmap() != null) { + mPictureResult.setImageBitmap(picEvent.getBitmap()); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onSetCameraViewSize(MessageEvent.OutputSizeEvent event) { + if (mCameraTextureView != null) { + mCameraTextureView.setRatio(event.width, event.height); + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onResultData(MessageEvent.MaceResultEvent resultData) { + if (resultData != null && resultData.getData() != null) { + String result = resultData.getData().name + "\n" + + resultData.getData().probability + "\ncost time(ms): " + + resultData.getData().costTime; + mResultView.setText(result); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_select_mode: + showSelectMode(); + break; + case R.id.tv_select_phone_type: + showPhoneType(); + break; + } + } + + private void initJni() { + AppModel.instance.maceMobilenetSetAttrs(initData); + AppModel.instance.maceMobilenetCreateEngine(initData); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == Constant.CAMERA_PERMISSION_REQ) { + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + mCameraEngage.onResume(); + break; + } + } + } + } + + private void showPhoneType() { + List menus = Arrays.asList(InitData.DEVICES); + ContextMenuDialog.show(this, menus, new ContextMenuDialog.OnClickItemListener() { + @Override + public void onCLickItem(String content) { + mSelectPhoneType.setText(content); + initData.setDevice(content); + AppModel.instance.maceMobilenetCreateEngine(initData); + } + }); + } + + private void showSelectMode() { + List menus = Arrays.asList(InitData.MODELS); + ContextMenuDialog.show(this, menus, new ContextMenuDialog.OnClickItemListener() { + @Override + public void onCLickItem(String content) { + mSelectMode.setText(content); + initData.setModel(content); + AppModel.instance.maceMobilenetCreateEngine(initData); + } + }); + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraFactory.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..a3fd21e3e27ecefdee11508532cebe055f094bd1 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraFactory.java @@ -0,0 +1,35 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo; + +import android.os.Build; + +import com.xiaomi.mace.demo.camera.CameraApiLessM; +import com.xiaomi.mace.demo.camera.CameraEngage; +import com.xiaomi.mace.demo.camera.CameraTextureView; + +public class CameraFactory { + + public static CameraEngage genCameEngage(CameraTextureView textureView) { + CameraEngage cameraEngage; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// cameraEngage = new CameraApiMoreM(textureView); + cameraEngage = new CameraApiLessM(textureView); + } else { + cameraEngage = new CameraApiLessM(textureView); + } + return cameraEngage; + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/Constant.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/Constant.java new file mode 100644 index 0000000000000000000000000000000000000000..a1f673a6e63366f183efaff81ec8dba52982ca7e --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/Constant.java @@ -0,0 +1,20 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo; + +public class Constant { + + public static final int CAMERA_PERMISSION_REQ = 1; +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/MaceApp.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/MaceApp.java new file mode 100644 index 0000000000000000000000000000000000000000..f525f63496fe5fac3608d77aa723f55cb0b1abb9 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/MaceApp.java @@ -0,0 +1,51 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo; + +import android.app.Application; +import android.os.Handler; +import android.os.HandlerThread; + +import com.xiaomi.mace.demo.result.LabelCache; + +public class MaceApp extends Application { + + public static MaceApp app; + public Handler mBackground; + public Handler mMainHandler; + + @Override + public void onCreate() { + super.onCreate(); + app = this; + + mMainHandler = new Handler(getMainLooper()); + + HandlerThread thread = new HandlerThread("mace_app"); + thread.start(); + mBackground = new Handler(thread.getLooper()); + mBackground.post(new Runnable() { + @Override + public void run() { + LabelCache.instance(); + } + }); + } + + public Handler mainHandler() { + return mMainHandler; + } + +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiLessM.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiLessM.java new file mode 100644 index 0000000000000000000000000000000000000000..9b334c5ad0ada3ab48e77d9deb492acdfc360d1b --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiLessM.java @@ -0,0 +1,149 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.text.TextUtils; +import android.util.Log; + +import java.util.List; + +public class CameraApiLessM extends CameraEngage implements Camera.AutoFocusCallback { + + private Camera mCamera; + + public CameraApiLessM(CameraTextureView textureView) { + super(textureView); + } + + @Override + public void openCamera(int width, int height) { + if (!checkCameraPermission()) { + return; + } + super.openCamera(width, height); + closeCamera(); + String cameraId = getCameraId(); + if (TextUtils.isEmpty(cameraId)) { + return; + } + + mCamera = Camera.open(Integer.parseInt(cameraId)); + setOutputConfig(width, height); + startPreview(); + } + + @Override + public void autoFocus() { + doAutoFocus(); + } + + @Override + public void closeCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } + + @Override + public String getCameraId() { + Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); + int cameraFacing = facingFrontPreview() ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK; + for (int i = 0; i < Camera.getNumberOfCameras(); i++) { + Camera.getCameraInfo(i, cameraInfo); + if (cameraInfo.facing == cameraFacing) { + return String.valueOf(i); + } + } + return ""; + } + + @Override + public void startPreview() { + try { + doAutoFocus(); + mCamera.setPreviewTexture(mSurfaceTexture); + mCamera.startPreview(); + mCamera.setDisplayOrientation(90); + } catch (Exception e) { + Log.e(getClass().getName(), "startPreview error = " + e); + } + } + + @Override + public void onAutoFocus(boolean success, Camera camera) { + if (success) { + mCamera.cancelAutoFocus(); + } + } + + private void doAutoFocus() { + try { + mCamera.autoFocus(this); + } catch (Throwable e) { + Log.e(this.getClass().getName(), "auto focus error = " + e); + } + } + + private void setOutputConfig(int width, int height) { + Camera.Parameters parameters = mCamera.getParameters(); + parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); + parameters.setPreviewFormat(ImageFormat.JPEG); + parameters.setPictureFormat(ImageFormat.JPEG); + Camera.Size size = getOptimalSize(parameters.getSupportedPreviewSizes(), width, height); + mPreviewWidth = size.width; + mPreviewHeight = size.height; + parameters.setPreviewSize(size.width, size.height); + parameters.setPictureSize(size.width, size.height); + mCamera.setParameters(parameters); + mTextureView.setRatio(size.height, size.width); + } + + private Camera.Size getOptimalSize(List sizes, int w, int h) { + final double ASPECT_TOLERANCE = 0.1; + double targetRatio = (double) h / w; + Camera.Size optimalSize = null; + double minDiff = Double.MAX_VALUE; + + int targetHeight = h; + + for (Camera.Size size : sizes) { + double ratio = (double) size.height / size.width; + if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) { + continue; + } + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + + if (optimalSize == null) { + minDiff = Double.MAX_VALUE; + for (Camera.Size size : sizes) { + if (Math.abs(size.height - targetHeight) < minDiff) { + optimalSize = size; + minDiff = Math.abs(size.height - targetHeight); + } + } + } + + return optimalSize; + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiMoreM.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiMoreM.java new file mode 100644 index 0000000000000000000000000000000000000000..8be09dd3f720560d1e44960dcdd2db149e4c1dd9 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiMoreM.java @@ -0,0 +1,270 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.content.Context; +import android.graphics.ImageFormat; +import android.graphics.SurfaceTexture; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCaptureSession.CaptureCallback; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.media.ImageReader; +import android.os.Handler; +import android.os.HandlerThread; +import android.support.annotation.NonNull; +import android.util.Log; +import android.util.Size; +import android.view.Surface; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class CameraApiMoreM extends CameraEngage { + + private CameraManager mCameraManager; + private ImageReader mImageReader; + private CameraCaptureSession mCameraCaptureSession; + private CaptureRequest.Builder mPreviewBuilder; + private Handler mCameraHandler; + private CameraDevice mCameraDevice; + private Size mPreviewSize; + + + private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { + @Override + public void onOpened(@NonNull CameraDevice camera) { + mCameraDevice = camera; + createPreviewSession(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice camera) { + camera.close(); + mCameraDevice = null; + } + + @Override + public void onError(@NonNull CameraDevice camera, int error) { + camera.close(); + mCameraDevice = null; + } + }; + + private CameraCaptureSession.CaptureCallback mCaptureCallback = new CaptureCallback() { + @Override + public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { + super.onCaptureProgressed(session, request, partialResult); + } + + @Override + public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { + super.onCaptureCompleted(session, request, result); + } + + @Override + public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { + super.onCaptureFailed(session, request, failure); + } + }; + + private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(@NonNull CameraCaptureSession session) { + if (mCameraDevice == null) { + Log.e("bjh", "device must be not null"); + return; + } + mCameraCaptureSession = session; + startPreview(); + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession session) { + + } + }; + + private void createPreviewSession() { + try { + mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); + + Surface surface = new Surface(mSurfaceTexture); + + mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + mPreviewBuilder.addTarget(surface); + + mCameraDevice.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, null); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public CameraApiMoreM(CameraTextureView textureView) { + super(textureView); + mCameraManager = (CameraManager) textureView.getContext().getSystemService(Context.CAMERA_SERVICE); + if (mCameraManager == null) { + throw new RuntimeException("camera manager must be not null"); + } + + HandlerThread handlerThread = new HandlerThread("camerabg"); + handlerThread.start(); + mCameraHandler = new Handler(handlerThread.getLooper()); + } + + @Override + public void openCamera(int width, int height) { + super.openCamera(width, height); + try { + if (!checkCameraPermission()) { + return; + } + setOutputConfig(width, height); + createImageReader(); + mCameraManager.openCamera(getCameraId(), mStateCallback, mCameraHandler); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void setOutputConfig(int width, int height) { + try { + for (String cameraId : mCameraManager.getCameraIdList()) { + CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); + + Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); + if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) { + continue; + } + + StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + if (map == null) { + continue; + } + + Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea()); + + mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, mPreviewWidth, mPreviewHeight, largest); + mPreviewWidth = mPreviewSize.getWidth(); + mPreviewHeight = mPreviewSize.getHeight(); + mTextureView.setRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth()); + break; + } + } catch (Exception e) { + Log.e("bjh", "error " + e); + } + } + + private static Size chooseOptimalSize(Size[] choices, int textureViewWidth, int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) { + + // Collect the supported resolutions that are at least as big as the preview Surface + List bigEnough = new ArrayList<>(); + // Collect the supported resolutions that are smaller than the preview Surface + List notBigEnough = new ArrayList<>(); + int w = aspectRatio.getWidth(); + int h = aspectRatio.getHeight(); + for (Size option : choices) { + if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight && option.getHeight() == option.getWidth() * h / w) { + if (option.getWidth() >= textureViewWidth && option.getHeight() >= textureViewHeight) { + bigEnough.add(option); + } else { + notBigEnough.add(option); + } + } + } + + // Pick the smallest of those big enough. If there is no one big enough, pick the + // largest of those not big enough. + if (bigEnough.size() > 0) { + return Collections.min(bigEnough, new CompareSizesByArea()); + } else if (notBigEnough.size() > 0) { + return Collections.max(notBigEnough, new CompareSizesByArea()); + } else { + return choices[0]; + } + } + + @Override + public void autoFocus() { + startPreview(); + } + + private void createImageReader() { + mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, 2); + } + + @Override + public void closeCamera() { + if (mImageReader != null) { + mImageReader.close(); + } + if (mCameraDevice != null) { + mCameraDevice.close(); + } + if (mCameraCaptureSession != null) { + mCameraCaptureSession.close(); + } + } + private static class CompareSizesByArea implements Comparator { + + @Override + public int compare(Size lhs, Size rhs) { + return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight()); + } + } + + + @Override + public String getCameraId() { + try { + String[] idList = mCameraManager.getCameraIdList(); + int currentFacing = facingFrontPreview() ? CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK; + for (String id : idList) { + CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); + int facing = characteristics.get(CameraCharacteristics.LENS_FACING); + if (facing != currentFacing) { + continue; + } + return id; + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + @Override + public void startPreview() { + if (mCameraCaptureSession != null) { + try { + mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + mCameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), mCaptureCallback, mCameraHandler); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraEngage.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraEngage.java new file mode 100644 index 0000000000000000000000000000000000000000..af8b1b85c2110326fafa4153664ec8b43901fc6f --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraEngage.java @@ -0,0 +1,223 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.Manifest; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.SurfaceTexture; +import android.os.Handler; +import android.os.HandlerThread; +import android.support.v4.content.ContextCompat; +import android.util.Log; +import android.view.TextureView.SurfaceTextureListener; +import android.view.View; + +import com.xiaomi.mace.demo.AppModel; +import com.xiaomi.mace.demo.MaceApp; + +import java.nio.FloatBuffer; + +import static com.xiaomi.mace.demo.Constant.CAMERA_PERMISSION_REQ; + +public abstract class CameraEngage implements SurfaceTextureListener { + + /** + * preview height and width + */ + int mPreviewHeight; + int mPreviewWidth; + + /** + * show camera view + */ + CameraTextureView mTextureView; + SurfaceTexture mSurfaceTexture; + + /** + * switch camera use + */ + private boolean mFacingFront = false; + /** + * camera background thread + */ + private HandlerThread mBackgroundHandlerThread; + private Handler mBackgroundHandler; + + /** + * mace need data size width and height + */ + private static final int FINAL_SIZE = 224; + /** + * storage rgb value + */ + private int[] colorValues; + + /** + * mace float[] input + */ + private FloatBuffer floatBuffer; + + private final Object lock = new Object(); + + private boolean isCapturePic = false; + + private Runnable mHandleCapturePicRunnable = new Runnable() { + @Override + public void run() { + synchronized (lock) { + if (isCapturePic) { + handleCapturePic(); + } + } + mBackgroundHandler.postDelayed(mHandleCapturePicRunnable, 200); + } + }; + + private void handleCapturePic() { + if (mTextureView != null) { + Bitmap bitmap = mTextureView.getBitmap(FINAL_SIZE, FINAL_SIZE); + if (bitmap != null) { + bitmap.getPixels(colorValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); + handleColorRgbs(); +// EventBus.getDefault().post(new MessageEvent.PicEvent(bitmap)); + bitmap.recycle(); + } + } + } + + + public CameraEngage(CameraTextureView mTextureView) { + this.mTextureView = mTextureView; + + colorValues = new int[FINAL_SIZE * FINAL_SIZE]; + float[] floatValues = new float[FINAL_SIZE * FINAL_SIZE * 3]; + floatBuffer = FloatBuffer.wrap(floatValues, 0, FINAL_SIZE * FINAL_SIZE * 3); + + mPreviewHeight = MaceApp.app.getResources().getDisplayMetrics().heightPixels; + mPreviewWidth = MaceApp.app.getResources().getDisplayMetrics().widthPixels; + + mTextureView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + autoFocus(); + } + }); + } + + public void openCamera(int width, int height) { + startCapturePic(); + } + + public abstract void autoFocus(); + + public abstract void closeCamera(); + + public abstract String getCameraId(); + + public abstract void startPreview(); + + boolean facingFrontPreview() { + return mFacingFront; + } + + public void setFacingFront(boolean facingFront) { + this.mFacingFront = facingFront; + onResume(); + } + + + private void handleColorRgbs() { + floatBuffer.rewind(); + for (int i = 0; i < colorValues.length; i++) { + int value = colorValues[i]; + floatBuffer.put((((value >> 16) & 0xFF) - 128f)/ 128f); + floatBuffer.put((((value >> 8) & 0xFF) - 128f) / 128f); + floatBuffer.put(((value & 0xFF) - 128f) / 128f); + } + AppModel.instance.maceMobilenetClassify(floatBuffer.array()); + + } + + + public void onResume() { + if (mTextureView.isAvailable()) { + openCamera(mTextureView.getWidth(), mTextureView.getHeight()); + } else { + mTextureView.setSurfaceTextureListener(this); + } + } + + private void startCapturePic() { + mBackgroundHandlerThread = new HandlerThread("captureBackground"); + mBackgroundHandlerThread.start(); + mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper()); + synchronized (lock) { + isCapturePic = true; + } + + mBackgroundHandler.post(mHandleCapturePicRunnable); + } + + private void stopBackgroundThread() { + try { + mBackgroundHandlerThread.quitSafely(); + mBackgroundHandlerThread.join(); + mBackgroundHandler = null; + mBackgroundHandlerThread = null; + synchronized (lock) { + isCapturePic = false; + } + } catch (Exception e) { + Log.e(this.getClass().getName(), "stopBackgroundThread" + e); + } + } + + public void onPause() { + closeCamera(); + stopBackgroundThread(); + } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + mSurfaceTexture = surface; + openCamera(width, height); + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + return false; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + + } + + boolean checkCameraPermission() { + if (ContextCompat.checkSelfPermission(mTextureView.getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED || + ContextCompat.checkSelfPermission(mTextureView.getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + ((Activity) mTextureView.getContext()).requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSION_REQ); + return false; + } + return true; + } + +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraTextureView.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraTextureView.java new file mode 100644 index 0000000000000000000000000000000000000000..ac9d710249b87fba88abca17e42df82eb29be041 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraTextureView.java @@ -0,0 +1,55 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.TextureView; + +public class CameraTextureView extends TextureView { + + private int ratioWidth; + private int ratioHeight; + + public CameraTextureView(Context context) { + super(context); + } + + public CameraTextureView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CameraTextureView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setRatio(int width, int height) { + this.ratioWidth = width; + this.ratioHeight = height; + requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + if (ratioWidth <= 0 || ratioHeight <= 0) { + setMeasuredDimension(width, height); + } else { + setMeasuredDimension(width, width * ratioHeight / ratioWidth); + } + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ContextMenuDialog.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ContextMenuDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..6c9a14f55b2d4d85b827b82ce3a4b4f5ceca8a79 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ContextMenuDialog.java @@ -0,0 +1,69 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.app.Activity; +import android.app.DialogFragment; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; + +import com.xiaomi.mace.demo.R; + +import java.util.ArrayList; +import java.util.List; + + +public class ContextMenuDialog extends DialogFragment { + + private List items = new ArrayList<>(); + private OnClickItemListener listener; + + public static void show(Activity activity, List items, OnClickItemListener listener) { + ContextMenuDialog dialog = new ContextMenuDialog(); + dialog.items = items; + dialog.listener = listener; + dialog.show(activity.getFragmentManager(), ""); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + View root = inflater.inflate(R.layout.layout_dialog, null); + final ListView listView = root.findViewById(R.id.list_menu); + ItemAdapter itemAdapter = new ItemAdapter(); + listView.setAdapter(itemAdapter); + itemAdapter.setItems(items); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (listener != null) { + listener.onCLickItem(items.get(position)); + } + dismissAllowingStateLoss(); + } + }); + return root; + } + + public static interface OnClickItemListener { + void onCLickItem(String content); + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ItemAdapter.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ItemAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..d4341970b0e0dee2bfeec335fd5f4ec5d574fc6c --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ItemAdapter.java @@ -0,0 +1,72 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.xiaomi.mace.demo.R; + +import java.util.ArrayList; +import java.util.List; + + +public class ItemAdapter extends BaseAdapter { + + private List items = new ArrayList<>(); + + public void setItems(List items) { + this.items = items; + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return items.size(); + } + + @Override + public Object getItem(int position) { + return items.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + if (convertView != null && convertView.getTag() instanceof Holder) { + holder = (Holder) convertView.getTag(); + } else { + convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null); + holder = new Holder(); + holder.itemView = convertView.findViewById(R.id.tv_item); + convertView.setTag(holder); + } + + holder.itemView.setText(items.get(position)); + return convertView; + } + + class Holder { + TextView itemView; + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MessageEvent.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MessageEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..2c408c09537b2a8568fabf36487f192bd6318ac0 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MessageEvent.java @@ -0,0 +1,57 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +import android.graphics.Bitmap; + +import com.xiaomi.mace.demo.result.ResultData; + + +public class MessageEvent { + + public static class MaceResultEvent { + ResultData data; + + public MaceResultEvent(ResultData data) { + this.data = data; + } + + public ResultData getData() { + return data; + } + } + + public static class PicEvent { + Bitmap bitmap; + + public PicEvent(Bitmap bitmap) { + this.bitmap = bitmap; + } + + public Bitmap getBitmap() { + return bitmap; + } + } + + public static class OutputSizeEvent { + public int width; + public int height; + + public OutputSizeEvent(int width, int height) { + this.width = width; + this.height = height; + } + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MobilenetResultCallback.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MobilenetResultCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..b039d2e0fa9ad626b7d235180c4e867c5ba63f51 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MobilenetResultCallback.java @@ -0,0 +1,19 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.camera; + +public interface MobilenetResultCallback { + void onMaceResult(float[] result, long costTime); +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/InitData.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/InitData.java new file mode 100644 index 0000000000000000000000000000000000000000..5159f44f12caf220fe40b31ba9e9eb46203ebe43 --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/InitData.java @@ -0,0 +1,100 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.result; + +import android.os.Environment; + +import java.io.File; + +public class InitData { + + public static final String[] DEVICES = new String[]{"CPU", "GPU"}; + public static final String[] MODELS = new String[]{"mobilenet_v1", "mobilenet_v2"}; + + private String model; + private String device = ""; + private int ompNumThreads; + private int cpuAffinityPolicy; + private int gpuPerfHint; + private int gpuPriorityHint; + private String kernelPath = ""; + + public InitData() { + model = MODELS[0]; + ompNumThreads = 2; + cpuAffinityPolicy = 1; + gpuPerfHint = 3; + gpuPriorityHint = 3; + device = DEVICES[0]; + kernelPath = Environment.getDownloadCacheDirectory().getAbsolutePath() + File.separator + "mace"; + + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getDevice() { + return device; + } + + public void setDevice(String device) { + this.device = device; + } + + public int getOmpNumThreads() { + return ompNumThreads; + } + + public void setOmpNumThreads(int ompNumThreads) { + this.ompNumThreads = ompNumThreads; + } + + public int getCpuAffinityPolicy() { + return cpuAffinityPolicy; + } + + public void setCpuAffinityPolicy(int cpuAffinityPolicy) { + this.cpuAffinityPolicy = cpuAffinityPolicy; + } + + public int getGpuPerfHint() { + return gpuPerfHint; + } + + public void setGpuPerfHint(int gpuPerfHint) { + this.gpuPerfHint = gpuPerfHint; + } + + public int getGpuPriorityHint() { + return gpuPriorityHint; + } + + public void setGpuPriorityHint(int gpuPriorityHint) { + this.gpuPriorityHint = gpuPriorityHint; + } + + public String getKernelPath() { + return kernelPath; + } + + public void setKernelPath(String kernelPath) { + this.kernelPath = kernelPath; + } +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/LabelCache.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/LabelCache.java new file mode 100644 index 0000000000000000000000000000000000000000..e525cea33822cbfbddf9b8c9cbe7ba7e894828bf --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/LabelCache.java @@ -0,0 +1,90 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.result; + +import android.content.res.AssetManager; +import android.util.Log; + +import com.xiaomi.mace.demo.MaceApp; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LabelCache { + + private static LabelCache labelCache; + private LabelCache() { + readCacheLabelFromLocalFile(); + } + private List floatList = new ArrayList<>(); + private List resultLabel = new ArrayList<>(); + private ResultData mResultData; + + public static LabelCache instance() { + if (labelCache == null) { + synchronized (LabelCache.class) { + if (labelCache == null) { + labelCache = new LabelCache(); + } + } + } + return labelCache; + } + + + private void readCacheLabelFromLocalFile() { + try { + AssetManager assetManager = MaceApp.app.getApplicationContext().getAssets(); + BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open("cacheLabel.txt"))); + String readLine = null; + while ((readLine = reader.readLine()) != null) { + Log.d("labelCache", "readLine = " + readLine); + resultLabel.add(readLine); + } + reader.close(); + } catch (Exception e) { + Log.e("labelCache", "error " + e); + } + } + + public ResultData getResultFirst(float[] floats) { + floatList.clear(); + for (float f : floats) { + floatList.add(f); + } + float maxResult = Collections.max(floatList); + + int indexResult = floatList.indexOf(maxResult); + if (indexResult < resultLabel.size()) { + String result = resultLabel.get(indexResult); + if (result != null) { + if (mResultData == null) { + mResultData = new ResultData(result, maxResult); + } else { + mResultData.updateData(result, maxResult); + } + return mResultData; + } + } + return null; + + + } + + +} diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/ResultData.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/ResultData.java new file mode 100644 index 0000000000000000000000000000000000000000..3474465362b1a1333f7419ddbcacc04b287fb0ba --- /dev/null +++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/ResultData.java @@ -0,0 +1,35 @@ +// Copyright 2018 Xiaomi, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.xiaomi.mace.demo.result; + +public class ResultData { + public String name; + public float probability; + public long costTime; //毫秒 + + public ResultData(String name, float probability) { + this.name = name; + this.probability = probability; + } + + public ResultData(String name) { + this.name = name; + } + + public void updateData(String name, float probability) { + this.name = name; + this.probability = probability; + } +} diff --git a/mace/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/mace/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000000000000000000000000000000000000..c7bd21dbd86990cde81fea8abd3bf904b4546749 --- /dev/null +++ b/mace/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/mace/examples/android/app/src/main/res/drawable/ic_launcher_background.xml b/mace/examples/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5fccc538c179838bfdce779c26eebb4fa0b5ce9 --- /dev/null +++ b/mace/examples/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mace/examples/android/app/src/main/res/layout/activity_camera.xml b/mace/examples/android/app/src/main/res/layout/activity_camera.xml new file mode 100644 index 0000000000000000000000000000000000000000..14f5731061dcee1ecfd10823b6a8795ceeceb6c3 --- /dev/null +++ b/mace/examples/android/app/src/main/res/layout/activity_camera.xml @@ -0,0 +1,47 @@ + + + + + + + + + +