Skip to content

Commit

Permalink
Merge pull request #11 from acnazarejr/readme
Browse files Browse the repository at this point in the history
README finished
  • Loading branch information
acnazarejr authored May 15, 2020
2 parents 1e9548e + 953c46b commit 6615fe1
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 32 deletions.
100 changes: 71 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/acnazarejr/fdet)](https://github.com/acnazarejr/fdet/releases)
[![GitHub](https://img.shields.io/github/license/acnazarejr/fdet)](https://github.com/acnazarejr/fdet/blob/master/LICENSE)

The `fdet` is a ready-to-use implementation of deep learning face detectors using PyTorch.
The `fdet` is a ready-to-use implementation of deep learning face detectors with landkmarks.

![Example](https://github.com/acnazarejr/fdet/raw/master/assets/example.jpg)

Expand All @@ -19,7 +19,8 @@ You can use it directly in your code, as a [python library](#python-library-usag
>>> from fdet import io, RetinaFace

>>> detector = RetinaFace(backbone='RESNET50')
>>> detector.detect(io.read_as_rgb('path_to_image.jpg'))
>>> image = io.read_as_rgb('path_to_image.jpg')
>>> detector.detect(image)
[{'box': [511, 47, 35, 45], 'confidence': 0.9999996423721313,
'keypoints': {'left_eye': [517, 70], 'right_eye': [530, 65], 'nose': [520, 77],
'mouth_left': [522, 87], 'mouth_right': [531, 83]}}]
Expand All @@ -28,7 +29,7 @@ You can use it directly in your code, as a [python library](#python-library-usag
Or through [command-line](#command-line-usage) application:

```bash
fdet retinaface -b RESNET50 -i path_to_image.jpg -o detections.json
fdet retinaface -b RESNET50 -i path_to_image.jpg -o detections.json --gpu 1
```

## **Features**
Expand All @@ -44,7 +45,7 @@ Despite the availability of different implementations of these algorithms, there

- :star: Real-time face detection;
- :star: Support for batch detection (useful for fast detection in multiple images and videos);
- :star: Ease of use through python library or command-line app;
- :star: Ease of use through python library or command-line tool;
- :star: Provide a unified interface to assign 'CPU' or 'GPU' devices;
- :star: Multiple GPU's support;
- :star: Automatic on-demand model weights download;
Expand All @@ -60,6 +61,42 @@ Despite the availability of different implementations of these algorithms, there
pip install fdet
```

## **Command-line Usage**

Simply and fast usage through command-line tool.

The **`fdet`** command-line tool has two sub-commands, on for each available detector: **`fdet mtcnn`** and **`fdet retinaface`**.

![Terminal](https://github.com/acnazarejr/fdet/raw/master/assets/terminal.gif)

### **Options**

For a detailed list of available options type: **`fdet mtcnn --help`** or **`fdet retinaface --help`**, according to the desired detector.

#### Data Input

> This options are mutually exclusive
- `-i, --image FILE`: Image to detect. You can specify multiple images (`-i img1.jpg -i img2.jpg`)
- `-v, --video FILE`: Video file to detect. Only one video can be specified at a time.
- `-l, --list FILE`: Text file containing a list of images (absolute paths) to detect.
- `-d, --dir DIRECTORY`: The path of a directory containing images to detect. Ignores files that are not images.

#### Data Output

- `-o, --output FILE`: Path to the output json file containing the detections.
- `-s, --save-frimes DIRECTORY` *(Optional)*: If specified, folder to save the output images with the detected faces drawn. Be careful when using this option with video input, as it will save all frames of the video.
- `p, --print` *(Optional)*: If specified,, print the detections to the console screen.
- `-q, --quiet` *(Optional)*: Do not display progress bar or any results.

#### Execution

- `--no-cuda`: Disables the CUDA utilization. When CUDA is not supported, it is automatically disabled.
- `-g, --GPU INT` *(Optional)*: When CUDA is supported, specifies which GPU to use. If not set, all available GPUs will be used.
- `-bs, --batch-size INT` *(Optional)*: The size of the detection batch (providing considerable speed-up) [default: 1]. **This option only works for multiple images when they are the same size**.

> Defining the batch size is a complex task because it depends on the available memory in the system. We recommend performing small preliminary tests to find a suitable value.
## **Python Library Usage**

If you want to use `fdet` from python, just import it,
Expand All @@ -85,45 +122,54 @@ and instantiate your desired detector, with its respective parameters:
- `cuda_enable` (bool, optional): Indicates wheter CUDA, if available, should be used or not. If False, uses only CPU processing. [default: True].
- `cuda_devices` (list, optional): List of CUDA GPUs to be used. If None, uses all avaliable GPUs. [default: None]. If `cuda_enable` is False, this parameter is ignored.

The detector classes listed above have two methods to perform the face detection:
To perform detection you can simply use the following methods provided by the classes:

**`detect(image: np.ndarray)`**: Single-image detection ([example](#singe-image-detection-example)).

**`batch_detect(image: np.ndarray)`**: Performs face detection on image batches, typically providing considerable speed-up ([example](#batch-detection-example)).

For each processed image, the detector returns a list of `dict` objects, which in turn represent the detected faces. The `dict` contains three main keys, described below.

```python
[
{'box': [511, 47, 35, 45], 'confidence': 0.9999996423721313,
'keypoints': {'left_eye': [517, 70], 'right_eye': [530, 65], 'nose': [520, 77],
'mouth_left': [522, 87], 'mouth_right': [531, 83]}}
]
```

- `'box'`: The bounding box formatted as a list `[x, y, width, height]`;
- `'confidence'`: The probability for a bounding box to be matching a face;
- `'keypoints'`: The five landmarks formatted into a `dict` with the keys `'left_eye'`, `'right_eye'`, `'nose'`, `'mouth_left'`, `'mouth_right'`. Each keypoint is identified by a pixel position `[x, y]`.

> The `batch_detect()` method will return a `list` of `lists` containing the results of all batch images.
### **Singe-Image Detection Example**

The following example illustrates the ease of use of this library to detect faces in a single-image using MTCNN and to create an output image with all detected faces drawn.
This example shows how to detect faces, using a single image, and draw the detections in an output image.

```python
>>> from fdet import io, MTCNN
>>>
>>> detector = MTCNN()
>>> image = io.read_as_rgb('example.jpg')
>>>
>>> image = io.read_as_rgb('example.jpg')
>>> detections = detector.detect(image)
>>> print(detections)
[{'box': [511, 47, 35, 45], 'confidence': 0.9999996423721313,
'keypoints': {'left_eye': [517, 70], 'right_eye': [530, 65], 'nose': [520, 77],
'mouth_left': [522, 87], 'mouth_right': [531, 83]}}]
>>>
>>> output_image = io.draw_detections(image, detections, color='white', thickness=5)
>>> io.save('output.jpg', output_image)
```

The detector returns a list of `dict` objects. Each `dict` contains three main keys:

- `'box'`: The bounding box formatted as a list `[x, y, width, height]`;
- `'confidence'`: The probability for a bounding box to be matching a face;
- `'keypoints'`:
The five landmarks formatted into a `dict` with the keys `'left_eye'`, `'right_eye'`, `'nose'`, `'mouth_left'`, `'mouth_right'`. Each keypoint is identified by a pixel position `[x, y]`.

The `io.read_as_rgb()` is a wrapper for opencv `cv2.imread()` to ensure an RGB image and can be replaced by:

```python
image = cv2.imread('example.jpg', cv2.IMREAD_COLOR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
```
> The `io.read_as_rgb()` is a wrapper for opencv `cv2.imread()` to ensure an RGB image and can be replaced by:
>
> ```python
> image = cv2.imread('example.jpg', cv2.IMREAD_COLOR)
> image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
> ```
### **Batch Detection Example**
The library is also capable of performing face detection on image batches, typically providing considerable speed-up. A batch should be structured as list of images (`numpy` arrays) of equal dimension. The returned detections list will have an additional first dimension corresponding to the batch size. Each image in the batch may have one or more faces detected.
A batch should be structured as list of images (`numpy` arrays) of equal dimension. The returned detections list will have an additional first dimension corresponding to the batch size. Each image in the batch may have one or more faces detected.
In the following example, we detect faces in every frame of a video using batchs of 10 images.
Expand Down Expand Up @@ -158,10 +204,6 @@ In the following example, we detect faces in every frame of a video using batchs
>>> video_face_detections.extend(batch_detections)
```
## **Command-line Usage**

![Terminal](https://github.com/acnazarejr/fdet/raw/master/assets/terminal.gif)

## Credits

The FDet was written heavily inspired by the other available implementations ([see credits](#credits)).
Expand Down
Binary file modified assets/example.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion fdet/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def __process_batch(current_batch: Iterable[Tuple[Hashable, np.ndarray]]) -> Dic
if batch:
detections.update(__process_batch(batch))

if kwargs.get('print'):
if kwargs.get('print') and not kwargs.get('quiet'):
for image_key, image_detections in detections.items():
filename = image_key if isinstance(image_key, str) else 'frame ' + str(image_key)
msg = click.style('Detected faces on {}: '.format(filename),
Expand Down
9 changes: 7 additions & 2 deletions fdet/utils/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,18 @@ def _draw_detection(image: np.ndarray, detection: Dict[str, Any],
color: Union[Color, str, tuple] = Color('red'),
thickness: int = None) -> np.ndarray:
"""draw_detection"""

if thickness is None:
thickness = max(int(min(image.shape[0], image.shape[1])/100), 2)

image = _draw_bbox(image, detection['box'], color=color, thickness=thickness)
image = _draw_points(image, detection['keypoints'].values(), color=color, thickness=thickness)
image = _draw_points(image, detection['keypoints'].values(), color=color,
thickness=thickness + 1)
return image

def draw_detections(image: Union[np.ndarray, str], detections: List[Dict[str, Any]],
color: Union[Color, str, tuple] = Color('red'),
thickness: int = 2) -> np.ndarray:
thickness: int = 3) -> np.ndarray:
"""draw_detections"""
if isinstance(image, str):
image = read_as_rgb(image)
Expand Down

0 comments on commit 6615fe1

Please sign in to comment.