Last active
December 5, 2023 11:09
-
-
Save r-sajal/66e235c58d6bd07785385006868decf2 to your computer and use it in GitHub Desktop.
Enclosed shape extraction from handwritten images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cv2 as cv | |
import numpy as np | |
import random as rng | |
rng.seed(99999) | |
# ONLY editable variables | |
IMAGE_PATH = r'C:\Users\Sajal\Desktop\s-4.jpg' # path to image | |
THRESH_MINI = 220 # pixel value above which you want MAX VALUE | |
THRESH_MAX_VAL = 255 # pixel value above our THRESH_MIN will be converted to this value | |
MIN_SIZE = 2000 # minimum size of enclosed figures you want to use (function - noise_removal) | |
##################### | |
# we are using uint8 conversion as connected components take in 8-bit single channel image | |
def noise_removal(image): | |
image = image.astype( 'uint8' ) | |
# Connected components analysis | |
nb_components, output, stats, centroids = cv.connectedComponentsWithStats(image, connectivity=8) | |
sizes = stats[1:, -1]; nb_components = nb_components - 1 | |
# min_size == Hyperparameter depends upon YOUR USAGE | |
min_size = MIN_SIZE | |
# Fake image where we put all the candidate figures | |
# image bigger than our parameter are only accepted | |
img2 = np.zeros(( output.shape )) | |
for i in range(0, nb_components): | |
if sizes[i] >= min_size: | |
img2[output == i + 1] = 255 | |
return img2.astype('uint8') | |
def filling(im_th): | |
im_floodfill = im_th.copy() | |
# Mask used to flood filling. | |
# Notice the size needs to be 2 pixels than the image. | |
h, w = im_th.shape[:2] | |
mask = np.zeros((h+2, w+2), np.uint8) | |
# Floodfill from point (0, 0) | |
cv.floodFill(im_floodfill, mask, (0,0), 255) | |
# Invert floodfilled image | |
im_floodfill_inv = cv.bitwise_not(im_floodfill) | |
# Combine the two images to get the foreground. | |
im_out = im_th | im_floodfill_inv | |
return [im_floodfill,im_floodfill_inv] | |
def draw_bounding_boxes(threshold,given_img): | |
# Standard Canny Edge Detection Implementation | |
canny_output = cv.Canny(given_img, threshold, threshold * 2) | |
contours, hierarchy = cv.findContours(canny_output, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) | |
contours_poly = [None]*len(contours) | |
boundRect = [None]*len(contours) | |
centers = [None]*len(contours) | |
radius = [None]*len(contours) | |
for i, c in enumerate(contours): | |
contours_poly[i] = cv.approxPolyDP(c, 3, True) | |
boundRect[i] = cv.boundingRect(contours_poly[i]) | |
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8) | |
color = (rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)) | |
# drawing the rectangles on extracted coordinates | |
for i in range(len(contours)): | |
cv.rectangle(drawing, (int(boundRect[i][0]), int(boundRect[i][1])), \ | |
(int(boundRect[i][0]+boundRect[i][2]), int(boundRect[i][1]+boundRect[i][3])), color, 2) | |
## For cropping the blocks | |
# crop = src_gray[int(boundRect[i][1]):int(boundRect[i][1]+boundRect[i][3]) , int(boundRect[i][0]):int(boundRect[i][0]+boundRect[i][2]) ] | |
# cv.imshow("contour"+str(i),crop) | |
cv.imshow('Contours', drawing) | |
# Standard Binarization | |
src = cv.imread(IMAGE_PATH,cv.IMREAD_GRAYSCALE) | |
cv.imshow("orig",src) | |
# Binarization modifications | |
src_gray = cv.blur(src, (3,3)) | |
th, im_th = cv.threshold(src_gray, THRESH_MINI , THRESH_MAX_VAL, cv.THRESH_BINARY_INV) | |
cv.imshow("gray",im_th) | |
# Noise and Character Removal | |
im_th = noise_removal(im_th) | |
cv.imshow('Character Removal' , im_th) | |
#filling | |
im_floodfill,im_floodfill_inv = filling(im_th) | |
cv.imshow("Floodfilled Image", im_floodfill) | |
cv.imshow("Inverted Floodfilled Image", im_floodfill_inv) | |
#Creating Bounding boxes | |
draw_bounding_boxes(100,im_floodfill_inv) | |
#Stop images from disappearing | |
cv.waitKey() | |
################################################################################################################################# | |
# CODE BY Sajal Rastogi | |
################################################################################################################################# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment