Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nalepae committed Jun 13, 2019
0 parents commit acf4576
Show file tree
Hide file tree
Showing 28 changed files with 398 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.egg-info
114 changes: 114 additions & 0 deletions .vscode/.ropeproject/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# The default ``config.py``
# flake8: noqa


def set_prefs(prefs):
"""This function is called before opening the project"""

# Specify which files and folders to ignore in the project.
# Changes to ignored resources are not added to the history and
# VCSs. Also they are not returned in `Project.get_files()`.
# Note that ``?`` and ``*`` match all characters but slashes.
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
# '.svn': matches 'pkg/.svn' and all of its children
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
'.hg', '.svn', '_svn', '.git', '.tox']

# Specifies which files should be considered python files. It is
# useful when you have scripts inside your project. Only files
# ending with ``.py`` are considered to be python files by
# default.
# prefs['python_files'] = ['*.py']

# Custom source folders: By default rope searches the project
# for finding source folders (folders that should be searched
# for finding modules). You can add paths to that list. Note
# that rope guesses project source folders correctly most of the
# time; use this if you have any problems.
# The folders should be relative to project root and use '/' for
# separating folders regardless of the platform rope is running on.
# 'src/my_source_folder' for instance.
# prefs.add('source_folders', 'src')

# You can extend python path for looking up modules
# prefs.add('python_path', '~/python/')

# Should rope save object information or not.
prefs['save_objectdb'] = True
prefs['compress_objectdb'] = False

# If `True`, rope analyzes each module when it is being saved.
prefs['automatic_soa'] = True
# The depth of calls to follow in static object analysis
prefs['soa_followed_calls'] = 0

# If `False` when running modules or unit tests "dynamic object
# analysis" is turned off. This makes them much faster.
prefs['perform_doa'] = True

# Rope can check the validity of its object DB when running.
prefs['validate_objectdb'] = True

# How many undos to hold?
prefs['max_history_items'] = 32

# Shows whether to save history across sessions.
prefs['save_history'] = True
prefs['compress_history'] = False

# Set the number spaces used for indenting. According to
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
# unit-tests use 4 spaces it is more reliable, too.
prefs['indent_size'] = 4

# Builtin and c-extension modules that are allowed to be imported
# and inspected by rope.
prefs['extension_modules'] = []

# Add all standard c-extensions to extension_modules list.
prefs['import_dynload_stdmods'] = True

# If `True` modules with syntax errors are considered to be empty.
# The default value is `False`; When `False` syntax errors raise
# `rope.base.exceptions.ModuleSyntaxError` exception.
prefs['ignore_syntax_errors'] = False

# If `True`, rope ignores unresolvable imports. Otherwise, they
# appear in the importing namespace.
prefs['ignore_bad_imports'] = False

# If `True`, rope will insert new module imports as
# `from <package> import <module>` by default.
prefs['prefer_module_from_imports'] = False

# If `True`, rope will transform a comma list of imports into
# multiple separate import statements when organizing
# imports.
prefs['split_imports'] = False

# If `True`, rope will remove all top-level import statements and
# reinsert them at the top of the module when making changes.
prefs['pull_imports_to_top'] = True

# If `True`, rope will sort imports alphabetically by module name instead
# of alphabetically by import statement, with from imports after normal
# imports.
prefs['sort_imports_alphabetically'] = False

# Location of implementation of
# rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general
# case, you don't have to change this value, unless you're an rope expert.
# Change this value to inject you own implementations of interfaces
# listed in module rope.base.oi.type_hinting.providers.interfaces
# For example, you can add you own providers for Django Models, or disable
# the search type-hinting in a class hierarchy, etc.
prefs['type_hinting_factory'] = (
'rope.base.oi.type_hinting.factory.default_type_hinting_factory')


def project_opened(project):
"""This function is called after opening the project"""
# Do whatever you like here!
Binary file added .vscode/.ropeproject/objectdb
Binary file not shown.
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2019, Manu NALEPA
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
recursive-include bounding_box *.ttf
Binary file added bounding_box/Ubuntu-B.ttf
Binary file not shown.
1 change: 1 addition & 0 deletions bounding_box/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '0.1.2'
Binary file added bounding_box/__init__.pyc
Binary file not shown.
131 changes: 131 additions & 0 deletions bounding_box/bounding_box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from __future__ import division as _division
from __future__ import print_function as _print_function

import os as _os
import os.path as _path
import numpy as np
import cv2 as _cv2
from PIL import ImageFont
import numpy as _np
from hashlib import md5 as _md5

_LOC = _path.realpath(_path.join(_os.getcwd(),_path.dirname(__file__)))

