Skip to content

Commit

Permalink
Merge pull request #1 from Alexandre-Delplanque/feature
Browse files Browse the repository at this point in the history
Feature
  • Loading branch information
Alexandre-Delplanque authored Mar 29, 2023
2 parents deec190 + ff94a5e commit 1115dfd
Show file tree
Hide file tree
Showing 60 changed files with 661 additions and 406 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# [v0.1.0](https://github.com/Alexandre-Delplanque/HerdNet/releases/tag/v0.1.0) (January 23, 2023)
Initial version of the code, used for producing the results of the reference paper "[From Crowd to Herd Counting: How to Precisely Detect and Count African Mammals using Aerial Imagery and Deep Learning?](https://doi.org/10.1016/j.isprsjprs.2023.01.025)".

## Commits
Alexandre-Delplanque (11):
- [f6586a1](https://github.com/Alexandre-Delplanque/HerdNet/commit/f6586a1bf846cf6ac66762ad84091e3476e1e435) - Add LICENSE
- [9164bd9](https://github.com/Alexandre-Delplanque/HerdNet/commit/9164bd941245701fcd1e734992d88a8edd4b9568) - Create LICENSE.md
- [e5d5e5c](https://github.com/Alexandre-Delplanque/HerdNet/commit/e5d5e5cc3589153470c4da07c2b21dd9d1415fdc) - Merge branch 'main' of https://github.com/Alexandre-Delplanque/Herd-Net
- [303ca64](https://github.com/Alexandre-Delplanque/HerdNet/commit/303ca64f2ef9fc243ff32b807cb329c36431e03d) - Upgrade infer tool and use tqdm for progress bars
- [ca8e03d](https://github.com/Alexandre-Delplanque/HerdNet/commit/ca8e03d3b0d3795e85329abf4ba7f966d6e26887) - Update Colab notebook link
- [4179b60](https://github.com/Alexandre-Delplanque/HerdNet/commit/4179b600cf9b1ac45ca4a262d0b24c952be62a99) - Add infer.py tool and demo notebook
- [48e2072](https://github.com/Alexandre-Delplanque/HerdNet/commit/48e2072bc75b696d67e7e7bcc5f7915c0ff4fe9f) - Update README.md
- [17f8efc](https://github.com/Alexandre-Delplanque/HerdNet/commit/17f8efc53ec761f9da7636d4562728e00c51072f) - Update environment.yml
- [77c3bbe](https://github.com/Alexandre-Delplanque/HerdNet/commit/77c3bbe6d3d1e17be9229c42c591f8719f0d880a) - Update README.md
- [3423d85](https://github.com/Alexandre-Delplanque/HerdNet/commit/3423d85f80a0f11c6d83d40ebe3ac9bf262d488b) - initial code commit
- [d176d9f](https://github.com/Alexandre-Delplanque/HerdNet/commit/d176d9fcc721c97888550a36b542a5bbb72f0fba) - Initial commit
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ You can also create your own config file. Save it first into the [`configs/train
```console
python tools/train.py train=<your config name>
```
Click [here](https://github.com/Alexandre-Delplanque/HerdNet/blob/main/TRAINING_CONFIG.md) to see the description of the **training config file**.
Click [here](https://github.com/Alexandre-Delplanque/HerdNet/tree/main/doc/configs_train.md) to see how to write a **training config file**.

You can also make multiple different configurations runs or modify some parameters directly from the command line (see the [doc](https://hydra.cc/docs/intro)).

Expand All @@ -254,7 +254,7 @@ You can also create your own config file. Save it first into the [`configs/test`
```console
python tools/test.py test=<your config name>
```
Click [here](https://github.com/Alexandre-Delplanque/HerdNet/blob/main/TESTING_CONFIG.md) to see the description of the **testing config file**.
Click [here](https://github.com/Alexandre-Delplanque/HerdNet/tree/main/doc/configs_test.md) to see how to write a **testing config file**.

### Visualizing Ground Truth (and Detections)
You can view your ground truth and your model's detections by using the `view.py` tool. This tool uses [FiftyOne](https://voxel51.com/fiftyone/). You simply need to specify a root directory that contains your images (`root`), your CSV file containing the ground truth (`gt`) and optionaly a CSV file containing model's detections (`-dets`). See dataset format below for your CSV files format.
Expand Down Expand Up @@ -286,4 +286,7 @@ torch.save(pth_file, 'path/to/the/file.pth')

## Colab Demo
Here is a [Google Colab demo](https://colab.research.google.com/github/Alexandre-Delplanque/HerdNet/blob/main/notebooks/demo-training-testing-herdnet.ipynb) based on the UAV nadir dataset used in the paper:
> *Delplanque, A., Foucher, S., Lejeune, P., Linchant, J. and Théau, J. (2022), Multispecies detection and identification of African mammals in aerial imagery using convolutional neural networks. Remote Sens Ecol Conserv, 8: 166-179. https://doi.org/10.1002/rse2.234*.
> *Delplanque, A., Foucher, S., Lejeune, P., Linchant, J. and Théau, J. (2022), Multispecies detection and identification of African mammals in aerial imagery using convolutional neural networks. Remote Sens Ecol Conserv, 8: 166-179. https://doi.org/10.1002/rse2.234*.
## Code Versioning
The code used in the paper is the one corresponding to the tag [`v0.1.0`](https://github.com/Alexandre-Delplanque/HerdNet/releases/tag/v0.1.0). The 'main' branch contains the latest stable version with fixed bugs and new features, it is recommended to use this branch for your development. The file [CHANGELOG.md](https://github.com/Alexandre-Delplanque/HerdNet/tree/main/CHANGELOG.md) contains the details of the commits for each version of the code.
4 changes: 2 additions & 2 deletions animaloc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


from animaloc import data
Expand Down
7 changes: 4 additions & 3 deletions animaloc/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"

from .annotations import *
from .patches import *
from .processors import *
from .transforms import *
from .types import *
from .utils import *
from .batch_utils import *
from .batch_utils import *
from .samplers import *
4 changes: 2 additions & 2 deletions animaloc/data/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


import pandas
Expand Down
4 changes: 2 additions & 2 deletions animaloc/data/batch_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


from torchvision.utils import make_grid
Expand Down
4 changes: 2 additions & 2 deletions animaloc/data/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


import os
Expand Down
4 changes: 2 additions & 2 deletions animaloc/data/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


from typing import Union
Expand Down
104 changes: 104 additions & 0 deletions animaloc/data/samplers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
__copyright__ = \
"""
Copyright (C) 2022 University of Liège, Gembloux Agro-Bio Tech, Forest Is Life
All rights reserved.
This source code is under the CC BY-NC-SA-4.0 license (https://creativecommons.org/licenses/by-nc-sa/4.0/).
It is to be used for academic research purposes only, no commercial use is permitted.
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.2.0"

import torch

from torch.utils.data import Sampler
from typing import Iterable, Iterator

from ..datasets import CSVDataset
from ..data.utils import group_by_image

from ..utils.registry import Registry

SAMPLERS = Registry('samplers', module_key='animaloc.data.samplers')

__all__ = ['SAMPLERS', *SAMPLERS.registry_names]

@SAMPLERS.register()
class BinaryBatchSampler(Sampler):
''' Samples elements from two image-level categories (C0 and C1) and returns batches
consisting of the same number of elements for each domain.
The batch size must be even and the csv file on which the dataset has been
built must contain a column defining the two categories, i.e. C0 (0) and C1 (1).
'''

def __init__(
self,
dataset: CSVDataset,
col: str,
batch_size: int = 2,
shuffle: bool = False,
*args, **kwargs
) -> None:
'''
Args:
dataset (CSVDataset): dataset from which to sample data. Must be a CSVDataset.
col (str): dataset's DataFrame column defining categories C0 and C1.
batch_size (int, optional): how many samples per batch to load. Defaults to 2.
shuffle (bool, optional): set to True to have the data reshuffled at every epoch.
Defaults to False.
'''
super().__init__(dataset)

if not isinstance(dataset, CSVDataset):
raise TypeError(
f"dataset should be an instance of 'CSVDataset' class, but got '{type(dataset)}'"
)

if batch_size % 2 != 0:
raise ValueError(f"batch size should be even, but got {batch_size}")

self.dataset = dataset
self.batch_size = batch_size
self.shuffle = shuffle

df = self.dataset.data.copy()
df = group_by_image(df)
self.col = col
if self.col not in df.columns:
raise ValueError(f"'{col}' column is missing from the csv file")

self.n = self.batch_size // 2
self.c0_idx = df.loc[df[col]==0].index.values.tolist()
self.c1_idx = df.loc[df[col]==1].index.values.tolist()

c0_idx, c1_idx = self._grouped(self.c0_idx, n=self.n), self._grouped(self.c1_idx, n=self.n)
self.batch_idx = [[*c0, *c1] for c0, c1 in zip(c0_idx, c1_idx)]

def __iter__(self) -> Iterator:

if self.shuffle:
seed = int(torch.empty((), dtype=torch.int64).random_().item())
generator = torch.Generator()
generator.manual_seed(seed)

c0_idx = [self.c0_idx[i] for i in torch.randperm(len(self.c0_idx), generator=generator)]
c1_idx = [self.c1_idx[i] for i in torch.randperm(len(self.c1_idx), generator=generator)]
c0_idx, c1_idx = self._grouped(c0_idx, n=self.n), self._grouped(c1_idx, n=self.n)
batch_idx = [[*c0, *c1] for c0, c1 in zip(c0_idx, c1_idx)]

yield from batch_idx

else:
yield from self.batch_idx

def __len__(self) -> int:
return len(self.batch_idx)

def _grouped(self, iterable: Iterable, n: int) -> Iterable:
return zip(*[iter(iterable)]*n)
59 changes: 28 additions & 31 deletions animaloc/data/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,18 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


import PIL
import numpy
import torch
import torchvision
import scipy
import random
import warnings
import albumentations

from typing import Dict, Optional, Union, Tuple, List

Expand Down Expand Up @@ -205,7 +202,8 @@ def __init__(
num_classes: int = 2,
onehot: bool = False,
squeeze: bool = True,
down_ratio: Optional[int] = None
down_ratio: Optional[int] = None,
target_type: str = 'long'
) -> None:
'''
Args:
Expand All @@ -222,13 +220,18 @@ def __init__(
down_ratio (int, optional): if specified, the target will be downsampled
according to the ratio.
Defaults to None
target_type (str, optional): output data type of target. Defaults to 'long'.
'''

assert target_type in ['long', 'float'], \
f"target type must be either 'long' or 'float', got {target_type}"

self.radius = radius
self.num_classes = num_classes - 1
self.onehot = onehot
self.squeeze = squeeze
self.down_ratio = down_ratio
self.target_type = target_type

def __call__(
self,
Expand Down Expand Up @@ -258,36 +261,30 @@ def __call__(
image, target.copy()
)

if self.onehot:
mask = self._onehot(target)

else:
mask = torch.zeros((1, self.img_height, self.img_width)).long()

# fill the mask
if len(target['points']) > 0:
for point, label in zip(target['points'], target['labels']):
x, y = point[0], point[1]
point_buffer = _point_buffer(x, y, mask[0], self.radius)
mask[0, point_buffer] = label

if self.squeeze:
mask = mask.squeeze(0)

return image, mask

def _onehot(self, target: torch.Tensor):

masks = torch.zeros((self.num_classes, self.img_height, self.img_width)).long()
mask = torch.zeros((1, self.img_height, self.img_width)).long()

# fill the mask
if len(target['points']) > 0:

for point, label in zip(target['points'], target['labels']):
x, y = point[0], point[1]
point_buffer = _point_buffer(x, y, masks[label-1], self.radius)
masks[label-1, point_buffer] = 1
point_buffer = _point_buffer(x, y, mask[0], self.radius)
mask[0, point_buffer] = label

if self.onehot:
mask = self._onehot(mask)

if self.squeeze:
mask = mask.squeeze(0)

if self.target_type == 'float':
mask = mask.float()

return masks
return image, mask

def _onehot(self, mask: torch.Tensor):
onehot_mask = torch.nn.functional.one_hot(mask, self.num_classes+1)
onehot_mask = torch.movedim(onehot_mask, -1, -3)
return onehot_mask

@TRANSFORMS.register()
class FIDT:
Expand Down
5 changes: 2 additions & 3 deletions animaloc/data/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"

__version__ = "0.2.0"

from typing import Union, Tuple

Expand Down
4 changes: 2 additions & 2 deletions animaloc/data/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


import pandas
Expand Down
4 changes: 2 additions & 2 deletions animaloc/datasets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
Please contact the author Alexandre Delplanque ([email protected]) for any questions.
Last modification: November 23, 2022
Last modification: March 29, 2023
"""
__author__ = "Alexandre Delplanque"
__license__ = "CC BY-NC-SA 4.0"
__version__ = "0.1.0"
__version__ = "0.2.0"


from .register import DATASETS
Expand Down
Loading

0 comments on commit 1115dfd

Please sign in to comment.