def __init__(self, signed_width: float, height: float, cx: float = 0., cy: float = 0., angle: float = 0.): self.signed_width = signed_width self.height = height self.center_pt = np.array([cx, cy]) self.angle = angle # compute the transformation tfm = translate2d(-0.5, -0.5) # shift the centroid of [0,0,1,1] to the origin tfm = scale2d(scale_x=signed_width, scale_y=height)*tfm # scale it along signed_width and height tfm = rotate2d(angle, 0., 0.)*tfm # rotate it tfm = translate2d(cx, cy)*tfm # now shift the centroid of the rotated rectangle to the target location self.tfm = tfm # transform the corners corners = np.array([[0,0],[1,0],[0,1],[1,1]]) # [tl, tr, bl, br] self.corners = transform(self.tfm, corners)
async def imsave(filepath: str, img: np.ndarray, params=None, file_mode: int = 0o664, context_vars: dict = {}, file_write_delayed: bool = False): '''An asyn function wrapping on :func:`cv.imwrite`. Parameters ---------- filepath : str Local path to the file to be saved to img : numpy.ndarray the image to be saved params : int Format-specific parameters, if any. Like those 'cv.IMWRITE_xxx' flags. See :func:`cv.imwrite`. file_mode : int file mode to be set to using :func:`os.chmod`. Only valid if fp is a string. If None is given, no setting of file mode will happen. context_vars : dict a dictionary of context variables within which the function runs. It must include `context_vars['async']` to tell whether to invoke the function asynchronously or not. file_write_delayed : bool Only valid in asynchronous mode. If True, wraps the file write task into a future and returns the future. In all other cases, proceeds as usual. Returns ------- asyncio.Future or int either a future or the number of bytes written, depending on whether the file write task is delayed or not Note ---- Do not use this function to write in PNG format. OpenCV would happily assume the input is BGR or BGRA and then write to PNG under that assumption, which often results in a wrong order. See Also -------- cv.imwrite wrapped asynchronous function ''' ext = path.splitext(filepath)[1] res, contents = cv2.imencode(ext, img, params=params) if res is not True: raise ValueError("Unable to encode the input image.") buf = np.array(contents.tostring()) return await aio.write_binary(filepath, buf, file_mode=file_mode, context_vars=context_vars, file_write_delayed=file_write_delayed)
def approx_oct(min_x, min_y, max_x, max_y): '''Converts a rectangle into an octagon inside it. Parameters ---------- min_x : float min x-coordinate min_y : float min y-coordinate max_x : float max x-coordinate max_y : float max y-coordinate Returns ------- polygon : numpy array list of 2D (x,y) points representing an octagon inside the rectangle (min_x, min_y, max_x, max_y) ''' c = np.array([min_x + max_x, min_y + max_y])*0.5 r = np.array([max_x, max_y]) - c return std_oct*r + c
def moment2(self): '''Second-order moment.''' if not hasattr(self, '_moment2'): moment_xx = self.signed_area * (self.min_x * self.min_x + self.min_x * self.max_x + self.max_x * self.max_x) / 3 moment_xy = self.moment_x * self.cy # self.sign*self.cx*self.cy moment_yy = self.signed_area * (self.min_y * self.min_y + self.min_y * self.max_y + self.max_y * self.max_y) / 3 self._moment2 = np.array([[moment_xx, moment_xy], [moment_xy, moment_yy]]) return self._moment2
def moment2(self): '''Second-order moment.''' if not hasattr(self, '_moment2'): # 2nd-order central moments if the rectangle were not rotated rx = self.signed_width/2 ry = self.height/2 r = Rect(-rx, -ry, rx, ry) Muu = r.moment_xx Muv = r.moment_xy Mvv = r.moment_yy # Rotate the central moments (a.k.a. moments of inertia): # Original axes: x, y # Rotated axes: u, v # Dst-to-src change-of-coordinates formulae: # x = c*u+s*v # y = -s*u+c*v # where c = cos(theta), s = sin(theta). Therefore, # Mxx = c*c*Muu + 2*c*s*Muv + s*s*Mvv # Mxy = -c*s*Muu + (c*c-s*s)*Muv + c*s*Mvv # Myy = s*s*Muu + -2*c*s*Muv + c*c*Mvv # Reference: `link <https://calcresource.com/moment-of-inertia-rotation.html>`_ c = math.cos(self.angle) s = math.sin(self.angle) cc = c*c cs = c*s ss = s*s Mxx = cc*Muu + 2*cs*Muv + ss*Mvv Mxy = -cs*Muu + (cc-ss)*Muv + cs*Mvv Myy = ss*Muu - 2*cs*Muv + cc*Mvv # Shift the origin to where it should be: # Axes from the rectangle center point: x, y # Image axes: p, q # Dst-to-src chang-of-coordinates formulae: # p = x+cx # q = y+cy # Formulae: # Mpp = Mxx + 2*cx*Mx + cx*cx*M1 # Mpq = Mxy + cx*My + cy*Mx + cx*cy*M1 # Mqq = Myy + 2*cy*My + cy*cy*M1 # where M1 is the signed area. But because the rectangle is symmetric, Mx = My = 0. cx = self.center_pt[0] cy = self.center_pt[1] M1 = self.signed_area Mpp = Mxx + cx*cx*M1 Mpq = Mxy + cx*cy*M1 Mqq = Myy + cy*cy*M1 self._moment2 = np.array([[Mpp, Mpq], [Mpq, Mqq]]) return self._moment2
def upper_bound_Hyperellipsoid_to_Hyperbox(obj): '''Returns a bounding axis-aligned box of the hyperellipsoid. Parameters ---------- obj : Hyperellipsoid the hyperellipsoid to be upper-bounded Returns ------- Hyperbox a bounding Hyperbox of the hyperellipsoid ''' weight = obj.aff_tfm.weight c = off.aff_tfm.bias m = np.array([np.linalg.norm(weight[i]) for i in range(self.ndim)]) return Hyperbox(min_coords=c-m, max_coords=c+m)
def crop2d(tl, br=None): '''Transforms an axis-aligned rectangle into [(0,0),(1,1)]. Parameters ---------- tl : 2d point (x,y) coordinates to be mapped to (0,0) if `br` is specified. If `br` is not specified, then the transformation is 2d scaling. In other words, (0,0) is mapped to (0,0) and tl is mapped to (1,1). br : 2d point (x,y), optional If specified, coordinates to be mapped to (1,1). Returns ------- Aff2d A transformation that maps points in [(0,0),(1,1)] to the crop given by `tl` and `br`. ''' if br is None: return scale2d(1.0 / tl[0], 1.0 / tl[1]) return Aff2d( offset=np.array([-tl[0] / (br[0] - tl[0]), -tl[1] / (br[1] - tl[1])]), linear=Lin2d(scale=[1.0 / (br[0] - tl[0]), 1.0 / (br[1] - tl[1])]))
def shearY2d(h): '''Returns the shearing along the y-axis.''' return Aff2d(linear=Lin2d.from_matrix(np.array([[1, 0], [h, 1]])))
def __init__(self, min_x, min_y, max_x, max_y, force_valid=False): super(Rect, self).__init__(np.array([min_x, min_y]), np.array([max_x, max_y]), force_valid=force_valid)
def __init__(self, min_x, min_y, min_z, max_x, max_y, max_z, force_valid=False): super(Box, self).__init__(np.array([min_x, min_y, min_z]), np.array([max_x, max_y, max_z]), force_valid = force_valid)
def min_pt(self): '''Corner point with minimum coordinates.''' return np.array([self.min_x, self.min_y])
'''Utilities for converting a rectangle into an octagon bounded by it.''' from mt import np __all__ = ['ISQRT2', 'approx_oct'] ISQRT2 = 1/np.sqrt(2) # octagon to approximate a circle originating at (0,0) with radius 1 std_oct = np.array([ (1, 0), (ISQRT2, ISQRT2), (0, 1), (-ISQRT2, ISQRT2), (-1, 0), (-ISQRT2, -ISQRT2), (0, -1), (ISQRT2, -ISQRT2), ]) def approx_oct(min_x, min_y, max_x, max_y): '''Converts a rectangle into an octagon inside it. Parameters ---------- min_x : float min x-coordinate min_y : float min y-coordinate
def center_pt(self): '''Center point.''' return np.array([self.cx, self.cy])
def swapAxes2d(): '''Returns the affine transformation that swaps the x-axis with the y-axis.''' return Aff2d(linear=Lin2d.from_matrix(np.array([[0, 1], [1, 0]])))
def get_linear(angle, on, scale=1.0): '''Forms the linear part of the transformation matrix representing scaling*rotation*reflection.''' ca = np.cos(angle) * scale sa = np.sin(angle) * scale return np.array([[-ca, -sa], [-sa, ca]]) if on else np.array( [[ca, -sa], [sa, ca]])
def flipUD2d(height): '''Returns a up-down flip for a given height.''' return Aff2d.from_matrix(np.array([[1, 0, 0], [0, -1, height]]))
def flipLR2d(width): '''Returns a left-right flip for a given width.''' return Aff2d.from_matrix(np.array([[-1, 0, width], [0, 1, 0]]))
def originate2d(tfm, x, y): '''Tweaks a 2D affine transformation so that it acts as if it originates at (x,y) instead of (0,0).''' return Aff2d(offset=np.array((x, y))).conjugate(tfm)
def translate2d(x, y): '''Returns the translation.''' return Aff2d(offset=np.array([x, y]))
def __init__(self, m0, m1, m2): self._m0 = np.float(m0) self._m1 = np.array(m1) self._m2 = np.array(m2) self._mean = None self._cov = None
def max_pt(self): '''Corner point with maximum coordinates.''' return np.array([self.max_x, self.max_y])