#https://clrs.cc/
_COLOR_NAME_TO_RGB = dict(
navy=((0, 38, 63), (119, 193, 250)),
blue=((0, 120, 210), (173, 220, 252)),
aqua=((115, 221, 252), (0, 76, 100)),
teal=((15, 205, 202), (0, 0, 0)),
olive=((52, 153, 114), (25, 58, 45)),
green=((0, 204, 84), (15, 64, 31)),
lime=((1, 255, 127), (0, 102, 53)),
yellow=((255, 216, 70), (103, 87, 28)),
orange=((255, 125, 57), (104, 48, 19)),
red=((255, 47, 65), (131, 0, 17)),
maroon=((135, 13, 75), (239, 117, 173)),
fuchsia=((246, 0, 184), (103, 0, 78)),
purple=((179, 17, 193), (241, 167, 244)),
black=((24, 24, 24), (220, 220, 220)),
gray=((168, 168, 168), (0, 0, 0)),
silver=((220, 220, 220), (0, 0, 0))
)

_COLOR_NAMES = list(_COLOR_NAME_TO_RGB)

_DEFAULT_COLOR_NAME = "green"

_FONT_PATH = _os.path.join(_LOC, "Ubuntu-B.ttf")
_FONT_HEIGHT = 15
_FONT = ImageFont.truetype(_FONT_PATH, _FONT_HEIGHT)

def _rgb_to_bgr(color):
return list(reversed(color))

def _color_image(image, font_color, background_color):
return background_color + (font_color - background_color) * image / 255

def _get_label_image(text, font_color_tuple_bgr, background_color_tuple_bgr):
text_image = _FONT.getmask(text)
shape = list(reversed(text_image.size))
bw_image = np.array(text_image).reshape(shape)

image = [
_color_image(bw_image, font_color, background_color)[None, ...]
for font_color, background_color
in zip(font_color_tuple_bgr, background_color_tuple_bgr)
]

return np.concatenate(image).transpose(1, 2, 0)

def add_bounding_box(image, left, top, right, bottom, label=None, color=None):
if type(image) is not _np.ndarray:
raise TypeError("'image' parameter must be a numpy.ndarray")
try:
left, top, right, bottom = int(left), int(top), int(right), int(bottom)
except ValueError:
raise TypeError("'left', 'top', 'right' & 'bottom' must be a number")

image_height, image_width, _ = image.shape

if not 0 <= top <= image_height:
raise TypeError("'top' must be between 0 and " + str(image_height))

if not 0 <= bottom <= image_height:
raise TypeError("'bottom' must be between 0 and " + str(image_height))

if not 0 <= left <= image_width:
raise TypeError("'left' must be between 0 and " + str(image_width))

if not 0 <= right <= image_width:
raise TypeError("'right' must be between 0 and " + str(image_width))

if label and type(label) is not str:
raise TypeError("'label' must be a str")

if label and not color:
hex_digest = _md5(label.encode()).hexdigest()
color_index = int(hex_digest, 16) % len(_COLOR_NAME_TO_RGB)
color = _COLOR_NAMES[color_index]

if not color:
color = _DEFAULT_COLOR_NAME

if type(color) is not str:
raise TypeError("'color' must be a str")

if color not in _COLOR_NAME_TO_RGB:
msg = "'color' must be one of " + ", ".join(_COLOR_NAME_TO_RGB)
raise ValueError(msg)

colors = [_rgb_to_bgr(item) for item in _COLOR_NAME_TO_RGB[color]]
color, color_text = colors

_cv2.rectangle(image, (left, top), (right, bottom), color, 2)

if label:
label_image = _get_label_image(label, color_text, color)
label_height, label_width, _ = label_image.shape

rectangle_bottom = top
rectangle_left = left - 1

rectangle_top = rectangle_bottom - label_height - 1
rectangle_right = rectangle_left + 1 + label_width

label_top = rectangle_top + 1

if rectangle_top < 0:
rectangle_top = top
rectangle_bottom = rectangle_top + label_height + 1

label_top = rectangle_top

label_left = rectangle_left + 1
label_bottom = label_top + label_height
label_right = label_left + label_width

_cv2.rectangle(image, (rectangle_left, rectangle_top),
(rectangle_right, rectangle_bottom), color, -1)

image[label_top:label_bottom, label_left:label_right, :] = label_image
Binary file added bounding_box/bounding_box.pyc
Binary file not shown.
97 changes: 97 additions & 0 deletions docs/examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env python

from __future__ import print_function
import cv2
from bounding_box import bounding_box as bb
import os

def show_and_save(title, image, path):
cv2.imwrite(path, image)
cv2.imshow(title, image)
print("Press 'Enter' to display the next picture...")
cv2.waitKey(0)
cv2.destroyAllWindows()

