#!/usr/bin/env python
# encoding: utf-8
# The MIT License
# Copyright (c) 2021 Ina (David Doukhan - http://www.ina.fr/)
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from typing import NamedTuple
import dlib
[docs]class Rect(NamedTuple):
"""
This class is an internal data structure allowing to manipulate rectangle shapes
"""
#: left
x1 : float
#: top
y1 : float
#: right
x2 : float
#: bottom
y2 : float
@property
def w(self):
""" self width """
return self.x2 - self.x1
@property
def h(self):
""" self height """
return self.y2 - self.y1
@property
def center(self):
""" center (x,y) of self (x1, y1, x2, y2) """
x1, y1, x2, y2 = self
return ((x1 + x2) / 2), ((y1 + y2) / 2)
@property
def area(self):
""" self Surface area """
return self.w * self.h
@property
def max_dim_len(self):
""" max (width, height)"""
return max(self.h, self.w)
@property
def square(self):
""" returns the smallest square containing the rectangle"""
offset = self.max_dim_len / 2
xc, yc = self.center
return Rect(xc - offset, yc - offset, xc + offset, yc + offset)
[docs] def transpose(self, xoffset, yoffset):
"""
Translation
Args:
xoffset (float): horizontal offset.
yoffset (float): vertical offset.
Returns:
Rect :
"""
x1, y1, x2, y2 = self
return Rect(x1 + xoffset, y1 + yoffset, x2 + xoffset, y2 + yoffset)
[docs] def mult(self, x, y):
"""
Multiply self coordinates by horizontal and vertical scaling factors
Usefull for converting [0...1] coordinates to image frame dimensions in pixels
Args:
x (float: horizontal scaling factor.
y (float): vertical scaling factor.
Returns:
Rect:
"""
x1, y1, x2, y2 = self
return Rect(x1 * x, y1 * y, x2 * x, y2 * y)
[docs] def intersect(self, r):
"""
Rectangle intersection between self and r
Args:
r (Rect):
Returns:
Rect:
"""
x1, y1, x2, y2 = self
ret = Rect(max(x1, r.x1), max(y1, r.y1), min(x2, r.x2), min(y2, r.y2))
if ret.h <= 0 or ret.w <= 0:
return Rect(0,0,0,0)
return ret
[docs] def iou(self, r):
"""
Intersection Over Union between self and r
Args:
r (Rect):
Returns:
float:
"""
inter = self.intersect(r).area
union = self.area + r.area - inter
return inter / union
[docs] def __contains__(self, point):
"""
point contained in self
Args:
point (tuple): (x,y)
Returns:
bool: True if point is in self, else False
"""
x1, y1, x2, y2 = self
x, y = point
return x >= x1 and x <= x2 and y >= y1 and y <= y2
[docs] def to_int(self):
"""
Convert self coordinates (float) to the nearest int values
Returns:
Rect:
"""
return Rect(*[int(round(e)) for e in self])
[docs] @staticmethod
def from_dlib(x):
"""
create Rect from dlib's rectangle instance
Args:
x (dlib.rectangle or dlib.drectangle):
Returns:
Rect:
"""
return Rect(x.left(), x.top(), x.right(), x.bottom())
[docs] def to_dlibInt(self):
"""
Convert self to dlib.rectangle (int)
Returns:
dlib.rectangle:
"""
return dlib.rectangle(*[e for e in self.to_int()])
[docs] def to_dlibFloat(self):
"""
Convert self to dlib.drectangle (float)
Returns:
dlib.drectangle:
"""
return dlib.drectangle(*self)
[docs] def scale(self, scale_prct):
"""
scale self according to a given scale percentage
Args:
scale_prct (float):
Returns:
Rect:
"""
w, h = (self.w, self.h)
x1, y1, x2, y2 = self
xdiff = (w * scale_prct - w) / 2
ydiff = (h * scale_prct -h) / 2
return Rect(x1 - xdiff, y1 - ydiff, x2 + xdiff, y2 + ydiff)