Spaces:
Running
Running
| """ | |
| 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""" | |
| def save_img(path, final_marked): | |
| logger.info(f"Saving Image to '{path}'") | |
| cv2.imwrite(path, final_marked) | |
| 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))) | |
| 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))) | |
| 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 | |
| def normalize_util(img, alpha=0, beta=255): | |
| return cv2.normalize(img, alpha, beta, norm_type=cv2.NORM_MINMAX) | |
| 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 | |
| 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) | |
| 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 | |
| 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 | |