def main():
in_path = os.path.join("docs", "images", "winton.jpg")
out_path = os.path.join("docs", "images", "winton_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 281, 12, 744, 431, "Winton", "maroon")
bb.add_bounding_box(image, 166, 149, 500, 297, "Trumpet", "yellow")
show_and_save("Winton MARSALIS", image, out_path)

in_path = os.path.join("docs", "images", "khatia.jpg")
out_path = os.path.join("docs", "images", "khatia_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 280, 24, 802, 593, "Khatia", "maroon")
bb.add_bounding_box(image, 687, 1, 1448, 648, "Piano", "gray")
bb.add_bounding_box(image, 888, 492, 1190, 536, "Text")
show_and_save("Khatia BUNIATISHVILI", image, out_path)

in_path = os.path.join("docs", "images", "clarifloue.jpg")
out_path = os.path.join("docs", "images", "clarifloue_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 69, 86, 470, 136, label="Headache designer")
bb.add_bounding_box(image, 136, 196, 406, 234, "Text")
bb.add_bounding_box(image, 67, 351, 471, 400, "Headache designer")
bb.add_bounding_box(image, 130, 456, 390, 494, "Text")
show_and_save("Clarinet", image, out_path)

in_path = os.path.join("docs", "images", "nao-romeo-pepper.jpg")
out_path = os.path.join("docs", "images", "nao-romeo-pepper_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 155, 152, 244, 297, "Nao")
bb.add_bounding_box(image, 260, 6, 423, 416, "Romeo")
bb.add_bounding_box(image, 421, 76, 547, 402, "Pepper")
show_and_save("Robots", image, out_path)

in_path = os.path.join("docs", "images", "ski-paraglider.jpg")
out_path = os.path.join("docs", "images", "ski-paraglider_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 0, 128, 645, 589, "Paraglider", "orange")
bb.add_bounding_box(image, 689, 442, 818, 566, "Skier", "gray")
show_and_save("Ski and paraglider", image, out_path)

in_path = os.path.join("docs", "images", "paragliders.jpg")
out_path = os.path.join("docs", "images", "paragliders_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 90, 228, 318, 428, "Paraglider")
bb.add_bounding_box(image, 521, 110, 656, 415, "Paraglider")
show_and_save("Pretty Bounding Box", image, out_path)

in_path = os.path.join("docs", "images", "selfie.jpg")
out_path = os.path.join("docs", "images", "selfie_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 5, 7, 150, 169, "Female", "fuchsia")
bb.add_bounding_box(image, 116, 7, 193, 113, "Male", "blue")
bb.add_bounding_box(image, 189, 7, 291, 124, "Female", "fuchsia")
bb.add_bounding_box(image, 288, 25, 355, 114, "Male", "blue")
bb.add_bounding_box(image, 367, 0, 448, 92, "Male", "blue")
bb.add_bounding_box(image, 435, 29, 506, 104, "Female", "fuchsia")
bb.add_bounding_box(image, 497, 3, 597, 111, "Female", "fuchsia")
bb.add_bounding_box(image, 110, 133, 213, 245, "Female", "fuchsia")
bb.add_bounding_box(image, 176, 120, 293, 289, "Female", "fuchsia")
bb.add_bounding_box(image, 314, 115, 470, 357, "Male", "blue")
bb.add_bounding_box(image, 468, 72, 577, 226, "Male", "blue")
show_and_save("The Selfie", image, out_path)

in_path = os.path.join("docs", "images", "pobb.jpg")
out_path = os.path.join("docs", "images", "pobb_bb.png")
image = cv2.imread(in_path, cv2.IMREAD_COLOR)
bb.add_bounding_box(image, 76, 62, 155, 271, "Female", "fuchsia")
bb.add_bounding_box(image, 157, 44, 288, 274, "Male", "blue")
bb.add_bounding_box(image, 224, 64, 317, 274, "Male", "blue")
bb.add_bounding_box(image, 290, 48, 383, 277, "Male", "blue")
bb.add_bounding_box(image, 350, 42, 458, 276, "Female", "fuchsia")
bb.add_bounding_box(image, 416, 17, 510, 279, "Male", "blue")
bb.add_bounding_box(image, 482, 55, 573, 278, "Female", "fuchsia")
bb.add_bounding_box(image, 547, 63, 615, 277, "Female", "fuchsia")
bb.add_bounding_box(image, 608, 49, 704, 275, "Female", "fuchsia")
bb.add_bounding_box(image, 672, 34, 767, 274, "Male", "blue")
bb.add_bounding_box(image, 725, 62, 813, 273, "Female", "fuchsia")
bb.add_bounding_box(image, 786, 38, 887, 267, "Male", "blue")
bb.add_bounding_box(image, 864, 51, 959, 266, "Male", "blue")
show_and_save("POBB", image, out_path)

if __name__ == "__main__":
main()
Binary file added docs/images/clarifloue.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/clarifloue_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/khatia.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/khatia_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/nao-romeo-pepper.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/nao-romeo-pepper_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/paragliders.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/paragliders_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/pobb.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/pobb_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/selfie.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/selfie_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/ski-paraglider.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/ski-paraglider_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/winton.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/winton_bb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit acf4576

Please sign in to comment.