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 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. ## Demo of Image Segmentation
  2. The following describes how to use the MindSpore Lite JAVA APIs and MindSpore Lite image segmentation models to perform on-device inference, classify the content captured by a device camera, and display the most possible segmentation result on the application's image preview screen.
  3. ### Running Dependencies
  4. - Android Studio 3.2 or later (Android 4.0 or later is recommended.)
  5. - Native development kit (NDK) 21.3
  6. - CMake 3.10.2 [CMake](https://cmake.org/download)
  7. - Android software development kit (SDK) 26 or later
  8. - JDK 1.8 or later
  9. ### Building and Running
  10. 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.)
  11. ![start_home](images/home.png)
  12. 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.
  13. ![start_sdk](images/sdk_management.png)
  14. If you have any Android Studio configuration problem when trying this demo, please refer to item 5 to resolve it.
  15. 2. Connect to an Android device and runs the image segmentation application.
  16. Connect to the Android device through a USB cable for debugging. Click `Run 'app'` to run the sample project on your device.
  17. ![run_app](images/run_app.PNG)
  18. For details about how to connect the Android Studio to a device for debugging, see <https://developer.android.com/studio/run/device?hl=zh-cn>.
  19. The mobile phone needs to be turn on "USB debugging mode" before Android Studio can recognize the mobile phone. Huawei mobile phones generally turn on "USB debugging model" in Settings > system and update > developer Options > USB debugging.
  20. 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.
  21. 4. The solutions of Android Studio configuration problems:
  22. | | Warning | Solution |
  23. | ---- | ------------------------------------------------------------ | ------------------------------------------------------------ |
  24. | 1 | Gradle sync failed: NDK not configured. | Specify the installed ndk directory in local.properties:ndk.dir={ndk的安装目录} |
  25. | 2 | Requested NDK version did not match the version requested by ndk.dir | Manually download corresponding [NDK Version](https://developer.android.com/ndk/downloads),and specify the sdk directory in Project Structure - Android NDK location.(You can refer to the figure below.) |
  26. | 3 | This version of Android Studio cannot open this project, please retry with Android Studio or newer. | Update Android Studio Version in Tools - help - Checkout for Updates. |
  27. | 4 | SSL peer shut down incorrectly | Run this demo again. |
  28. ![project_structure](images/project_structure.png)
  29. ## Detailed Description of the Sample Program
  30. This image segmentation sample program on the Android device is implemented through Java. At the Java layer, the Android Camera 2 API is used to enable a camera to obtain image frames and process images. Then Java API is called to infer.[Runtime](https://www.mindspore.cn/tutorial/lite/en/master/use/runtime.html).
  31. ### Sample Program Structure
  32. ```text
  33. app
  34. ├── src/main
  35. │ ├── assets # resource files
  36. | | └── deeplabv3.ms # model file
  37. │ |
  38. │ ├── java # application code at the Java layer
  39. │ │ └── com.mindspore.imagesegmentation
  40. │ │ ├── help # pre-process of image and inference of model
  41. │ │ │ └── ImageUtils # image pre-process
  42. │ │ │ └── ModelTrackingResult # post-process of result of inference
  43. │ │ │ └── TrackingMobile # load model, compile graph and perform
  44. │ │ └── BitmapUtils # image process
  45. │ │ └── MainActivity # interactive page
  46. │ │ └── OnBackgroundImageListener # get images from the photo album
  47. │ │ └── StyleRecycleViewAdapter # get images from the photo album
  48. │ │
  49. │ ├── res # resource files related to Android
  50. │ └── AndroidManifest.xml # Android configuration file
  51. ├── CMakeList.txt # CMake compilation entry file
  52. ├── build.gradle # Other Android configuration file
  53. ├── download.gradle # MindSpore version download
  54. └── ...
  55. ```
  56. ### Configuring MindSpore Lite Dependencies
  57. When MindSpore Java APIs are called, related library files are required. You can use MindSpore Lite [source code compilation](https://www.mindspore.cn/tutorial/lite/en/master/use/build.html) to generate the MindSpore Lite version. In this case, you need to use the compile command of generate with image preprocessing module.
  58. In this example, the build process automatically downloads the `mindspore-lite-1.0.1-runtime-arm64-cpu` by the `app/download.gradle` file and saves in the `app/src/main/cpp` directory.
  59. Note: if the automatic download fails, please manually download the relevant library files and put them in the corresponding location.
  60. mindspore-lite-1.0.1-runtime-arm64-cpu.tar.gz [Download link](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)
  61. ```text
  62. android{
  63. defaultConfig{
  64. externalNativeBuild{
  65. cmake{
  66. arguments "-DANDROID_STL=c++_shared"
  67. }
  68. }
  69. ndk{
  70. abiFilters'armeabi-v7a', 'arm64-v8a'
  71. }
  72. }
  73. }
  74. ```
  75. Create a link to the `.so` library file in the `app/CMakeLists.txt` file:
  76. ```text
  77. # ============== Set MindSpore Dependencies. =============
  78. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp)
  79. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/third_party/flatbuffers/include)
  80. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION})
  81. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/include)
  82. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/include/ir/dtype)
  83. include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/include/schema)
  84. add_library(mindspore-lite SHARED IMPORTED )
  85. add_library(minddata-lite SHARED IMPORTED )
  86. set_target_properties(mindspore-lite PROPERTIES IMPORTED_LOCATION
  87. ${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/lib/libmindspore-lite.so)
  88. set_target_properties(minddata-lite PROPERTIES IMPORTED_LOCATION
  89. ${CMAKE_SOURCE_DIR}/src/main/cpp/${MINDSPORELITE_VERSION}/lib/libminddata-lite.so)
  90. # --------------- MindSpore Lite set End. --------------------
  91. # Link target library.
  92. target_link_libraries(
  93. ...
  94. # --- mindspore ---
  95. minddata-lite
  96. mindspore-lite
  97. ...
  98. )
  99. ```
  100. ### Downloading and Deploying a Model File
  101. In this example, the download.gradle File configuration auto download `deeplabv3.ms`and placed in the 'app/libs/arm64-v8a' directory.
  102. Note: if the automatic download fails, please manually download the relevant library files and put them in the corresponding location.
  103. deeplabv3.ms [deeplabv3.ms]( https://download.mindspore.cn/model_zoo/official/lite/deeplabv3_openimage_lite/deeplabv3.ms)
  104. ### Compiling On-Device Inference Code
  105. Call MindSpore Lite Java APIs to implement on-device inference.
  106. The inference code process is as follows. For details about the complete code, see `src/java/TrackingMobile.java`.
  107. 1. Load the MindSpore Lite model file and build the context, session, and computational graph for inference.
  108. - Load a model file. Import and configure the context for model inference.
  109. ```Java
  110. // Create context and load the .ms model named 'IMAGESEGMENTATIONMODEL'
  111. model = new Model();
  112. if (!model.loadModel(Context, IMAGESEGMENTATIONMODEL)) {
  113. Log.e(TAG, "Load Model failed");
  114. return;
  115. }
  116. ```
  117. - Create a session.
  118. ```Java
  119. // Create and init config.
  120. msConfig = new MSConfig();
  121. if (!msConfig.init(DeviceType.DT_CPU, 2, CpuBindMode.MID_CPU)) {
  122. Log.e(TAG, "Init context failed");
  123. return;
  124. }
  125. // Create the MindSpore lite session.
  126. session = new LiteSession();
  127. if (!session.init(msConfig)) {
  128. Log.e(TAG, "Create session failed");
  129. msConfig.free();
  130. return;
  131. }
  132. msConfig.free();
  133. ```
  134. - Compile graph for inference.
  135. ```Java
  136. if (!session.compileGraph(model)) {
  137. Log.e(TAG, "Compile graph failed");
  138. model.freeBuffer();
  139. return;
  140. }
  141. // Note: when use model.freeBuffer(), the model can not be complile graph again.
  142. model.freeBuffer();
  143. ```
  144. 2. Convert the input image into the Tensor format of the MindSpore model.
  145. ```Java
  146. List<MSTensor> inputs = session.getInputs();
  147. if (inputs.size() != 1) {
  148. Log.e(TAG, "inputs.size() != 1");
  149. return null;
  150. }
  151. // `bitmap` is the picture used to infer.
  152. float resource_height = bitmap.getHeight();
  153. float resource_weight = bitmap.getWidth();
  154. ByteBuffer contentArray = bitmapToByteBuffer(bitmap, imageSize, imageSize, IMAGE_MEAN, IMAGE_STD);
  155. MSTensor inTensor = inputs.get(0);
  156. inTensor.setData(contentArray);
  157. ```
  158. 3. Perform inference on the input tensor based on the model, obtain the output tensor, and perform post-processing.
  159. - Perform graph execution and on-device inference.
  160. ```Java
  161. // After the model and image tensor data is loaded, run inference.
  162. if (!session.runGraph()) {
  163. Log.e(TAG, "Run graph failed");
  164. return null;
  165. }
  166. ```
  167. - Obtain the output data.
  168. ```Java
  169. // Get output tensor values, the model only outputs one tensor.
  170. List<String> tensorNames = session.getOutputTensorNames();
  171. MSTensor output = session.getOutputByTensorName(tensorNames.front());
  172. if (output == null) {
  173. Log.e(TAG, "Can not find output " + tensorName);
  174. return null;
  175. }
  176. ```
  177. - Perform post-processing of the output data.
  178. ```Java
  179. // Show output as pictures.
  180. float[] results = output.getFloatData();
  181. ByteBuffer bytebuffer_results = floatArrayToByteArray(results);
  182. Bitmap dstBitmap = convertBytebufferMaskToBitmap(bytebuffer_results, imageSize, imageSize, bitmap, dstBitmap, segmentColors);
  183. dstBitmap = scaleBitmapAndKeepRatio(dstBitmap, (int) resource_height, (int) resource_weight);
  184. ```
  185. 4. The process of image and output data can refer to methods showing bellow.
  186. ```Java
  187. Bitmap scaleBitmapAndKeepRatio(Bitmap targetBmp, int reqHeightInPixels, int reqWidthInPixels) {
  188. if (targetBmp.getHeight() == reqHeightInPixels && targetBmp.getWidth() == reqWidthInPixels) {
  189. return targetBmp;
  190. }
  191. Matrix matrix = new Matrix();
  192. matrix.setRectToRect(new RectF(0f, 0f, targetBmp.getWidth(), targetBmp.getHeight()),
  193. new RectF(0f, 0f, reqWidthInPixels, reqHeightInPixels), Matrix.ScaleToFit.FILL;
  194. return Bitmap.createBitmap(targetBmp, 0, 0, targetBmp.getWidth(), targetBmp.getHeight(), matrix, true);
  195. }
  196. ByteBuffer bitmapToByteBuffer(Bitmap bitmapIn, int width, int height, float mean, float std) {
  197. Bitmap bitmap = scaleBitmapAndKeepRatio(bitmapIn, width, height);
  198. ByteBuffer inputImage = ByteBuffer.allocateDirect(1 * width * height * 3 * 4);
  199. inputImage.order(ByteOrder.nativeOrder());
  200. inputImage.rewind();
  201. int[] intValues = new int[width * height];
  202. bitmap.getPixels(intValues, 0, width, 0, 0, width, height);
  203. int pixel = 0;
  204. for (int y = 0; y < height; y++) {
  205. for (int x = 0; x < width; x++) {
  206. int value = intValues[pixel++];
  207. inputImage.putFloat(((float) (value >> 16 & 255) - mean) / std);
  208. inputImage.putFloat(((float) (value >> 8 & 255) - mean) / std);
  209. inputImage.putFloat(((float) (value & 255) - mean) / std);
  210. }
  211. }
  212. inputImage.rewind();
  213. return inputImage;
  214. }
  215. ByteBuffer floatArrayToByteArray(float[] floats) {
  216. ByteBuffer buffer = ByteBuffer.allocate(4 * floats.length);
  217. FloatBuffer floatBuffer = buffer.asFloatBuffer();
  218. floatBuffer.put(floats);
  219. return buffer;
  220. }
  221. Bitmap convertBytebufferMaskToBitmap(ByteBuffer inputBuffer, int imageWidth, int imageHeight, Bitmap backgroundImage, int[] colors) {
  222. Bitmap.Config conf = Bitmap.Config.ARGB_8888;
  223. Bitmap dstBitmap = Bitmap.createBitmap(imageWidth, imageHeight, conf);
  224. Bitmap scaledBackgroundImage = scaleBitmapAndKeepRatio(backgroundImage, imageWidth, imageHeight);
  225. int[][] mSegmentBits = new int[imageWidth][imageHeight];
  226. inputBuffer.rewind();
  227. for (int y = 0; y < imageHeight; y++) {
  228. for (int x = 0; x < imageWidth; x++) {
  229. float maxVal = 0f;
  230. mSegmentBits[x][y] = 0;
  231. // NUM_CLASSES is the number of labels, the value here is 21.
  232. for (int i = 0; i < NUM_CLASSES; i++) {
  233. float value = inputBuffer.getFloat((y * imageWidth * NUM_CLASSES + x * NUM_CLASSES + i) * 4);
  234. if (i == 0 || value > maxVal) {
  235. maxVal = value;
  236. // Check wether a pixel belongs to a person whose label is 15.
  237. if (i == 15) {
  238. mSegmentBits[x][y] = i;
  239. } else {
  240. mSegmentBits[x][y] = 0;
  241. }
  242. }
  243. }
  244. itemsFound.add(mSegmentBits[x][y]);
  245. int newPixelColor = ColorUtils.compositeColors(
  246. colors[mSegmentBits[x][y] == 0 ? 0 : 1],
  247. scaledBackgroundImage.getPixel(x, y)
  248. );
  249. dstBitmap.setPixel(x, y, mSegmentBits[x][y] == 0 ? colors[0] : scaledBackgroundImage.getPixel(x, y));
  250. }
  251. }
  252. return dstBitmap;
  253. }
  254. ```