Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/deploy-gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,12 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
steps: [uses: thatgeeman/workflows/quarto-ghp@master]
steps:
- uses: thatgeeman/workflows/quarto-ghp@master
with:
version: "3.8"
- name: Verify generated sidebar
run: |
test -f _docs/index.html
grep -q 'id="quarto-sidebar"' _docs/index.html
grep -q 'href="./basics.html"' _docs/index.html
95 changes: 61 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PyBx
================
# PyBx


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

Expand All @@ -17,17 +17,32 @@ box = get_bx({"x_min": 130, "y_min": 63, "x_max": 225, "y_max": 180})
box.label
```

['unknown']

Inputs are validated as Pascal VOC boxes: exactly four coordinates and
an optional string or integer label, non-negative coordinates, and maxima greater
than minima. For explicit construction, use `bbx` for coordinate lists,
`dbx` for dictionaries, and `jbx` for JSON strings or dictionaries. The
former `lbx` alias has been removed; use `bbx` instead.
an optional string or integer label, non-negative coordinates, and
maxima greater than minima. For explicit construction, use
[`bbx`](https://thatgeeman.github.io/pybx/basics.html#bbx) for
coordinate lists,
[`dbx`](https://thatgeeman.github.io/pybx/basics.html#dbx) for
dictionaries, and
[`jbx`](https://thatgeeman.github.io/pybx/basics.html#jbx) for JSON
strings or dictionaries. The former `lbx` alias has been removed; use
[`bbx`](https://thatgeeman.github.io/pybx/basics.html#bbx) instead.

`Bx.xywh()` and `Bx.yolo()` now include the label as the fifth value in
their returned box. IoU values retain full floating-point precision.

[![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/examples/pybx_walkthrough_0.4.ipynb)
[![Ask
DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/thatgeeman/pybx)

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

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

### Installation

``` shell
Expand All @@ -44,7 +59,7 @@ from pybx import anchor, ops

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

coords, labels = anchor.bx(image_sz, feature_sz, asp_ratio)
```
Expand Down Expand Up @@ -72,7 +87,7 @@ ratios, we use `anchor.bxs` instead:

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

coords, labels = anchor.bxs(image_sz, feature_szs, asp_ratios)
```
Expand Down Expand Up @@ -105,7 +120,8 @@ exposing many useful methods and attributes of
example to calculate the area of each box iteratively:

``` python
from pybx.basics import *
from pybx.basics import *

# passing anchor boxes and labels from anchor.bxs()
print(coords.shape)

Expand Down Expand Up @@ -143,42 +159,55 @@ boxes[-1]
boxes[-1].coords, boxes[-1].label
```

