jalan-api / src /utils /image.py
sairusses's picture
add
b400ace
"""
OMRChecker
Author: Udayraj Deshmukh
Github: https://github.com/Udayraj123
"""
import cv2
import matplotlib.pyplot as plt
import numpy as np
from src.logger import logger
plt.rcParams["figure.figsize"] = (10.0, 8.0)
CLAHE_HELPER = cv2.createCLAHE(clipLimit=5.0, tileGridSize=(8, 8))
class ImageUtils:
"""A Static-only Class to hold common image processing utilities & wrappers over OpenCV functions"""
@staticmethod
def save_img(path, final_marked):
logger.info(f"Saving Image to '{path}'")
cv2.imwrite(path, final_marked)
@staticmethod
def resize_util(img, u_width, u_height=None):
if u_height is None:
h, w = img.shape[:2]
u_height = int(h * u_width / w)
return cv2.resize(img, (int(u_width), int(u_height)))
@staticmethod
def resize_util_h(img, u_height, u_width=None):
if u_width is None:
h, w = img.shape[:2]
u_width = int(w * u_height / h)
return cv2.resize(img, (int(u_width), int(u_height)))
@staticmethod
def grab_contours(cnts):
# source: imutils package
# if the length the contours tuple returned by cv2.findContours
# is '2' then we are using either OpenCV v2.4, v4-beta, or
# v4-official
if len(cnts) == 2:
cnts = cnts[0]
# if the length of the contours tuple is '3' then we are using
# either OpenCV v3, v4-pre, or v4-alpha
elif len(cnts) == 3:
cnts = cnts[1]
# otherwise OpenCV has changed their cv2.findContours return
# signature yet again and I have no idea WTH is going on
else:
raise Exception(
(
"Contours tuple must have length 2 or 3, "
"otherwise OpenCV changed their cv2.findContours return "
"signature yet again. Refer to OpenCV's documentation "
"in that case"
)
)
# return the actual contours array
return cnts
@staticmethod
def normalize_util(img, alpha=0, beta=255):
return cv2.normalize(img, alpha, beta, norm_type=cv2.NORM_MINMAX)
@staticmethod
def auto_canny(image, sigma=0.93):
# compute the median of the single channel pixel intensities
v = np.median(image)
# apply automatic Canny edge detection using the computed median
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
edged = cv2.Canny(image, lower, upper)
# return the edged image
return edged
@staticmethod
def adjust_gamma(image, gamma=1.0):
# build a lookup table mapping the pixel values [0, 255] to
# their adjusted gamma values
inv_gamma = 1.0 / gamma
table = np.array(
[((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]
).astype("uint8")
# apply gamma correction using the lookup table
return cv2.LUT(image, table)
@staticmethod
def four_point_transform(image, pts):
# obtain a consistent order of the points and unpack them
# individually
rect = ImageUtils.order_points(pts)
(tl, tr, br, bl) = rect
# compute the width of the new image, which will be the
width_a = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
width_b = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
max_width = max(int(width_a), int(width_b))
# max_width = max(int(np.linalg.norm(br-bl)), int(np.linalg.norm(tr-tl)))
# compute the height of the new image, which will be the
height_a = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
height_b = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
max_height = max(int(height_a), int(height_b))
# max_height = max(int(np.linalg.norm(tr-br)), int(np.linalg.norm(tl-br)))
# now that we have the dimensions of the new image, construct
# the set of destination points to obtain a "birds eye view",
# (i.e. top-down view) of the image, again specifying points
# in the top-left, top-right, bottom-right, and bottom-left
# order
dst = np.array(
[
[0, 0],
[max_width - 1, 0],
[max_width - 1, max_height - 1],
[0, max_height - 1],
],
dtype="float32",
)
transform_matrix = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(image, transform_matrix, (max_width, max_height))
# return the warped image
return warped
@staticmethod
def order_points(pts):
rect = np.zeros((4, 2), dtype="float32")
# the top-left point will have the smallest sum, whereas
# the bottom-right point will have the largest sum
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
# return the ordered coordinates
return rect