【发布时间】:2020-10-03 11:03:16
【问题描述】:
如果有人能就我上周一直在工作但没有成功的任务提供建议,我将不胜感激。 我有语义分割模型(MobileNetV3 + Lightweight ASPP)。简短信息:输入 - 1024x1024,输出 - 相同大小和 2 个类(bg 和车辆),所以我的输出形状是(1、1048576、2)。我不是移动开发人员或 java 世界的人,所以我使用了一些完整的 Android 示例进行图像分割来测试它: 来自谷歌的那个:https://github.com/tensorflow/examples/tree/master/lite/examples/image_segmentation 另一个开源的:https://github.com/pillarpond/image-segmenter-android
我成功地将其转换为 tflite 格式,并且它在启用 GPU 且 10 个线程的 OnePlus 7 上的推理时间在 105-140 毫秒之间。但是在这里我遇到了一个问题:这两个 android 示例或任何您可以找到的语义分割的一般执行时间约为 1050-1300 毫秒(小于 1FPS)。该管道中较慢的部分是图像后处理(~900-1150ms)。您可以在 Deeplab#segment 方法中看到该部分。因为除了 bg 之外我只有 1 个班级 - 我没有 this third loop,但其他所有内容都没有受到影响,而且仍然很慢。与其他常见的移动尺寸(如 128/226/512)相比,输出尺寸并不小,但仍然如此。我认为在现代智能手机上处理 1024x1024 矩阵并在画布上绘制矩形不应该花费太多时间。 我尝试了不同的解决方案,例如将矩阵操作拆分为线程或创建所有这些对象(如 RectF 和 Recognition),然后在嵌套循环中用新数据填充它们的属性,但我没有成功。在桌面端,我用 numpy 和 opencv 轻松处理它,我什至不了解如何在 Android 中做同样的事情,它是否有效。 这是我在 python 中使用的代码:
CLASS_COLORS = [(0, 0, 0), (255, 255, 255)] # black for bg and white for mask
def get_image_array(image_input, width, height):
img = cv2.imread(image_input, 1)
img = cv2.resize(img, (width, height))
img = img.astype(np.float32)
img[:, :, 0] -= 128.0
img[:, :, 1] -= 128.0
img[:, :, 2] -= 128.0
img = img[:, :, ::-1]
return img
def get_segmentation_array(seg_arr, n_classes):
output_height = seg_arr.shape[0]
output_width = seg_arr.shape[1]
seg_img = np.zeros((output_height, output_width, 3))
for c in range(n_classes):
seg_arr_c = seg_arr[:, :] == c
seg_img[:, :, 0] += ((seg_arr_c)*(CLASS_COLORS[c][0])).astype('uint8')
seg_img[:, :, 1] += ((seg_arr_c)*(CLASS_COLORS[c][1])).astype('uint8')
seg_img[:, :, 2] += ((seg_arr_c)*(CLASS_COLORS[c][2])).astype('uint8')
return seg_img
interpreter = tf.lite.Interpreter(model_path=f"my_model.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
img_arr = get_image_array("input.png", 1024, 1024)
interpreter.set_tensor(input_details[0]['index'], np.array([x]))
interpreter.invoke()
output = interpreter.get_tensor(output_details[0]['index'])
output = output.reshape((1024, 1024, 2)).argmax(axis=2)
seg_img = get_segmentation_array(output, 2)
cv2.imwrite("output.png", seg_img)
也许有什么比当前的后处理解决方案更强大。 我真的很感激这方面的任何帮助。我确信有任何东西可以改进后处理并将其时间减少到 ~100 毫秒,所以我一般会有 ~5FPS。
【问题讨论】:
-
我认为你应该在 android 中尝试 OpenCv。看看this 项目,其中 OpenCv 在一个用于分割肺病的安卓应用程序中使用。 OpenCv 有一个用于斑点检测的类,它可以在斑点(掩码)的边缘绘制矩形。如果您需要任何帮助,请标记我
-
感谢@Farmaker 的帮助!
标签: java android tensorflow-lite opencv4android semantic-segmentation