#coding: utf-8
import re
import cv2
import math
import numpy as np
from ..utils.generic_utils import handleKeyError
from ..matplotlib.cmaps import FAMOUS_COLOR_PALETTES, color_dict_create
from ..matplotlib.layout import FigAxes_create, clear_grid
SUPPORTED_COORD_TYPES = ["xywh", "ltrb"]
cv2BLACK = (0, 0, 0)
cv2RED = (0, 0, 255)
cv2GREEN = (0, 128, 0)
cv2YELLOW = (0, 255, 255)
cv2BLUE = (255, 0, 0)
cv2MAGENTA = (255, 0, 255)
cv2CYAN = (255, 255, 0)
cv2WHITE = (255, 255, 255)
[docs]def convert_coords(bbox, to_type, from_type=""):
"""Convert coordinates::
[OpenCV] [YOLO]
(x,y)---------(x+w,y) (l,t)----------(r,t)
| | | |
| | | |
| | | |
(x,y+h)-------(x+w,y+h) (l,b)----------(r,b)
[xywh] [ltrb]
Args:
bbox (tuple) : Bounding Box coordinates.
to_type (str) : coordinate type.
Examples:
>>> from pycharmers.opencv import convert_coords
>>> xywh = (120,250,60,80)
>>> ltrb = convert_coords(bbox=xywh, to_type="ltrb")
>>> xywh = convert_coords(bbox=ltrb, to_type="xywh")
"""
handleKeyError(lst=SUPPORTED_COORD_TYPES, to_type=to_type)
if from_type!=to_type:
a,b,c,d = bbox
if to_type == "xywh":
a,b,c,d = (a,b,c-a,d-b)
elif to_type == "ltrb":
a,b,c,d = (a,b,a+c,b+d)
bbox = (a,b,c,d)
return bbox
[docs]def draw_bboxes_create(coord_type="xywh"):
handleKeyError(lst=SUPPORTED_COORD_TYPES, coord_type=coord_type)
def draw_bboxes(frame, bboxes, infos=None):
if not hasattr(bboxes[0], "__iter__"):
bboxes = [bboxes]
if infos is None:
infos = [{} for _ in range(len(bboxes))]
for bbox,info in zip(bboxes, infos):
color = info.pop("color", (0,255,0))
text = info.pop("text", "")
rectangle_thickness = info.pop("rectangle_thickness", 3)
l,t,r,b = convert_coords(bbox, to_type="ltrb", from_type=coord_type)
cv2.rectangle(img=frame, pt1=(l, t), pt2=(r, b), color=color, thickness=rectangle_thickness)
if len(text)>0:
draw_text_with_bg(img=frame, text=text, org=(l,t-10), offset=(10, 10), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.5, thickness=2)
return frame
dict_infos = '{"color":(255,0,0),"text": "person1"},{"color":(0,255,0),"text": "person2"}'
draw_bboxes.__doc__ = f"""Drawing Inference results on frame.
Args:
frame (ndarray) : Image. shape=(H,W,ch)
bboxes (list) : Each element is the coordinate (x,y,w,h)
infos (list) : Each element is dictionary. (``key`` is ``color``, or ``text``)
Examples:
>>> import cv2
>>> import matplotlib.pyplot as plt
>>> from pycharmers.opencv import draw_bboxes_{coord_type}, cv2read_mpl
>>> img = cv2read_mpl("path/to/img.png")
>>> draw_bboxes_{coord_type}(
... frame=img,
... bboxes=[(120,250,60,80),(220,40,80,100)],
... infos=[{dict_infos}]
... )
>>> plt.imshow(img)
>>> plt.show()
"""
return draw_bboxes
draw_bboxes_xywh = draw_bboxes_create(coord_type="xywh")
draw_bboxes_ltrb = draw_bboxes_create(coord_type="ltrb")
[docs]def cv2read_mpl(filename, *flags):
"""loads an image from the specified file and returns it as RGB format.
Args:
filename (str): Name of file to be loaded.
flags (int) : Flags.
"""
return cv2.cvtColor(cv2.imread(filename, *flags), cv2.COLOR_BGR2RGB)
[docs]def cv2plot(x, ax=None, clear_pos=["l","t","r","b"], cmap=None, is_cv2=True, figkeywargs={}, plotkeywargs={}):
"""Plot Image using OpenCV
Args:
x (str/np.ndarray) : path to an image, or image. (BGR)
ax (Axes) : The ``Axes`` instance.
clear_pos (list) : Positions to clean a grid
cmap (str) :
is_cv2 (bool) : Whether ``x`` is BGR (OpenCV format) or not.
figkeywargs (dict) : Keyword arguments for :meth:`FigAxes_create <pycharmers.matplotlib.layout.FigAxes_create>`
plotkeywargs (dict) : Keyword arguments for ``ax.imshow`` .
Examples:
>>> from pycharmers.opencv import cv2plot, SAMPLE_LENA_IMG
>>> ax = cv2plot(x=SAMPLE_LENA_IMG)
"""
cmap = cmap or plotkeywargs.pop("cmap", None)
ax = FigAxes_create(ax=ax, **figkeywargs)[1][0]
if isinstance(x, str):
x = cv2read_mpl(x)
elif is_cv2:
x = cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
ax.imshow(X=x, cmap=cmap, **plotkeywargs)
ax = clear_grid(ax, pos=clear_pos)
return ax
[docs]def draw_text_with_bg(img, text, org=(10,10), offset=(10, 10),
fontFace=cv2.FONT_HERSHEY_COMPLEX, fontScale=1,
color=cv2BLACK, bgcolor=cv2WHITE, color_type="css4",
thickness=2, **kwargs):
"""Put text with background color.
Args:
img (np.ndarray) : Image.
text (str) : Text string to be drawn.
org (tuple) : Bottom-left corner of the text string in the image.
fontFace (int) : Font type.
fontScale (int) : Font scale factor that is multiplied by the font-specific base size.
color (str/tuple) : Text color.
thickness (int) : Thickness of the lines used to draw a text.
lineType (int) : Line type.
bottomLeftOrigin (bool) : When ``True`, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
Examples:
>>> import matplotlib.pyplot as plt
>>> from pycharmers.opencv import draw_text_with_bg, cv2read_mpl, SAMPLE_LENA_IMG
>>> img = cv2read_mpl(filename=SAMPLE_LENA_IMG)
>>> draw_text_with_bg(img=img, offset=(100,-100), text="My name is Shuto")
>>> plt.imshow(img)
>>> plt.show()
"""
if isinstance(color, str):
color = FAMOUS_COLOR_PALETTES.get(color_type).get(color, cv2BLACK)
if isinstance(bgcolor, str):
bgcolor = FAMOUS_COLOR_PALETTES.get(color_type).get(bgcolor, cv2WHITE)
text_W, text_H = cv2.getTextSize(text=text, fontFace=fontFace, fontScale=fontScale, thickness=thickness)[0]
text_off_x, text_off_y = offset
org_x, org_y = org
box_coords = (
(org_x - text_off_x, org_y + text_off_y),
(org_x + text_W + text_off_x, org_y - text_H - text_off_y)
)
cv2.rectangle(img, *box_coords, bgcolor, cv2.FILLED)
cv2.putText(
img=img, text=text, org=org, fontFace=fontFace,
fontScale=fontScale, color=color, thickness=thickness, **kwargs
)
[docs]def plot_cv2fontFaces(bgcolor=(50,50,50), cmap="Pastel1"):
"""Plot All ``fontFace`` supported by OpenCV.
Args:
bgcolor (tuple) : background color (RGB)
cmap (str) : The name of a color map known to ``matplotlib``
Examples:
>>> from pycharmers.opencv import plot_cv2fontFaces
>>> plot_cv2fontFaces()
"""
i=0; img = np.full(shape=(400,1400,3), fill_value=bgcolor, dtype=np.uint8)
color_dict = color_dict_create(keys=range(8), cmap=cmap, max_val=255)
for name,val in cv2.__dict__.items():
m = re.match(pattern=r"^FONT_(?!.*ITALIC$).+$", string=name)
if m:
cv2.putText(img=img, text=f"{val:>02} {name}", org=(20, 35+50*i), fontScale=1, color=color_dict[i%8], fontFace=val)
cv2.putText(img=img, text=f"{val | cv2.FONT_ITALIC:>02} {name}", org=(720, 35+50*i), fontScale=1, color=color_dict[i%8], fontFace=val | cv2.FONT_ITALIC)
i+=1
ax = cv2plot(img, figkeywargs={"figsize": (14,49)}, is_cv2=False)
ax.set_title("OpenCV fontFace [left: normal, right: FONT_ITALICK]", size=20)
return ax