Merge pull request #20290 from wjj19950828:add_paddle_humanseg_demo

Add paddle humanseg demo

* fixed onnx resize op bug

* add humanseg demo for PaddlePaddle sample

* update README.md and flake8 format

* update func name

* update README.md for enviroment setup

* update README.md in the way install paddle2onnx

* update README.md

* update README.md

* add paddleseg in requirements.txt

* deal with comments

* replace picture
pull/20771/head
WJJ1995 3 years ago committed by GitHub
parent 98ad72b096
commit 8fa8d471af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 69
      samples/dnn/dnn_model_runner/dnn_conversion/paddlepaddle/README.md
  2. BIN
      samples/dnn/dnn_model_runner/dnn_conversion/paddlepaddle/data/result_test_human.jpg
  3. 112
      samples/dnn/dnn_model_runner/dnn_conversion/paddlepaddle/paddle_humanseg.py
  4. 18
      samples/dnn/dnn_model_runner/dnn_conversion/paddlepaddle/paddle_resnet50.py
  5. 1
      samples/dnn/dnn_model_runner/dnn_conversion/requirements.txt

@ -1,6 +1,6 @@
# Run PaddlePaddle model by OpenCV
# Run PaddlePaddle model using OpenCV
This tutorial shows how to run PaddlePaddle model by opencv.
These two demonstrations show how to inference PaddlePaddle model using OpenCV.
## Environment Setup
@ -10,16 +10,69 @@ pip install paddlehub
pip install paddle2onnx
```
## Run PaddlePaddle model demo
## 1. Run PaddlePaddle ResNet50 using OpenCV
Run the example code as below,
### Run PaddlePaddle model demo
Run the code sample as follows:
```shell
python paddle_resnet50.py
```
there are 3 part of this execution
There are three parts to the process:
1. Export PaddlePaddle ResNet50 model to onnx format.
2. Use `cv2.dnn.readNetFromONNX` to load the model file.
3. Preprocess image file and do the inference.
## 2. Run PaddleSeg Portrait Segmentation using OpenCV
### Convert to ONNX Model
#### 1. Get Paddle Inference model
For more details, please refer to [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.1/contrib/HumanSeg/README.md).
```shell
wget https://x2paddle.bj.bcebos.com/inference/models/humanseg_hrnet18_small_v1.zip
unzip humanseg_hrnet18_small_v1.zip
```
Notes:
* The exported model must have a fixed input shape, as dynamic is not supported at this moment.
#### 2. Convert to ONNX model using paddle2onnx
To convert the model, use the following command:
```
paddle2onnx --model_dir humanseg_hrnet18_small_v1 \
--model_filename model.pdmodel \
--params_filename model.pdiparams \
--opset_version 11 \
--save_file humanseg_hrnet18_tiny.onnx
```
The converted model can be found in the current directory by the name `humanseg_hrnet18_tiny.onnx` .
### Run PaddleSeg Portrait Segmentation demo
Run the code sample as follows:
```shell
python paddle_humanseg.py
```
There are three parts to the process:
1. Use `cv2.dnn.readNetFromONNX` to load the model file.
2. Preprocess image file and do inference.
3. Postprocess image file and visualize.
The resulting file can be found at `data/result_test_human.jpg` .
### Portrait segmentation visualization
- 1. Export PaddlePaddle ResNet50 model to onnx format;
- 2. Use `cv2.dnn.readNetFromONNX` load model file;
- 3. Preprocess image file and do inference.
<img src="../../../../data/messi5.jpg" width="50%" height="50%"><img src="./data/result_test_human.jpg" width="50%" height="50%">

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

@ -0,0 +1,112 @@
import os
import paddlehub.vision.transforms as T
import numpy as np
import cv2 as cv
def get_color_map_list(num_classes):
"""
Returns the color map for visualizing the segmentation mask,
which can support arbitrary number of classes.
Args:
num_classes (int): Number of classes.
Returns:
(list). The color map.
"""
num_classes += 1
color_map = num_classes * [0, 0, 0]
for i in range(0, num_classes):
j = 0
lab = i
while lab:
color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
j += 1
lab >>= 3
color_map = color_map[3:]
return color_map
def visualize(image, result, save_dir=None, weight=0.6):
"""
Convert predict result to color image, and save added image.
Args:
image (str): The path of origin image.
result (np.ndarray): The predict result of image.
save_dir (str): The directory for saving visual image. Default: None.
weight (float): The image weight of visual image, and the result weight is (1 - weight). Default: 0.6
Returns:
vis_result (np.ndarray): If `save_dir` is None, return the visualized result.
"""
color_map = get_color_map_list(256)
color_map = [color_map[i:i + 3] for i in range(0, len(color_map), 3)]
color_map = np.array(color_map).astype("uint8")
# Use OpenCV LUT for color mapping
c1 = cv.LUT(result, color_map[:, 0])
c2 = cv.LUT(result, color_map[:, 1])
c3 = cv.LUT(result, color_map[:, 2])
pseudo_img = np.dstack((c1, c2, c3))
im = cv.imread(image)
vis_result = cv.addWeighted(im, weight, pseudo_img, 1 - weight, 0)
if save_dir is not None:
if not os.path.exists(save_dir):
os.makedirs(save_dir)
image_name = os.path.split(image)[-1]
out_path = os.path.join(save_dir, image_name)
cv.imwrite(out_path, vis_result)
else:
return vis_result
def preprocess(image_path):
''' preprocess input image file to np.ndarray
Args:
image_path(str): Path of input image file
Returns:
ProcessedImage(numpy.ndarray): A numpy.ndarray
variable which shape is (1, 3, 192, 192)
'''
transforms = T.Compose([
T.Resize((192, 192)),
T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
],
to_rgb=True)
return np.expand_dims(transforms(image_path), axis=0)
if __name__ == '__main__':
img_path = "../../../../data/messi5.jpg"
# load PPSeg Model use cv.dnn
net = cv.dnn.readNetFromONNX('humanseg_hrnet18_tiny.onnx')
# read and preprocess image file
im = preprocess(img_path)
# inference
net.setInput(im)
result = net.forward(['save_infer_model/scale_0.tmp_1'])
# post process
image = cv.imread(img_path)
r, c, _ = image.shape
result = np.argmax(result[0], axis=1).astype(np.uint8)
result = cv.resize(result[0, :, :],
dsize=(c, r),
interpolation=cv.INTER_NEAREST)
print("grid_image.shape is: ", result.shape)
folder_path = "data"
if not os.path.exists(folder_path):
os.makedirs(folder_path)
file_path = os.path.join(folder_path, '%s.jpg' % "result_test_human")
result_color = visualize(img_path, result)
cv.imwrite(file_path, result_color)
print('%s saved' % file_path)

@ -16,15 +16,15 @@ def preprocess(image_path):
variable which shape is (1, 3, 224, 224)
'''
transforms = T.Compose([
T.Resize((256, 256)),
T.CenterCrop(224),
T.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])],
to_rgb=True)
T.Resize((256, 256)),
T.CenterCrop(224),
T.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])],
to_rgb=True)
return np.expand_dims(transforms(image_path), axis=0)
def export_onnx_mobilenetv2(save_path):
def export_onnx_resnet50(save_path):
''' export PaddlePaddle model to ONNX format
Args:
@ -35,7 +35,7 @@ def export_onnx_mobilenetv2(save_path):
'''
model = hub.Module(name="resnet50_vd_imagenet_ssld")
input_spec = paddle.static.InputSpec(
[1, 3, 224, 224], "float32", "image")
[1, 3, 224, 224], "float32", "image")
paddle.onnx.export(model, save_path,
input_spec=[input_spec],
opset_version=10)
@ -45,9 +45,9 @@ if __name__ == '__main__':
save_path = './resnet50'
image_file = './data/cat.jpg'
labels = open('./data/labels.txt').read().strip().split('\n')
model = export_onnx_mobilenetv2(save_path)
model = export_onnx_resnet50(save_path)
# load mobilenetv2 use cv.dnn
# load resnet50 use cv.dnn
net = cv.dnn.readNetFromONNX(save_path + '.onnx')
# read and preprocess image file
im = preprocess(image_file)

@ -12,3 +12,4 @@ paddlepaddle>=2.0.0
paddlepaddle-gpu>=2.0.0
paddlehub>=2.1.0
paddle2onnx>=0.5.1
paddleseg>=2.0.0
Loading…
Cancel
Save