# 图像分割 本示例主要通过deeplabv3模型说明如何使用MIGraphX Python API进行图像分割模型的推理,包括预处理、模型推理。 ## 模型简介 本示例采用了经典的deeplabv3模型进行图像分割,将deeplabv3_resnet101.onnx文件保存在Resource/Models文件夹下。模型结构如下图所示, 链接:https://netron.app/, 该模型的输入shape为[batch_size,3,513,513],输出shape为[batch_size,1,513,513],数据排布为NCHW。 ## 预处理 在将数据输入到模型之前,需要对图像做如下预处理操作: ​ 1.尺度变换,将图像resize到513x513大小 ​ 2.数据排布,将数据从HWC转换为CHW,再将维度转换为NCHW ​ 3.归一化,将数据归一化到[0.0, 1.0]之间 本示例代码通过如下方式实现预处理操作: ```python def Preprocessing(pil_img, newW, newH): assert newW > 0 and newH > 0, 'Scale is too small' img_nd = cv2.cvtColor(pil_img, cv2.COLOR_BGR2RGB) # BGR转换为RGB img_nd = cv2.resize(img_nd, (newW, newH)) # 将图像尺寸修改为256x256 if len(img_nd.shape) == 2: img_nd = np.expand_dims(img_nd, axis=2) img_trans = img_nd.transpose((2, 0, 1)) # HWC转换为CHW img_trans = np.expand_dims(img_trans, 0) # CHW扩展为NCHW img_trans = np.ascontiguousarray(img_trans) # 保证内存连续存储 img_trans = img_trans.astype(np.float32) # 转换成浮点型数据 if img_trans.max() > 1: img = img_trans / 255.0 # 保证数据处于0-1之间的浮点数 return img ``` ## 推理 完成图像预处理后,就可以执行推理,得到推理结果。 ```python # 加载模型 model = migraphx.parse_onnx("../Resource/Models/deeplabv3_resnet101.onnx", map_input_dims=maxInput) # 获取模型输入/输出节点信息 inputs = model.get_inputs() outputs = model.get_outputs() inputName = model.get_parameter_names()[0] inputShape = inputs[inputName].lens() #量化 if useInt8: dic = dict() calibrate_folder_path = "../Resource/Images/" calibrate_image_extensions = ('.jpg') calibrate_image_list = [] for filename in os.listdir(calibrate_folder_path): # 检查文件是否为图片 if filename.lower().endswith(calibrate_image_extensions): file_path = os.path.join(calibrate_folder_path, filename) img = cv2.imread(file_path) calibrate_image_list.append(Preprocessing(img, 513, 513)) calibrate_img = np.concatenate(calibrate_image_list,axis=0) dic[inputName] = migraphx.argument(calibrate_img) calibration = [dic] migraphx.quantize_int8(model, migraphx.get_target("gpu"), calibration) if useFP16: migraphx.quantize_fp16(model) if offloadCopy : # 编译模型 model.compile(migraphx.get_target("gpu"), device_id=0) # device_id: 设置GPU设备,默认为0号设备 # 模型推理 mask = model.run({'input':input_img}) result = mask[0] # 得到第一个输出节点的结果 else: # 编译模型 model.compile(migraphx.get_target("gpu"),offload_copy=False, device_id=0) # device_id: 设置GPU设备,默认为0号设备 modelData = AllocateOutputMemory(model) # 为输出节点分配device内存,用于保存输出数据 modelData[inputName] = migraphx.to_gpu(migraphx.argument(input_img)) # 推理 mask = model.run(modelData) result = migraphx.from_gpu(mask[0]) # 获取第1个输出节点的数据,migraphx.argument类型 # 对通道维度进行softmax softmax_result = softmax(result) # 计算通道维度最大值对应的索引(即类别索引) max_indices = np.argmax(softmax_result, axis=1) # 使用预设颜色 color_map = np.array([ [0, 0, 0], [255, 0, 0], [0, 255, 0], [0, 0, 255], # 0-3类 [255, 255, 0], [255, 0, 255], [0, 255, 255], [128, 0, 0], # 4-7类 [0, 128, 0], [0, 0, 128], [128, 128, 0], [128, 0, 128], # 8-11类 [0, 128, 128], [192, 192, 192], [128, 128, 128], [64, 0, 0], # 12-15类 [0, 64, 0], [0, 0, 64], [64, 64, 0], [64, 0, 64], # 16-19类 [0, 64, 64] # 20类 ], dtype=np.uint8) for i in range(max_indices.shape[0]): flat_index = max_indices[i] rgb_image = color_map[flat_index] # # 将二维的类别索引图直接转换为三维的 RGB 彩色图像 fileName = "Result_"+str(i+1)+".jpg" cv2.imwrite(fileName, rgb_image) # 保存图像分割结果 print("Segmentation results have been saved to Python directory") # 保存图像分割结果 ``` 1.Preprocessing函数返回预处理后的数据(numpy类型),在offloadCopy==true时,通过model.run({'images':input_img})得到推理结果,在offloadCopy==false时,通过mask = model.run(modelData)得到推理结果,通过mask[0]获取第一个输出节点的数据即可。 2.模型得到的推理结果并不能直接作为分割结果。首先,需要计算softmax值,计算不同通道同一[H,W]位置的softmax值,找出概率最高的通道。其次,根据不同的通道索引转换为三维的 RGB 彩色图像。最终,保存结果得到分割图像。 注:本次采用的模型权重onnx文件是通过使用PASCAL VOC 2012数据集来训练的。因此,“现实世界“图像的分割结果不完美是意料之中的。为了获得更好的结果,建议对现实世界示例数据集上的模型进行微调。