You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.en.md 13 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. # MindSpore Lite Scene Detection Demo (Android)
  2. This sample application demonstrates how to use the MindSpore Lite C++ API (Android JNI) and MindSpore Lite scene detection model to perform inference on the device, detect the content captured by the device camera, and display the continuous objective detection result on the image preview screen of the app.
  3. ## Running Dependencies
  4. - Android Studio 3.2 or later (Android 4.0 or later is recommended.)
  5. - NDK 21.3
  6. - CMake 3.10
  7. - Android software development kit (SDK) 26 or later
  8. ## Building and Running
  9. 1. Load the sample source code to Android Studio and install the corresponding SDK. (After the SDK version is specified, Android Studio automatically installs the SDK.)
  10. ![start_home](images/home.png)
  11. Start Android Studio, click `File > Settings > System Settings > Android SDK`, and select the corresponding SDK. As shown in the following figure, select an SDK and click `OK`. Android Studio automatically installs the SDK.
  12. ![start_sdk](images/sdk_management.png)
  13. If an Android Studio configuration error occurs, solve it by referring to the following table.
  14. | | Error | Solution |
  15. | ---- | ------------------------------------------------------------ | ------------------------------------------------------------ |
  16. | 1 | Gradle sync failed: NDK not configured. | Specify the NDK installation directory in the local.properties file: ndk.dir={NDK installation directory} |
  17. | 2 | Requested NDK version did not match the version requested by ndk.dir | Manually download the corresponding [NDK version](https://developer.android.com/ndk/downloads) and specify the SDK location in the `Android NDK location` field (see the following figure). |
  18. | 3 | This version of Android Studio cannot open this project, please retry with Android Studio or newer. | Choose `Help` > `Checkout for Updates` on the toolbar to update the version. |
  19. | 4 | SSL peer shut down incorrectly | Rebuild. |
  20. ![project_structure](images/project_structure.png)
  21. 2. Connect to an Android device and run the scene detection sample application.
  22. Connect to the Android device through a USB cable for debugging. Click `Run 'app'` to run the sample project on your device.
  23. > During the building, Android Studio automatically downloads dependencies related to MindSpore Lite and model files. Please wait.
  24. ![run_app](images/run_app.PNG)
  25. For details about how to connect the Android Studio to a device for debugging, see <https://developer.android.com/studio/run/device>.
  26. 3. Continue the installation on the Android device. After the installation is complete, you can view the content captured by a camera and the inference result.
  27. ![install](images/install.jpg)
  28. ## Detailed Description of the Sample Application
  29. The scene detection sample application on the Android device includes a Java layer and a JNI layer. At the Java layer, the Android Camera 2 API is used to enable a camera to obtain image frames and process images (drawing frames based on the inference result). At the JNI layer, the model inference process is completed in [runtime](https://www.mindspore.cn/tutorial/lite/en/master/use/runtime.html).
  30. > This following describes the JNI layer implementation of the sample application. At the Java layer, the Android Camera 2 API is used to enable a device camera and process image frames. Readers are expected to have the basic Android development knowledge.
  31. ### Sample Application Structure
  32. ```text
  33. app
  34. |
  35. ├── libs # Library files built by the demo JNI layer
  36. │ └── arm64-v8a
  37. │ │── libmlkit-label-MS.so #
  38. |
  39. ├── src/main
  40. │ ├── assets # Resource file
  41. | | └── mobilenetv2.ms # Model file
  42. │ |
  43. │ ├── cpp # Main logic encapsulation classes for model loading and prediction
  44. | | ├── mindspore-lite-x.x.x-mindata-arm64-cpu # Calling package built from the MindSpore source code, including the library files and related header files on which the demo JNI layer depends
  45. | | | └── ...
  46. │ | |
  47. | | ├── MindSporeNetnative.cpp # JNI methods related to MindSpore calling
  48. │ ├── java # Application code at the Java layer
  49. │ │ └── com.huawei.himindsporedemo
  50. │ │ ├── help # Implementation related to image processing and MindSpore JNI calling
  51. │ │ │ └── ...
  52. │ │ └── obejctdetect # Implementation related to camera enabling and drawing
  53. │ │ └── ...
  54. │ │
  55. │ ├── res # Resource files related to Android
  56. │ └── AndroidManifest.xml # Android configuration file
  57. ├── CMakeLists.txt # CMake compilation entry file
  58. ├── build.gradle # Other Android configuration file
  59. ├── download.gradle # During app building, the .gradle file automatically downloads the dependent library files and model files from the Huawei server.
  60. └── ...
  61. ```
  62. ### Configuring MindSpore Lite Dependencies
  63. When MindSpore C++ APIs are called at the Android JNI layer, related library files are required. You can refer to [Building MindSpore Lite](https://www.mindspore.cn/tutorial/lite/en/master/use/build.html) to generate the `mindspore-lite-{version}-minddata-{os}-{device}.tar.gz` library file package (including the `libmindspore-lite.so` library file and related header files) and decompress it. The following example uses the build command with the image preprocessing module.
  64. > version: version number in the output file, which is the same as the version number of the built branch code.
  65. >
  66. > device: The value can be cpu (built-in CPU operator) or gpu (built-in CPU and GPU operator).
  67. >
  68. > os: operating system to be deployed in the output file.
  69. In this example, the MindSpore Lite version file is automatically downloaded by the download.gradle file during the build process and stored in the `app/src/main/cpp/` directory.
  70. > If the automatic download fails, manually download the library file [mindspore-lite-1.0.1-runtime-arm64-cpu.tar.gz](https://ms-release.obs.cn-north-4.myhuaweicloud.com/1.0.1/lite/android_aarch64/mindspore-lite-1.0.1-runtime-arm64-cpu.tar.gz), and decompress and save it to the directory.
  71. In the `build.gradle` file of the app, configure the build support of both CMake and `arm64-v8a`:
  72. ```text
  73. android{
  74. defaultConfig{
  75. externalNativeBuild{
  76. cmake{
  77. arguments "-DANDROID_STL=c++_shared"
  78. }
  79. }
  80. ndk{
  81. abiFilters 'arm64-v8a'
  82. }
  83. }
  84. }
  85. ```
  86. Create a link to the `.so` library file in the `app/CMakeLists.txt` file:
  87. ```text
  88. # Set MindSpore Lite Dependencies.
  89. set(MINDSPORELITE_VERSION mindspore-lite-1.0.1-runtime-arm64-cpu)
  90. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION})
  91. add_library(mindspore-lite SHARED IMPORTED )
  92. add_library(minddata-lite SHARED IMPORTED )
  93. set_target_properties(mindspore-lite PROPERTIES IMPORTED_LOCATION
  94. ${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/lib/libmindspore-lite.so)
  95. set_target_properties(minddata-lite PROPERTIES IMPORTED_LOCATION
  96. ${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/lib/libminddata-lite.so)
  97. # Link target library.
  98. target_link_libraries(
  99. ...
  100. mindspore-lite
  101. minddata-lite
  102. ...
  103. )
  104. ```
  105. ### Downloading and Deploying the Model File
  106. Download the model file from MindSpore Model Hub. The scene detection model file used in this sample application is `mobilenetv2.ms`, which is automatically downloaded during app building using the `download.gradle` script and stored in the `app/src/main/assets` project directory.
  107. > If the download fails, manually download the model file [mobilenetv2.ms](https://download.mindspore.cn/model_zoo/official/lite/mobilenetv2_openimage_lite/mobilenetv2.ms).
  108. ### Writing On-Device Inference Code
  109. Call MindSpore Lite C++ APIs at the JNI layer to implement on-device inference.
  110. The inference code process is as follows. For details about the complete code, see `src/cpp/MindSporeNetnative.cpp`.
  111. 1. Load the MindSpore Lite model file and build the context, session, and computational graph for inference.
  112. - Load a model file.
  113. ```cpp
  114. jlong bufferLen = env->GetDirectBufferCapacity(model_buffer);
  115. if (0 == bufferLen) {
  116. MS_PRINT("error, bufferLen is 0!");
  117. return (jlong) nullptr;
  118. }
  119. char *modelBuffer = CreateLocalModelBuffer(env, model_buffer);
  120. if (modelBuffer == nullptr) {
  121. MS_PRINT("modelBuffer create failed!");
  122. return (jlong) nullptr;
  123. }
  124. ```
  125. - Create a session.
  126. ```cpp
  127. void **labelEnv = new void *;
  128. MSNetWork *labelNet = new MSNetWork;
  129. *labelEnv = labelNet;
  130. mindspore::lite::Context *context = new mindspore::lite::Context;
  131. context->thread_num_ = num_thread;
  132. context->device_list_[0].device_info_.cpu_device_info_.cpu_bind_mode_ = mindspore::lite::NO_BIND;
  133. context->device_list_[0].device_info_.cpu_device_info_.enable_float16_ = false;
  134. context->device_list_[0].device_type_ = mindspore::lite::DT_CPU;
  135. labelNet->CreateSessionMS(modelBuffer, bufferLen, context);
  136. delete context;
  137. ```
  138. - Load the model file and build a computational graph for inference.
  139. ```cpp
  140. void
  141. MSNetWork::CreateSessionMS(char *modelBuffer, size_t bufferLen, mindspore::lite::Context *ctx) {
  142. session_ = mindspore::session::LiteSession::CreateSession(ctx);
  143. if (session_ == nullptr) {
  144. MS_PRINT("Create Session failed.");
  145. return;
  146. }
  147. // Compile model.
  148. model_ = mindspore::lite::Model::Import(modelBuffer, bufferLen);
  149. if (model_ == nullptr) {
  150. ReleaseNets();
  151. MS_PRINT("Import model failed.");
  152. return;
  153. }
  154. int ret = session_->CompileGraph(model_);
  155. if (ret != mindspore::lite::RET_OK) {
  156. ReleaseNets();
  157. MS_PRINT("CompileGraph failed.");
  158. return;
  159. }
  160. }
  161. ```
  162. 2. Convert the input image into the Tensor format of the MindSpore model.
  163. ```cpp
  164. // Convert the Bitmap image passed in from the JAVA layer to Mat for OpenCV processing
  165. LiteMat lite_mat_bgr,lite_norm_mat_cut;
  166. if (!BitmapToLiteMat(env, srcBitmap, lite_mat_bgr)){
  167. MS_PRINT("BitmapToLiteMat error");
  168. return NULL;
  169. }
  170. int srcImageWidth = lite_mat_bgr.width_;
  171. int srcImageHeight = lite_mat_bgr.height_;
  172. if(!PreProcessImageData(lite_mat_bgr, lite_norm_mat_cut)){
  173. MS_PRINT("PreProcessImageData error");
  174. return NULL;
  175. }
  176. ImgDims inputDims;
  177. inputDims.channel =lite_norm_mat_cut.channel_;
  178. inputDims.width = lite_norm_mat_cut.width_;
  179. inputDims.height = lite_norm_mat_cut.height_;
  180. // Get the mindsore inference environment which created in loadModel().
  181. void **labelEnv = reinterpret_cast<void **>(netEnv);
  182. if (labelEnv == nullptr) {
  183. MS_PRINT("MindSpore error, labelEnv is a nullptr.");
  184. return NULL;
  185. }
  186. MSNetWork *labelNet = static_cast<MSNetWork *>(*labelEnv);
  187. auto mSession = labelNet->session;
  188. if (mSession == nullptr) {
  189. MS_PRINT("MindSpore error, Session is a nullptr.");
  190. return NULL;
  191. }
  192. MS_PRINT("MindSpore get session.");
  193. auto msInputs = mSession->GetInputs();
  194. auto inTensor = msInputs.front();
  195. float *dataHWC = reinterpret_cast<float *>(lite_norm_mat_cut.data_ptr_);
  196. // copy input Tensor
  197. memcpy(inTensor->MutableData(), dataHWC,
  198. inputDims.channel * inputDims.width * inputDims.height * sizeof(float));
  199. delete[] (dataHWC);
  200. ```
  201. 3. Perform inference on the input tensor based on the model to obtain the output tensor.
  202. - Perform graph execution and on-device inference.
  203. ```cpp
  204. // After the model and image tensor data is loaded, run inference.
  205. auto status = mSession->RunGraph();
  206. if (status != mindspore::lite::RET_OK) {
  207. MS_PRINT("MindSpore run net error.");
  208. return NULL;
  209. }
  210. ```
  211. - Obtain the output data.
  212. ```cpp
  213. /**
  214. * Get the mindspore inference results.
  215. * Return the map of output node name and MindSpore Lite MSTensor.
  216. */
  217. auto names = mSession->GetOutputTensorNames();
  218. std::unordered_map<std::string, mindspore::tensor::MSTensor *> msOutputs;
  219. for (const auto &name : names) {
  220. auto temp_dat = mSession->GetOutputByTensorName(name);
  221. msOutputs.insert(std::pair<std::string, mindspore::tensor::MSTensor *>{name, temp_dat});
  222. }
  223. ```