Skip to content

Commit

Permalink
Build and refactor [nbdev] (#12)
Browse files Browse the repository at this point in the history
A refactored version of `pybx` built using `nbdev`.

Added:
- documentation page: [docs](https://thatgeeman.github.io/pybx/), README.md, example walkthrough file
- GH workflow tests

Breaking changes:
- Need `area()` and `valid()` are now properties of BaseBx, so `.area` and `.valid` would suffice
- `utils` methods refactored to `utils` and `ops`
  • Loading branch information
thatgeeman authored Nov 20, 2022
1 parent d1085d2 commit 024e037
Show file tree
Hide file tree
Showing 97 changed files with 22,614 additions and 1,875 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/pytests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: PyBx tests

on:
push:
branches: ["master"]
pull_request:
branches: ["master"]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.7
uses: actions/setup-python@v3
with:
python-version: "3.7"
- name: Install pip
run: |
python -m pip install --upgrade pip
- name: Install test requirements
run: |
pip install pytest flake8 black
- name: Install pybx as editable
run: |
pip install -e .
- name: Lint with black
run: |
black .
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest .
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Byte-compiled / optimized / DLL files
# User added
.idea/
.vscode/
.pytest_cache/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
Expand Down Expand Up @@ -76,6 +80,7 @@ docs/_build/
target/

# Jupyter Notebook
*/.ipynb_checkpoints
.ipynb_checkpoints

# IPython
Expand Down
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
repos:
- repo: https://github.com/fastai/nbdev
rev: 2.3.7
hooks:
- id: nbdev_clean
- id: nbdev_export
5 changes: 5 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include settings.ini
include LICENSE
include CONTRIBUTING.md
include README.md
recursive-exclude * __pycache__
12 changes: 8 additions & 4 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@ verify_ssl = true
name = "pypi"

[packages]
fastcore = ">=1.3.20"
numpy = "==1.21"
fastcore = "==1.5.27"
numpy = ">=1.21.6"
matplotlib = "==3.5"
opencv-python = ">=4.0"

[dev-packages]
[dev-packages]
build = "==0.7"
twine = "==3.7"
ipykernel = "==6.12.0"
pybx = {editable = true, path = "."}
pytest = "==7.1.1"
python-build = "==0.2.13"
nbdev = "==2.3.7"
pre-commit = "*"
flake8 = "*"
black = "*"
pybx = {editable = true, path = "."}

[requires]
python_version = "3.7"
1,620 changes: 1,042 additions & 578 deletions Pipfile.lock

Large diffs are not rendered by default.

175 changes: 136 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,167 @@
# PyBx
[![PyPI version](https://badge.fury.io/py/pybx.svg)](https://badge.fury.io/py/pybx)
[![Open In Collab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/thatgeeman/pybx/blob/master/nbs/pybx_walkthrough.ipynb)

A simple python package to generate anchor boxes for multi-box
object detection models. Calculated anchor boxes are in `pascal_voc` format by default.
[![PyPI
version](https://badge.fury.io/py/pybx.svg)](https://badge.fury.io/py/pybx)
[![Open In
Collab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/thatgeeman/pybx/blob/master/nbs/pybx_walkthrough.ipynb)

A simple python package to generate anchor boxes for multi-box object
detection models.

Calculated anchor boxes are in `pascal_voc` format by default.

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

### Installation
```shell

``` shell
pip install pybx
```

### Usage

To calculate the anchor boxes for a single feature size and
aspect ratio, given the image size:
```python
from pybx import anchor
To calculate the anchor boxes for a single feature size and aspect
ratio, given the image size:

image_sz = (300, 300, 3)
``` python
from pybx import anchor, ops

image_sz = (300, 300)
feature_sz = (10, 10)
asp_ratio = 1/2.

coords, labels = anchor.bx(image_sz, feature_sz, asp_ratio)
```

To calculate anchor boxes for **multiple** feature sizes and
aspect ratios:
```python
100 anchor boxes of `asp_ratio` 0.5 is generated along with [unique
labels](../data/README.md):

``` python
len(coords), len(labels)
```

(100, 100)

The anchor box labels are especially useful, since they are pretty
descriptive:

``` python
coords[-1], labels[-1]
```

([274.3933982822018, 263.7867965644036, 295.6066017177982, 300.0],
'a_10x10_0.5_99')

To calculate anchor boxes for **multiple** feature sizes and aspect
ratios, we use `anchor.bxs` instead:

``` python
feature_szs = [(10, 10), (8, 8)]
asp_ratios = [1., 1/2., 2.]

coords, labels = anchor.bxs(image_sz, feature_szs, asp_ratios)
```
All anchor boxes are returned as `ndarrays` of shape `(N,4)` where N
is the number of boxes; along with a list of
[default labels](data/README.md) for each box.

### Using `MultiBx` methods
Box annotations in any format (`ndarray`, `list`, `json`, `dict`)
can be instantialized as a `MultiBx`, exposing many useful
methods and attributes `MultiBx`.
For example to calculate the area of each box iteratively:
```python
All anchor boxes are returned as `ndarrays` of shape `(N,4)` where N is
the number of boxes.

The box labels are even more important now, since they help you uniquely
identify to which feature map size or aspect ratios they belong to.

``` python
coords[101], labels[101]
```

(array([34.39339828, 0. , 55.60660172, 36.21320344]), 'a_10x10_0.5_1')

``` python
coords[-1], labels[-1]
```

(array([254.73349571, 267.99174785, 300. , 294.50825215]),
'a_8x8_2.0_63')

#### [`MultiBx`](https://thatgeeman.github.io/pybx/basics.html#multibx) methods

Box coordinates (with/without labels) in any format (usually `ndarray`,
`list`, `json`, `dict`) can be instantialized as a
[`MultiBx`](https://thatgeeman.github.io/pybx/basics.html#multibx),
exposing many useful methods and attributes of
[`MultiBx`](https://thatgeeman.github.io/pybx/basics.html#multibx). For
example to calculate the area of each box iteratively:

``` python
from pybx.basics import *
# passing anchor boxes and labels from anchor.bxs()
boxes = mbx(coords, labels)
areas = [b.area() for b in boxes]
print(coords.shape)

boxes = mbx(coords, labels)
type(boxes)
```
Each annotation in the `MultiBx` object `boxes` is a
`BaseBx` with its own set of methods and properties.

`MultiBx` objects can also be "added" which stacks
them vertically to create a new `MultiBx` object:
```python
(492, 4)

pybx.basics.MultiBx

``` python
len(boxes)
```

492

``` python
areas = [b.area for b in boxes]
```

Each annotation in the
[`MultiBx`](https://thatgeeman.github.io/pybx/basics.html#multibx)
object `boxes` is also a
[`BaseBx`](https://thatgeeman.github.io/pybx/basics.html#basebx) with
its own set of methods and properties.

``` python
boxes[-1]
```

BaseBx(coords=[[254.73349570550448, 267.9917478527522, 300.0, 294.5082521472478]], label=['a_8x8_2.0_63'])

``` python
boxes[-1].coords, boxes[-1].label
```

((#1) [[254.73349570550448, 267.9917478527522, 300.0, 294.5082521472478]],
(#1) ['a_8x8_2.0_63'])

[`MultiBx`](https://thatgeeman.github.io/pybx/basics.html#multibx)
objects can also be “added” which stacks them vertically to create a new
[`MultiBx`](https://thatgeeman.github.io/pybx/basics.html#multibx)
object:

``` python
boxes_true = mbx(coords_json) # annotation as json records
len(boxes_true)
```

2

``` python
boxes_anchor = mbx(coords_numpy) # annotation as ndarray
boxes = boxes_true + boxes_anchor
len(boxes_anchor)
```

The `vis` module of `pybx` can be used to visualize these "stacks"
of `MultiBx` objects, raw `ndarray`/`list`/`json` records,
target annotations and model logits.
492

![](data/box-1.png)
``` python
boxes_true
```

MultiBx(coords=[[150, 70, 270, 220], [10, 180, 115, 260]], label=['clock', 'frame'])

``` python
boxes = boxes_true + boxes_anchor + boxes_true
```

``` python
len(boxes)
```

Please refer
to [Visualising anchor boxes](data/README.md) or try out the
[walkthrough notebook](nbs/pybx_walkthrough.ipynb) for more
details!
496
1 change: 1 addition & 0 deletions _proc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.quarto/
Loading

0 comments on commit 024e037

Please sign in to comment.