([[217, 228, 256, 251]], (#1) ['a_8x8_2.0_63'])
([[217, 228, 256, 251]], ['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
boxes_true = mbx(coords_json) # annotation as json records
len(boxes_true)
```

2

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

492

``` python
boxes_true
boxes_true.coords
```

[{'x_min': 130, 'y_min': 63, 'x_max': 225, 'y_max': 180, 'label': 'clock'},
{'x_min': 13, 'y_min': 158, 'x_max': 90, 'y_max': 213, 'label': 'frame'}]

``` python
boxes_anchor.coords
```

MultiBx(coords=[[130, 63, 225, 180], [13, 158, 90, 213]], label=['clock', 'frame'])
array([[ 0, 0, 25, 25],
[ 25, 0, 51, 25],
[ 51, 0, 76, 25],
...,
[153, 228, 198, 251],
[185, 228, 230, 251],
[217, 228, 256, 251]])

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

``` python
len(boxes)
```

496
494

# Use ground truth boxes for model training

Expand All @@ -197,21 +226,21 @@ image_sz
boxes_true
```

MultiBx(coords=[[130, 63, 225, 180], [13, 158, 90, 213]], label=['clock', 'frame'])
MultiBx(coords: 2, labels: 2)

Calculate candidate anchor boxes for many aspect ratios and scales.

``` python
feature_szs = [(10, 10), (3, 3), (2, 2)]
asp_ratios = [0.3, 1/2., 2.]
asp_ratios = [0.3, 1 / 2.0, 2.0]

anchors, labels = anchor.bxs(image_sz, feature_szs, asp_ratios)
```

Wrap using pybx methods. This step is not necessary but convenient.

``` python
boxes_anchor = get_bx(anchors, labels)
boxes_anchor = get_bx(anchors, labels)
len(boxes_anchor)
```

Expand All @@ -221,11 +250,11 @@ The following function returns two positive ground truth anchors with
largest IOU for each class in the label bounding boxes passed.

``` python
gt_anchors, gt_ious, gt_masks = get_gt_max_iou(
true_annots=boxes_true,
anchor_boxes=boxes_anchor, # if plain numpy, pass anchor_boxes and anchor_labels
gt_anchors, gt_ious, gt_masks = get_gt_max_iou(
true_annots=boxes_true,
anchor_boxes=boxes_anchor, # if plain numpy, pass anchor_boxes and anchor_labels
update_labels=False, # whether to replace ground truth labels with true labels
positive_boxes=1, # can request extra boxes
positive_boxes=1, # can request extra boxes
)
```

Expand All @@ -237,23 +266,21 @@ gt_anchors
'frame': BaseBx(coords=[[12, 152, 72, 256]], label=['a_3x3_0.5_6'])}

``` python
all_gt_anchors = gt_anchors['clock'] + gt_anchors['frame']
all_gt_anchors = gt_anchors["clock"] + gt_anchors["frame"]
all_gt_anchors
```

/mnt/data/projects/pybx/pybx/basics.py:464: BxViolation: Change of object type imminent if trying to add <class 'pybx.basics.BaseBx'>+<class 'pybx.basics.BaseBx'>. Use <class 'pybx.basics.BaseBx'>+<class 'pybx.basics.BaseBx'> instead or basics.stack_bxs().
f"Change of object type imminent if trying to add "
/work1/u31l94/pybx/pybx/basics.py:599: BxViolation: Change of object type imminent if trying to add <class 'pybx.basics.BaseBx'>+<class 'pybx.basics.BaseBx'>. Use <class 'pybx.basics.BaseBx'>+<class 'pybx.basics.BaseBx'> instead or basics.stack_bxs().
warnings.warn(

MultiBx(coords=[[156, 0, 227, 180], [12, 152, 72, 256]], label=['a_2x2_0.3_1', 'a_3x3_0.5_6'])
MultiBx(coords: 2, labels: 2)

``` python
v = VisBx(pth='../data/', img_fn='image.jpg', image_sz=image_sz)
v.show(all_gt_anchors, color={'a_2x2_0.3_1':'red', 'a_3x3_0.5_6': 'red'})
v = VisBx(pth="../data/", img_fn="image.jpg", image_sz=image_sz)
v.show(all_gt_anchors, color={"a_2x2_0.3_1": "red", "a_3x3_0.5_6": "red"})
```

<AxesSubplot:>

![](index_files/figure-commonmark/cell-26-output-2.png)
![](index_files/figure-commonmark/cell-27-output-1.png)

More exploratory stuff in the [walkthrough
notebook](https://github.com/thatgeeman/pybx/blob/master/examples/pybx_walkthrough_0.4.ipynb)
Expand Down
31 changes: 11 additions & 20 deletions nbs/01_basics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -3418,29 +3418,20 @@
"\n",
"\n",
"def get_bx(coords, label=None, no_check=False):\n",
" \"\"\"\n",
" Helper function to check and call the correct type of Bx instance.\n",
"\n",
" Checks for the type of data passed and calls the respective class\n",
" to generate a Bx instance. Currently only supports ndarray, list, dict,\n",
" tuple, nested list, nested tuple.\n",
" \"\"\"Create a `BaseBx` or `MultiBx` from supported coordinates.\n",
"\n",
" Parameters\n",
" ----------\n",
" coords : ndarray, list, dict, tuple, nested list, nested tuple\n",
" Coordinates of anchor boxes.\n",
" label : list, optional\n",
" Labels for anchor boxes in order, by default None\n",
" Args:\n",
" coords: A box or collection of boxes represented by lists, tuples,\n",
" dictionaries, JSON strings, NumPy arrays, or existing Bx objects.\n",
" label: An optional label or list of labels corresponding to the boxes.\n",
" no_check: Skip coordinate validation for trusted internal data.\n",
"\n",
" Returns\n",
" -------\n",
" Bx\n",
" An instance of MultiBx, ListBx, BaseBx or JsonBx\n",
" Returns:\n",
" A `BaseBx` for one box or `MultiBx` for a collection of boxes.\n",
"\n",
" Raises\n",
" ------\n",
" NotImplementedError\n",
" If unknown type of coordinates are passed.\n",
" Raises:\n",
" ValueError: If coordinates are empty or malformed.\n",
" NotImplementedError: If the coordinate representation is unsupported.\n",
" \"\"\"\n",
" # process ndarray\n",
" if isinstance(coords, np.ndarray):\n",
Expand Down
2 changes: 1 addition & 1 deletion nbs/index.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@
{
"data": {
"text/plain": [
"492"
"494"
]
},
"execution_count": null,
Expand Down
31 changes: 11 additions & 20 deletions pybx/basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,29 +557,20 @@ def mbx(coords=None, label=None, no_check=False):

# %% ../nbs/01_basics.ipynb 186
def get_bx(coords, label=None, no_check=False):
"""
Helper function to check and call the correct type of Bx instance.

Checks for the type of data passed and calls the respective class
to generate a Bx instance. Currently only supports ndarray, list, dict,
tuple, nested list, nested tuple.
"""Create a `BaseBx` or `MultiBx` from supported coordinates.

Parameters
----------
coords : ndarray, list, dict, tuple, nested list, nested tuple
Coordinates of anchor boxes.
label : list, optional
Labels for anchor boxes in order, by default None
Args:
coords: A box or collection of boxes represented by lists, tuples,
dictionaries, JSON strings, NumPy arrays, or existing Bx objects.
label: An optional label or list of labels corresponding to the boxes.
no_check: Skip coordinate validation for trusted internal data.

Returns
-------
Bx
An instance of MultiBx, ListBx, BaseBx or JsonBx
Returns:
A `BaseBx` for one box or `MultiBx` for a collection of boxes.

Raises
------
NotImplementedError
If unknown type of coordinates are passed.
Raises:
ValueError: If coordinates are empty or malformed.
NotImplementedError: If the coordinate representation is unsupported.
"""
# process ndarray
if isinstance(coords, np.ndarray):
Expand Down
9 changes: 9 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Runtime dependencies used by the documentation build. Keep this file
# intentionally minimal; the Pages workflow installs nbdev separately.
nbdev==2.3.12
fastcore==1.5.27
execnb==0.1.5
ghapi==1.0.4
numpy==1.21.6
matplotlib>=3.5
opencv-python==4.7.0.72
2 changes: 1 addition & 1 deletion settings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ put_version_in_init = True
### Docs ###
branch = master
# custom_quarto_yml = True
custom_sidebar = False
custom_sidebar = True
doc_host = https://%(user)s.github.io
doc_baseurl = /%(repo)s
git_url = https://github.com/%(user)s/%(repo)s
Expand Down
Loading