Source code for opencv_wrapper.misc_functions

from typing import Union, Optional

import cv2 as cv
import numpy as np

from .model import Point, Rect


[docs]def norm(input: Union[Point, np.ndarray]) -> float: """ Calculates the absolute L2 norm of the point or array. :param input: The n-dimensional point :return: The L2 norm of the n-dimensional point """ if isinstance(input, Point): return cv.norm((*input,)) else: return cv.norm(input)
[docs]def line_iterator(image: np.ndarray, p1: Point, p2: Point) -> np.ndarray: """ Produces and array that consists of the coordinates and intensities of each pixel in a line between two points. Credit: https://stackoverflow.com/questions/32328179/opencv-3-0-python-lineiterator :param image: The image being processed :param p1: The first point :param p2: The second point :return: An array that consists of the coordinates and intensities of each pixel on the line. (shape: [numPixels, 3(5)], row = [x,y, intensity(b, g, r)]), for gray-scale(bgr) image. """ # define local variables for readability imageH = image.shape[0] imageW = image.shape[1] # P1X = P1[0] # P1.y = P1[1] # P2X = P2[0] # P2.y = P2[1] # difference and absolute difference between points # used to calculate slope and relative location between points dX = p2.x - p1.x dY = p2.y - p1.y dXa = np.abs(dX) dYa = np.abs(dY) # predefine numpy array for output based on distance between points color_chls = 1 if image.ndim == 2 else 3 itbuffer = np.empty(shape=(np.maximum(dYa, dXa), 2 + color_chls), dtype=np.int32) itbuffer.fill(np.nan) # Obtain coordinates along the line using a form of Bresenham's algorithm negY = p1.y > p2.y negX = p1.x > p2.x if p1.x == p2.x: # vertical line segment itbuffer[:, 0] = p1.x if negY: itbuffer[:, 1] = np.arange(p1.y - 1, p1.y - dYa - 1, -1, dtype=np.int32) else: itbuffer[:, 1] = np.arange(p1.y + 1, p1.y + dYa + 1, dtype=np.int32) elif p1.y == p2.y: # horizontal line segment itbuffer[:, 1] = p1.y if negX: itbuffer[:, 0] = np.arange(p1.x - 1, p1.x - dXa - 1, -1, dtype=np.int32) else: itbuffer[:, 0] = np.arange(p1.x + 1, p1.x + dXa + 1, dtype=np.int32) else: # diagonal line segment # TODO: error here when drawing from bottom right to top left diagonal. steepSlope = dYa > dXa if steepSlope: slope = dX / dY if negY: itbuffer[:, 1] = np.arange(p1.y - 1, p1.y - dYa - 1, -1, dtype=np.int32) else: itbuffer[:, 1] = np.arange(p1.y + 1, p1.y + dYa + 1, dtype=np.int32) itbuffer[:, 0] = (slope * (itbuffer[:, 1] - p1.y)).astype(np.int) + p1.x else: slope = dY / dX if negX: itbuffer[:, 0] = np.arange(p1.x - 1, p1.x - dXa - 1, -1, dtype=np.int32) else: itbuffer[:, 0] = np.arange(p1.x + 1, p1.x + dXa + 1, dtype=np.int32) itbuffer[:, 1] = (slope * (itbuffer[:, 0] - p1.x)).astype(np.int) + p1.y # Remove points outside of image colX = itbuffer[:, 0] colY = itbuffer[:, 1] itbuffer = itbuffer[(colX >= 0) & (colY >= 0) & (colX < imageW) & (colY < imageH)] # Get intensities from img ndarray # Get three values if color image num_channels = 2 if image.ndim == 2 else slice(2, None, None) itbuffer[:, num_channels] = image[itbuffer[:, 1], itbuffer[:, 0]] return itbuffer
[docs]def rect_intersection(rect1: Rect, rect2: Rect) -> Optional[Rect]: """ Calculate the intersection between two rectangles. :param rect1: First rectangle :param rect2: Second rectangle :return: A rectangle representing the intersection between `rect1` and `rect2` if it exists, else None. """ top = min(rect1, rect2, key=lambda x: x.tl.y) bottom = max(rect2, rect1, key=lambda x: x.tl.y) if top.br.y < bottom.tl.y or top.br.x < bottom.bl.x or top.bl.x > bottom.br.x: return None tl = Point(max(top.tl.x, bottom.tl.x), bottom.tl.y) width = min(bottom.br.x, top.br.x) - tl.x height = min(bottom.br.y, top.br.y) - tl.y return Rect(tl.x, tl.y, width, height)