opencv-gui / src /opencv_utils.py
samuellimabraz's picture
Add Streamlit application for real-time OpenCV exploration
83907f9 unverified
raw
history blame
9.39 kB
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)