coat

Wrapper around ndarray and opencv for rapid prototyping


Keywords
ndarray, opencv, prototyping, image, processing
License
MIT
Install
pip install coat==0.6

Documentation

Coat


Coat is small wrapper that sits on numpy's ndarray (subclassed) and opencv
Coat's only purpouse is for rapid prototyping


Style

Coat is using method cascading
return from every method is Coat's HigherCoating instance
Only exception is method classic() which returns back numpy instance\

Install

preferably use virtual env

pip install coat

Demo

function Coat is a proxy function that handles different types of args.

It handles str(url), list/generator of images and ndarray.

from coat import Coat

url = "https://natgeo.imgix.net/subjects/headers/shutterstock_276228476.jpg?auto=compress,format&w=1920&h=960&fit=crop"
Coat(url).thresh(125,255).show()

Usage

Content

Core functionalities
Dominance
Array manipulation
Image downloading
Labeling
Color spaces
Helper functions
Montage
Contours
Color filtering
Motion difference


Core functionalities

Lets define two arrays of different type, size and dimension

# Import Coat(proxy function) and Montage
from coat import Coat, Montage
import numpy as np

array1 = Coat(np.zeros(shape=[40,60,3],dtype=np.uint8))
array2 = Coat(np.zeros(shape=[8,8],dtype=np.float32))
Auto resolver

Coating the arrays you let Coat resolve array operations whenever there is conflict

res = array1 + array2

res.shape,res.dtype
>>> (40, 60, 3) uint8

Coated arrays can be dominant or non-dominant. General rules are as follows:

A(non-dominant) + B(non-dominant) -> A is prioritized
A(non-dominant) + B(dominant)     -> B is prioritized
A(dominant) + B(non-dominant)     -> A is prioritized
A(dominant) + B(dominant)         -> A is prioritized
Dominance setting

You can set which array is dominant Be default each array is not dominant.

res = array1 * array2.host()
res.shape,res.dtype
>>> (8, 8) float32

If have arrays of different size and dimension( gray & colored), you can simply transform to common standard as follows

list_of_images = [img1,img2, img3, .., .., imgN]

# define common standard
grayscale_template = Coat(np.zeros(shape=[100,100],dtype=np.uint8))
colored_template = Coat(np.zeros(shape=[100,100],dtype=np.uint8))

grascaled = [grayscale_template.host() + image for image in list_of_images]
colored =   [colored_template.host() + image for image in list_of_images]
interpolation

You can set interpolation algorithm (default is LINEAR - BILINEAR)

res = array1 - array2.host('CUBIC')
Removing dominance
res = array1 * array2.host('CUBIC').guest()
res.shape,res.dtype
>>> (40, 60, 3) uint8

Array manipulation

osize as objective size
array1.shape, array2.shape
>>> (40, 60, 3) , (8,8)
array1.osize(array2.shape).shape
>>> (8,8,3)
array2.osize(array1.shape).shape
>>> (40, 60)
rsize as relative size
res = array2.rsize(fx = 2, fy=0.5)
res.shape
>>> (16, 4)
ndarray compatibility
res = array1 + np.zeros(shape=array1.shape)
np.uint8(array1) # -> returns back Coat instance with changed datatype
array1.classic() # -> returns back numpy instance

Leveraging OpenCV

Download image

pass url to Coat and show it

url = "https://natgeo.imgix.net/subjects/headers/shutterstock_276228476.jpg?auto=compress,format&w=1920&h=960&fit=crop"
image = Coat(url).show()
image = image.rsize(fx=0.25,fy=0.25)

Supports labeling
# Use int for objective coordinates
image.labelbox("Home",(0,136),(230,340), bcolor = [0,255,0]).show()
# Use float for relative coordinates
image.labelbox("Home",(0.0,0.3),(0.9,0.7), bcolor = [0,255,0]).show()

Colorspace change

supported color transformation

BGR2GRAY
BGR2HLS
BGR2HSV
HSV2BGR
GRAY2RGB
GRAY2BGR
RGB2GRAY
RGB2HSV
RGB2HLS
image.color_to('BGR2GRAY')
NOTE

OpenCV is using BGR as default color scheme

Image processing helpers

Threshold

image.thresh(125,255,'thresh_binary').show()

Convolution filtering

image.blur_median
image.filter_bilateral
image.blur_gauss
image.blur_average

Convolution 2D

img.conv(kernel)
Montage

See orignal next to processed image
we add host (turn on dominance of first image) so we get result in RGB colorspace as our original image is rgb

image.rsize(fx=0.3,fy=0.3).host().join(image.thresh(127,255)).show()

Montage of different color spaces

img = image.rsize(fx=0.3,fy=0.3)
color_spaces = ["BGR2GRAY","BGR2HLS","BGR2HSV",]

Dominant is the first image if template is not defined

all_images = [img] + [img.to_color(cspace) for cspace in color_spaces]
montage = Montage(all_images).grid(2,2).show()

resize montage based on template

montage = Montage(all_images).template(np.zeros(shape=[50,50,3],dtype=np.uint8)).grid(2,2)
Remove stars with morphological opening
image.morphologyEx('open',3).show()

Contours
# Draw quick countours
thr = image.thresh(200,255)

# copy 
contoured = image.copy().contours(thr,min_size=5, max_size = 9999999,thickness=2,color = [0,125,255]).show()

Replace particular color
present = [0,125,255]
future = [255,0,0]
contoured.replace(present,future).show()

Color filtering
# [36,0,0] --> green color interval in HSV <--[70,255,255]
image.filterHsv([36,0,0],[70,255,255],passband=True).show()
image.filterHsv([36,0,0],[70,255,255],passband=False).show()
# Passband False:   -------|++|----- 
# Passband True:   ++++++|--|++++++ 

passband True

passband False

Motion difference
box1 = Coat(np.zeros(shape=[400,400,3])).box((30,30),(250,250),color=[255,125,0])
box2 = Coat(np.zeros(shape=[400,400,3])).box((30,150),(250,350),color=[255,125,0])

motion_diff = box1.motion_difference(box2,val=30).show()