Spaces:
Running
Running
import cv2 | |
import numpy as np | |
from src.hand_tracker import HandTracker | |
from src.face_mesh_tracker import FaceMeshTracker | |
class OpenCVUtils: | |
def __init__(self) -> None: | |
self.hand_tracker = HandTracker( | |
num_hands=2, | |
min_hand_detection_confidence=0.7, | |
min_hand_presence_confidence=0.7, | |
min_tracking_confidence=0.7, | |
) | |
self.face_mesh_tracker = FaceMeshTracker( | |
num_faces=1, | |
min_face_detection_confidence=0.7, | |
min_face_presence_confidence=0.7, | |
min_tracking_confidence=0.7, | |
) | |
def detect_faces(self, frame: np.ndarray, draw: bool = True) -> np.ndarray: | |
""" | |
Detect a face in the frame with the face mesh tracker of mediapipe | |
:param frame: The frame to detect the face | |
:param draw: If the output should be drawn | |
""" | |
return self.face_mesh_tracker.detect(frame, draw=draw) | |
def detect_hands(self, frame: np.ndarray, draw: bool = True) -> np.ndarray: | |
""" | |
Detect a hand in the frame with the hand tracker of mediapipe | |
:param frame: The frame to detect the hand | |
:param draw: If the output should be drawn | |
""" | |
result = self.hand_tracker.detect(frame, draw=draw) | |
return result | |
def apply_color_filter( | |
self, frame: np.ndarray, lower_bound: list, upper_bound: list | |
) -> np.ndarray: | |
""" | |
Apply a color filter to the frame | |
:param frame: The frame to apply the filter | |
:param lower_bound: The lower bound of the color filter in HSV | |
:param upper_bound: The upper bound of the color filter in HSV | |
""" | |
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) | |
lower_bound = np.array([lower_bound[0], lower_bound[1], lower_bound[2]]) | |
upper_bound = np.array([upper_bound[0], upper_bound[1], upper_bound[2]]) | |
mask = cv2.inRange(hsv, lower_bound, upper_bound) | |
return cv2.bitwise_and(frame, frame, mask=mask) | |
def apply_edge_detection( | |
self, frame: np.ndarray, lower_canny: int = 100, upper_canny: int = 200 | |
) -> np.ndarray: | |
""" | |
Apply a edge detection to the frame | |
:param frame: The frame to apply the filter | |
:param lower_canny: The lower bound of the canny edge detection | |
:param upper_canny: The upper bound of the canny edge detection | |
""" | |
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | |
edges = cv2.Canny(gray, lower_canny, upper_canny) | |
return cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) | |
def apply_contour_detection(self, frame: np.ndarray) -> np.ndarray: | |
""" | |
Apply a contour detection to the frame | |
:param frame: The frame to apply the filter | |
""" | |
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | |
ret, thresh = cv2.threshold(gray, 127, 255, 0) | |
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
cv2.drawContours(frame, contours, -1, (0, 255, 0), 3) | |
return frame | |
def blur_image(self, image: np.ndarray, kernel_size: int = 5) -> np.ndarray: | |
""" | |
Apply a blur to the image | |
:param image: The image to apply the blur | |
:param kernel_size: The kernel size of the blur | |
""" | |
if kernel_size % 2 == 0: | |
kernel_size += 1 | |
return cv2.GaussianBlur(image, (kernel_size, kernel_size), 0) | |
def rotate_image(self, image: np.ndarray, angle: int = 0) -> np.ndarray: | |
""" | |
Rotate the image | |
:param image: The image to rotate | |
:param angle: The angle to rotate the image | |
""" | |
(h, w) = image.shape[:2] | |
center = (w / 2, h / 2) | |
M = cv2.getRotationMatrix2D(center, angle, 1.0) | |
return cv2.warpAffine(image, M, (w, h)) | |
def resize_image( | |
self, image: np.ndarray, width: int = None, height: int = None | |
) -> np.ndarray: | |
""" | |
Resize the image | |
:param image: The image to resize | |
:param width: The width of the new image | |
:param height: The height of the new image | |
""" | |
dim = None | |
(h, w) = image.shape[:2] | |
if width is None and height is None: | |
return image | |
if width is None: | |
r = height / float(h) | |
dim = (int(w * r), height) | |
else: | |
r = width / float(w) | |
dim = (width, int(h * r)) | |
return cv2.resize(image, dim, interpolation=cv2.INTER_AREA) | |
def pencil_sketch( | |
self, | |
image: np.ndarray, | |
sigma_s: int = 60, | |
sigma_r: float = 0.07, | |
shade_factor: float = 0.05, | |
) -> np.ndarray: | |
# Converte para sketch preto e branco | |
gray, sketch = cv2.pencilSketch( | |
image, sigma_s=sigma_s, sigma_r=sigma_r, shade_factor=shade_factor | |
) | |
return sketch | |
def stylization( | |
self, image: np.ndarray, sigma_s: int = 60, sigma_r: float = 0.45 | |
) -> np.ndarray: | |
# Efeito de pintura estilizada | |
return cv2.stylization(image, sigma_s=sigma_s, sigma_r=sigma_r) | |
def cartoonify(self, image: np.ndarray) -> np.ndarray: | |
# Cartoon: detecta bordas e aplica quantização de cores | |
# 1) Detecção de bordas | |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
blur = cv2.medianBlur(gray, 7) | |
edges = cv2.adaptiveThreshold( | |
blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 2 | |
) | |
# 2) Redução de cores | |
data = np.float32(image).reshape((-1, 3)) | |
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001) | |
_, label, center = cv2.kmeans( | |
data, 8, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS | |
) | |
center = np.uint8(center) | |
quant = center[label.flatten()].reshape(image.shape) | |
# Combina bordas e quantização | |
cartoon = cv2.bitwise_and(quant, quant, mask=edges) | |
return cartoon | |
def color_quantization(self, image: np.ndarray, k: int = 8) -> np.ndarray: | |
# Reduz o número de cores via k-means | |
data = np.float32(image).reshape((-1, 3)) | |
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001) | |
_, label, center = cv2.kmeans( | |
data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS | |
) | |
center = np.uint8(center) | |
quant = center[label.flatten()].reshape(image.shape) | |
return quant | |
def equalize_histogram(self, image: np.ndarray) -> np.ndarray: | |
ycrcb = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb) | |
channels = cv2.split(ycrcb) | |
cv2.equalizeHist(channels[0], channels[0]) | |
merged = cv2.merge(channels) | |
return cv2.cvtColor(merged, cv2.COLOR_YCrCb2BGR) | |
def adaptive_threshold(self, image: np.ndarray) -> np.ndarray: | |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
return cv2.cvtColor( | |
cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, | |
cv2.THRESH_BINARY, 11, 2), | |
cv2.COLOR_GRAY2BGR) | |
def morphology(self, image: np.ndarray, op: str = 'erode', ksize: int = 5) -> np.ndarray: | |
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (ksize, ksize)) | |
ops = { | |
'erode': cv2.erode, | |
'dilate': cv2.dilate, | |
'open': cv2.morphologyEx, | |
'close': cv2.morphologyEx | |
} | |
if op in ['open', 'close']: | |
flag = cv2.MORPH_OPEN if op == 'open' else cv2.MORPH_CLOSE | |
return ops[op](image, flag, kernel) | |
return ops[op](image, kernel) | |
def sharpen(self, image: np.ndarray) -> np.ndarray: | |
kernel = np.array([[0, -1, 0], | |
[-1, 5, -1], | |
[0, -1, 0]]) | |
return cv2.filter2D(image, -1, kernel) | |
def hough_lines(self, image: np.ndarray) -> np.ndarray: | |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
edges = cv2.Canny(gray, 50, 150) | |
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=50, | |
minLineLength=50, maxLineGap=10) | |
if lines is not None: | |
for x1, y1, x2, y2 in lines[:,0]: | |
cv2.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2) | |
return image | |
def hough_circles(self, image: np.ndarray) -> np.ndarray: | |
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) | |
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp=1.2, | |
minDist=50, param1=50, param2=30, | |
minRadius=5, maxRadius=100) | |
if circles is not None: | |
circles = np.uint16(np.around(circles)) | |
for x, y, r in circles[0, :]: | |
cv2.circle(image, (x, y), r, (0, 255, 0), 2) | |
return image | |
def optical_flow(self, prev_gray: np.ndarray, curr_gray: np.ndarray, image: np.ndarray) -> np.ndarray: | |
flow = cv2.calcOpticalFlowFarneback(prev_gray, curr_gray, None, | |
0.5, 3, 15, 3, 5, 1.2, 0) | |
mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1]) | |
hsv = np.zeros_like(image) | |
hsv[...,1] = 255 | |
hsv[...,0] = ang * 180 / np.pi / 2 | |
hsv[...,2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX) | |
return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) |