From e60afe4993cab9174683be400b46375f7edaddee Mon Sep 17 00:00:00 2001
From: RE-OWOD <95522332+RE-OWOD@users.noreply.github.com>
Date: Tue, 4 Jan 2022 13:54:26 +0800
Subject: [PATCH] Add files via upload
---
projects/DensePose/dev/README.md | 7 +
projects/DensePose/dev/run_inference_tests.sh | 33 +++
projects/DensePose/dev/run_instant_tests.sh | 28 ++
projects/DensePose/doc/GETTING_STARTED.md | 58 ++++
projects/DensePose/doc/MODEL_ZOO.md | 277 ++++++++++++++++++
projects/DensePose/doc/TOOL_APPLY_NET.md | 131 +++++++++
projects/DensePose/doc/TOOL_QUERY_DB.md | 105 +++++++
.../doc/images/res_bbox_dp_contour.jpg | Bin 0 -> 91492 bytes
.../DensePose/doc/images/res_bbox_dp_segm.jpg | Bin 0 -> 156777 bytes
.../DensePose/doc/images/res_bbox_dp_u.jpg | Bin 0 -> 158784 bytes
.../DensePose/doc/images/res_bbox_dp_v.jpg | Bin 0 -> 158204 bytes
.../DensePose/doc/images/vis_bbox_dp_i.jpg | Bin 0 -> 86262 bytes
.../DensePose/doc/images/vis_bbox_dp_pts.jpg | Bin 0 -> 83397 bytes
.../DensePose/doc/images/vis_bbox_dp_segm.jpg | Bin 0 -> 79599 bytes
.../DensePose/doc/images/vis_bbox_dp_u.jpg | Bin 0 -> 87042 bytes
.../DensePose/doc/images/vis_bbox_dp_v.jpg | Bin 0 -> 86995 bytes
projects/DensePose/tests/common.py | 124 ++++++++
.../tests/test_combine_data_loader.py | 46 +++
.../DensePose/tests/test_frame_selector.py | 60 ++++
.../tests/test_image_resize_transform.py | 16 +
projects/DensePose/tests/test_model_e2e.py | 43 +++
projects/DensePose/tests/test_setup.py | 36 +++
projects/DensePose/tests/test_structures.py | 25 ++
.../tests/test_video_keyframe_dataset.py | 92 ++++++
24 files changed, 1081 insertions(+)
create mode 100644 projects/DensePose/dev/README.md
create mode 100644 projects/DensePose/dev/run_inference_tests.sh
create mode 100644 projects/DensePose/dev/run_instant_tests.sh
create mode 100644 projects/DensePose/doc/GETTING_STARTED.md
create mode 100644 projects/DensePose/doc/MODEL_ZOO.md
create mode 100644 projects/DensePose/doc/TOOL_APPLY_NET.md
create mode 100644 projects/DensePose/doc/TOOL_QUERY_DB.md
create mode 100644 projects/DensePose/doc/images/res_bbox_dp_contour.jpg
create mode 100644 projects/DensePose/doc/images/res_bbox_dp_segm.jpg
create mode 100644 projects/DensePose/doc/images/res_bbox_dp_u.jpg
create mode 100644 projects/DensePose/doc/images/res_bbox_dp_v.jpg
create mode 100644 projects/DensePose/doc/images/vis_bbox_dp_i.jpg
create mode 100644 projects/DensePose/doc/images/vis_bbox_dp_pts.jpg
create mode 100644 projects/DensePose/doc/images/vis_bbox_dp_segm.jpg
create mode 100644 projects/DensePose/doc/images/vis_bbox_dp_u.jpg
create mode 100644 projects/DensePose/doc/images/vis_bbox_dp_v.jpg
create mode 100644 projects/DensePose/tests/common.py
create mode 100644 projects/DensePose/tests/test_combine_data_loader.py
create mode 100644 projects/DensePose/tests/test_frame_selector.py
create mode 100644 projects/DensePose/tests/test_image_resize_transform.py
create mode 100644 projects/DensePose/tests/test_model_e2e.py
create mode 100644 projects/DensePose/tests/test_setup.py
create mode 100644 projects/DensePose/tests/test_structures.py
create mode 100644 projects/DensePose/tests/test_video_keyframe_dataset.py
diff --git a/projects/DensePose/dev/README.md b/projects/DensePose/dev/README.md
new file mode 100644
index 0000000..e3a94b6
--- /dev/null
+++ b/projects/DensePose/dev/README.md
@@ -0,0 +1,7 @@
+
+## Some scripts for developers to use, include:
+
+- `run_instant_tests.sh`: run training for a few iterations.
+- `run_inference_tests.sh`: run inference on a small dataset.
+- `../../dev/linter.sh`: lint the codebase before commit
+- `../../dev/parse_results.sh`: parse results from log file.
diff --git a/projects/DensePose/dev/run_inference_tests.sh b/projects/DensePose/dev/run_inference_tests.sh
new file mode 100644
index 0000000..34f47d5
--- /dev/null
+++ b/projects/DensePose/dev/run_inference_tests.sh
@@ -0,0 +1,33 @@
+#!/bin/bash -e
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
+
+BIN="python train_net.py"
+OUTPUT="inference_test_output"
+NUM_GPUS=2
+IMS_PER_GPU=2
+IMS_PER_BATCH=$(( NUM_GPUS * IMS_PER_GPU ))
+
+CFG_LIST=( "${@:1}" )
+
+if [ ${#CFG_LIST[@]} -eq 0 ]; then
+ CFG_LIST=( ./configs/quick_schedules/*inference_acc_test.yaml )
+fi
+
+echo "========================================================================"
+echo "Configs to run:"
+echo "${CFG_LIST[@]}"
+echo "========================================================================"
+
+for cfg in "${CFG_LIST[@]}"; do
+ echo "========================================================================"
+ echo "Running $cfg ..."
+ echo "========================================================================"
+ $BIN \
+ --eval-only \
+ --num-gpus $NUM_GPUS \
+ --config-file "$cfg" \
+ OUTPUT_DIR "$OUTPUT" \
+ SOLVER.IMS_PER_BATCH $IMS_PER_BATCH
+ rm -rf $OUTPUT
+done
+
diff --git a/projects/DensePose/dev/run_instant_tests.sh b/projects/DensePose/dev/run_instant_tests.sh
new file mode 100644
index 0000000..a537851
--- /dev/null
+++ b/projects/DensePose/dev/run_instant_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash -e
+# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
+
+BIN="python train_net.py"
+OUTPUT="instant_test_output"
+NUM_GPUS=2
+SOLVER_IMS_PER_BATCH=$((NUM_GPUS * 2))
+
+CFG_LIST=( "${@:1}" )
+if [ ${#CFG_LIST[@]} -eq 0 ]; then
+ CFG_LIST=( ./configs/quick_schedules/*instant_test.yaml )
+fi
+
+echo "========================================================================"
+echo "Configs to run:"
+echo "${CFG_LIST[@]}"
+echo "========================================================================"
+
+for cfg in "${CFG_LIST[@]}"; do
+ echo "========================================================================"
+ echo "Running $cfg ..."
+ echo "========================================================================"
+ $BIN --num-gpus $NUM_GPUS --config-file "$cfg" \
+ SOLVER.IMS_PER_BATCH $SOLVER_IMS_PER_BATCH \
+ OUTPUT_DIR "$OUTPUT"
+ rm -rf "$OUTPUT"
+done
+
diff --git a/projects/DensePose/doc/GETTING_STARTED.md b/projects/DensePose/doc/GETTING_STARTED.md
new file mode 100644
index 0000000..a6bcbed
--- /dev/null
+++ b/projects/DensePose/doc/GETTING_STARTED.md
@@ -0,0 +1,58 @@
+# Getting Started with DensePose
+
+## Inference with Pre-trained Models
+
+1. Pick a model and its config file from [Model Zoo](MODEL_ZOO.md), for example [densepose_rcnn_R_50_FPN_s1x.yaml](../configs/densepose_rcnn_R_50_FPN_s1x.yaml)
+2. Run the [Apply Net](TOOL_APPLY_NET.md) tool to visualize the results or save the to disk. For example, to use contour visualization for DensePose, one can run:
+```bash
+python apply_net.py show configs/densepose_rcnn_R_50_FPN_s1x.yaml densepose_rcnn_R_50_FPN_s1x.pkl image.jpg dp_contour,bbox --output image_densepose_contour.png
+```
+Please see [Apply Net](TOOL_APPLY_NET.md) for more details on the tool.
+
+## Training
+
+First, prepare the [dataset](http://densepose.org/#dataset) into the following structure under the directory you'll run training scripts:
+
+datasets/coco/
+ annotations/
+ densepose_{train,minival,valminusminival}2014.json
+ densepose_minival2014_100.json (optional, for testing only)
+ {train,val}2014/
+ # image files that are mentioned in the corresponding json
+
+
+To train a model one can use the [train_net.py](../train_net.py) script.
+This script was used to train all DensePose models in [Model Zoo](MODEL_ZOO.md).
+For example, to launch end-to-end DensePose-RCNN training with ResNet-50 FPN backbone
+on 8 GPUs following the s1x schedule, one can run
+```bash
+python train_net.py --config-file configs/densepose_rcnn_R_50_FPN_s1x.yaml --num-gpus 8
+```
+The configs are made for 8-GPU training. To train on 1 GPU, one can apply the
+[linear learning rate scaling rule](https://arxiv.org/abs/1706.02677):
+```bash
+python train_net.py --config-file configs/densepose_rcnn_R_50_FPN_s1x.yaml \
+ SOLVER.IMS_PER_BATCH 2 SOLVER.BASE_LR 0.0025
+```
+
+## Evaluation
+
+Model testing can be done in the same way as training, except for an additional flag `--eval-only` and
+model location specification through `MODEL.WEIGHTS model.pth` in the command line
+```bash
+python train_net.py --config-file configs/densepose_rcnn_R_50_FPN_s1x.yaml \
+ --eval-only MODEL.WEIGHTS model.pth
+```
+
+## Tools
+
+We provide tools which allow one to:
+ - easily view DensePose annotated data in a dataset;
+ - perform DensePose inference on a set of images;
+ - visualize DensePose model results;
+
+`query_db` is a tool to print or visualize DensePose data in a dataset.
+Please refer to [Query DB](TOOL_QUERY_DB.md) for more details on this tool
+
+`apply_net` is a tool to print or visualize DensePose results.
+Please refer to [Apply Net](TOOL_APPLY_NET.md) for more details on this tool
diff --git a/projects/DensePose/doc/MODEL_ZOO.md b/projects/DensePose/doc/MODEL_ZOO.md
new file mode 100644
index 0000000..c263084
--- /dev/null
+++ b/projects/DensePose/doc/MODEL_ZOO.md
@@ -0,0 +1,277 @@
+# Model Zoo and Baselines
+
+# Introduction
+
+We provide baselines trained with Detectron2 DensePose. The corresponding
+configuration files can be found in the [configs](../configs) directory.
+All models were trained on COCO `train2014` + `valminusminival2014` and
+evaluated on COCO `minival2014`. For the details on common settings in which
+baselines were trained, please check [Detectron 2 Model Zoo](../../../MODEL_ZOO.md).
+
+## License
+
+All models available for download through this document are licensed under the
+[Creative Commons Attribution-ShareAlike 3.0 license](https://creativecommons.org/licenses/by-sa/3.0/)
+
+## COCO DensePose Baselines with DensePose-RCNN
+
+### Legacy Models
+
+Baselines trained using schedules from [Güler et al, 2018](https://arxiv.org/pdf/1802.00434.pdf)
+
+
+
+### Improved Baselines, Original Fully Convolutional Haad
+
+These models use an improved training schedule and Panoptic FPN head from [Kirillov et al, 2019](https://arxiv.org/abs/1901.02446).
+
+
+
+### Improved Baselines, DeepLabV3 Head
+
+These models use an improved training schedule, Panoptic FPN head from [Kirillov et al, 2019](https://arxiv.org/abs/1901.02446) and DeepLabV3 head from [Chen et al, 2017](https://arxiv.org/abs/1706.05587).
+
+
+
+### Baselines with Confidence Estimation
+
+These models perform additional estimation of confidence in regressed UV coodrinates, along the lines of [Neverova et al., 2019](https://papers.nips.cc/paper/8378-correlated-uncertainty-for-learning-dense-correspondences-from-noisy-labels).
+
+
+
+## Old Baselines
+
+It is still possible to use some baselines from [DensePose 1](https://github.com/facebookresearch/DensePose).
+Below are evaluation metrics for the baselines recomputed in the current framework:
+
+| Model | bbox AP | AP | AP50 | AP75 | APm |APl |
+|-----|-----|-----|--- |--- |--- |--- |
+| [`ResNet50_FPN_s1x-e2e`](https://dl.fbaipublicfiles.com/densepose/DensePose_ResNet50_FPN_s1x-e2e.pkl) | 54.673 | 48.894 | 84.963 | 50.717 | 43.132 | 50.433 |
+| [`ResNet101_FPN_s1x-e2e`](https://dl.fbaipublicfiles.com/densepose/DensePose_ResNet101_FPN_s1x-e2e.pkl) | 56.032 | 51.088 | 86.250 | 55.057 | 46.542 | 52.563 |
+
+Note: these scores are close, but not strictly equal to the ones reported in the [DensePose 1 Model Zoo](https://github.com/facebookresearch/DensePose/blob/master/MODEL_ZOO.md),
+which is due to small incompatibilities between the frameworks.
diff --git a/projects/DensePose/doc/TOOL_APPLY_NET.md b/projects/DensePose/doc/TOOL_APPLY_NET.md
new file mode 100644
index 0000000..f62bdbc
--- /dev/null
+++ b/projects/DensePose/doc/TOOL_APPLY_NET.md
@@ -0,0 +1,131 @@
+# Apply Net
+
+`apply_net` is a tool to print or visualize DensePose results on a set of images.
+It has two modes: `dump` to save DensePose model results to a pickle file
+and `show` to visualize them on images.
+
+## Dump Mode
+
+The general command form is:
+```bash
+python apply_net.py dump [-h] [-v] [--output ]
+```
+
+There are three mandatory arguments:
+ - ``, configuration file for a given model;
+ - ``, model file with trained parameters
+ - ``, input image file name, pattern or folder
+
+One can additionally provide `--output` argument to define the output file name,
+which defaults to `output.pkl`.
+
+
+Examples:
+
+1. Dump results of a DensePose model with ResNet-50 FPN backbone for images
+ in a folder `images` to file `dump.pkl`:
+```bash
+python apply_net.py dump configs/densepose_rcnn_R_50_FPN_s1x.yaml DensePose_ResNet50_FPN_s1x-e2e.pkl images --output dump.pkl -v
+```
+
+2. Dump results of a DensePose model with ResNet-50 FPN backbone for images
+ with file name matching a pattern `image*.jpg` to file `results.pkl`:
+```bash
+python apply_net.py dump configs/densepose_rcnn_R_50_FPN_s1x.yaml DensePose_ResNet50_FPN_s1x-e2e.pkl "image*.jpg" --output results.pkl -v
+```
+
+If you want to load the pickle file generated by the above command:
+```
+# make sure DensePose is in your PYTHONPATH, or use the following line to add it:
+sys.path.append("/your_detectron2_path/detectron2_repo/projects/DensePose/")
+
+f = open('/your_result_path/results.pkl', 'rb')
+data = pickle.load(f)
+```
+
+The file `results.pkl` contains the list of results per image, for each image the result is a dictionary:
+```
+data: [{'file_name': '/your_path/image1.jpg',
+ 'scores': tensor([0.9884]),
+ 'pred_boxes_XYXY': tensor([[ 69.6114, 0.0000, 706.9797, 706.0000]]),
+ 'pred_densepose': },
+ {'file_name': '/your_path/image2.jpg',
+ 'scores': tensor([0.9999, 0.5373, 0.3991]),
+ 'pred_boxes_XYXY': tensor([[ 59.5734, 7.7535, 579.9311, 932.3619],
+ [612.9418, 686.1254, 612.9999, 704.6053],
+ [164.5081, 407.4034, 598.3944, 920.4266]]),
+ 'pred_densepose': }]
+```
+
+We can use the following code, to parse the outputs of the first
+detected instance on the first image.
+```
+from densepose.data.structures import DensePoseResult
+img_id, instance_id = 0, 0 # Look at the first image and the first detected instance
+bbox_xyxy = data[img_id]['pred_boxes_XYXY'][instance_id]
+result_encoded = data[img_id]['pred_densepose'].results[instance_id]
+iuv_arr = DensePoseResult.decode_png_data(*result_encoded)
+```
+The array `bbox_xyxy` contains (x0, y0, x1, y1) of the bounding box.
+
+The shape of `iuv_arr` is `[3, H, W]`, where (H, W) is the shape of the bounding box.
+- `iuv_arr[0,:,:]`: The patch index of image points, indicating which of the 24 surface patches the point is on.
+- `iuv_arr[1,:,:]`: The U-coordinate value of image points.
+- `iuv_arr[2,:,:]`: The V-coordinate value of image points.
+
+
+## Visualization Mode
+
+The general command form is:
+```bash
+python apply_net.py show [-h] [-v] [--min_score ] [--nms_thresh ] [--output ]
+```
+
+There are four mandatory arguments:
+ - ``, configuration file for a given model;
+ - ``, model file with trained parameters
+ - ``, input image file name, pattern or folder
+ - ``, visualizations specifier; currently available visualizations are:
+ * `bbox` - bounding boxes of detected persons;
+ * `dp_segm` - segmentation masks for detected persons;
+ * `dp_u` - each body part is colored according to the estimated values of the
+ U coordinate in part parameterization;
+ * `dp_v` - each body part is colored according to the estimated values of the
+ V coordinate in part parameterization;
+ * `dp_contour` - plots contours with color-coded U and V coordinates
+
+
+One can additionally provide the following optional arguments:
+ - `--min_score` to only show detections with sufficient scores that are not lower than provided value
+ - `--nms_thresh` to additionally apply non-maximum suppression to detections at a given threshold
+ - `--output` to define visualization file name template, which defaults to `output.png`.
+ To distinguish output file names for different images, the tool appends 1-based entry index,
+ e.g. output.0001.png, output.0002.png, etc...
+
+
+The following examples show how to output results of a DensePose model
+with ResNet-50 FPN backbone using different visualizations for image `image.jpg`:
+
+1. Show bounding box and segmentation:
+```bash
+python apply_net.py show configs/densepose_rcnn_R_50_FPN_s1x.yaml DensePose_ResNet50_FPN_s1x-e2e.pkl image.jpg bbox,dp_segm -v
+```
+
+
+2. Show bounding box and estimated U coordinates for body parts:
+```bash
+python apply_net.py show configs/densepose_rcnn_R_50_FPN_s1x.yaml DensePose_ResNet50_FPN_s1x-e2e.pkl image.jpg bbox,dp_u -v
+```
+
+
+3. Show bounding box and estimated V coordinates for body parts:
+```bash
+python apply_net.py show configs/densepose_rcnn_R_50_FPN_s1x.yaml DensePose_ResNet50_FPN_s1x-e2e.pkl image.jpg bbox,dp_v -v
+```
+
+
+4. Show bounding box and estimated U and V coordinates via contour plots:
+```bash
+python apply_net.py show configs/densepose_rcnn_R_50_FPN_s1x.yaml DensePose_ResNet50_FPN_s1x-e2e.pkl image.jpg dp_contour,bbox -v
+```
+
diff --git a/projects/DensePose/doc/TOOL_QUERY_DB.md b/projects/DensePose/doc/TOOL_QUERY_DB.md
new file mode 100644
index 0000000..b0a764b
--- /dev/null
+++ b/projects/DensePose/doc/TOOL_QUERY_DB.md
@@ -0,0 +1,105 @@
+
+# Query Dataset
+
+`query_db` is a tool to print or visualize DensePose data from a dataset.
+It has two modes: `print` and `show` to output dataset entries to standard
+output or to visualize them on images.
+
+## Print Mode
+
+The general command form is:
+```bash
+python query_db.py print [-h] [-v] [--max-entries N]
+```
+
+There are two mandatory arguments:
+ - ``, DensePose dataset specification, from which to select
+ the entries (e.g. `densepose_coco_2014_train`).
+ - ``, dataset entry selector which can be a single specification,
+ or a comma-separated list of specifications of the form
+ `field[:type]=value` for exact match with the value
+ or `field[:type]=min-max` for a range of values
+
+One can additionally limit the maximum number of entries to output
+by providing `--max-entries` argument.
+
+Examples:
+
+1. Output at most 10 first entries from the `densepose_coco_2014_train` dataset:
+```bash
+python query_db.py print densepose_coco_2014_train \* --max-entries 10 -v
+```
+
+2. Output all entries with `file_name` equal to `COCO_train2014_000000000036.jpg`:
+```bash
+python query_db.py print densepose_coco_2014_train file_name=COCO_train2014_000000000036.jpg -v
+```
+
+3. Output all entries with `image_id` between 36 and 156:
+```bash
+python query_db.py print densepose_coco_2014_train image_id:int=36-156 -v
+```
+
+## Visualization Mode
+
+The general command form is:
+```bash
+python query_db.py show [-h] [-v] [--max-entries N] [--output ]
+```
+
+There are three mandatory arguments:
+ - ``, DensePose dataset specification, from which to select
+ the entries (e.g. `densepose_coco_2014_train`).
+ - ``, dataset entry selector which can be a single specification,
+ or a comma-separated list of specifications of the form
+ `field[:type]=value` for exact match with the value
+ or `field[:type]=min-max` for a range of values
+ - ``, visualizations specifier; currently available visualizations are:
+ * `bbox` - bounding boxes of annotated persons;
+ * `dp_i` - annotated points colored according to the containing part;
+ * `dp_pts` - annotated points in green color;
+ * `dp_segm` - segmentation masks for annotated persons;
+ * `dp_u` - annotated points colored according to their U coordinate in part parameterization;
+ * `dp_v` - annotated points colored according to their V coordinate in part parameterization;
+
+One can additionally provide one of the two optional arguments:
+ - `--max_entries` to limit the maximum number of entries to visualize
+ - `--output` to provide visualization file name template, which defaults
+ to `output.png`. To distinguish file names for different dataset
+ entries, the tool appends 1-based entry index to the output file name,
+ e.g. output.0001.png, output.0002.png, etc.
+
+The following examples show how to output different visualizations for image with `id = 322`
+from `densepose_coco_2014_train` dataset:
+
+1. Show bounding box and segmentation:
+```bash
+python query_db.py show densepose_coco_2014_train image_id:int=322 bbox,dp_segm -v
+```
+
+
+2. Show bounding box and points colored according to the containing part:
+```bash
+python query_db.py show densepose_coco_2014_train image_id:int=322 bbox,dp_i -v
+```
+
+
+3. Show bounding box and annotated points in green color:
+```bash
+python query_db.py show densepose_coco_2014_train image_id:int=322 bbox,dp_segm -v
+```
+
+
+4. Show bounding box and annotated points colored according to their U coordinate in part parameterization:
+```bash
+python query_db.py show densepose_coco_2014_train image_id:int=322 bbox,dp_u -v
+```
+
+
+5. Show bounding box and annotated points colored according to their V coordinate in part parameterization:
+```bash
+python query_db.py show densepose_coco_2014_train image_id:int=322 bbox,dp_v -v
+```
+
+
+
diff --git a/projects/DensePose/doc/images/res_bbox_dp_contour.jpg b/projects/DensePose/doc/images/res_bbox_dp_contour.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8f0c195c237d8ca70e16f5827b8a3b6e456844a4
GIT binary patch
literal 91492
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