Path: blob/master/Model-3/ocr/normalization.py
426 views
# -*- coding: utf-8 -*-1"""2Include functions for normalizing images of words and letters3Main functions: imageNorm, letterNorm, imageStandardization4"""5import numpy as np6import cv27import math8from .helpers import *9101112def imageStandardization(image):13""" Image standardization same as tf.image.per_image_standardization """14return (image - np.mean(image)) / max(np.std(image), 1.0/math.sqrt(image.size))151617def cropAddBorder(img, height, threshold=50, border=True, borderSize=15):18""" Crop and add border to word image of letter segmentation """19# Clear small values20ret, img = cv2.threshold(img, threshold, 255, cv2.THRESH_TOZERO)2122x0 = 023y0 = 024x1 = img.shape[1]25y1 = img.shape[0]2627for i in range(img.shape[0]):28if np.count_nonzero(img[i, :]) > 1:29y0 = i30break31for i in reversed(range(img.shape[0])):32if np.count_nonzero(img[i, :]) > 1:33y1 = i+134break35for i in range(img.shape[1]):36if np.count_nonzero(img[:, i]) > 1:37x0 = i38break39for i in reversed(range(img.shape[1])):40if np.count_nonzero(img[:, i]) > 1:41x1 = i+142break4344if height != 0:45img = resize(img[y0:y1, x0:x1], height, True)46else:47img = img[y0:y1, x0:x1]4849if border:50return cv2.copyMakeBorder(img, 0, 0, borderSize, borderSize,51cv2.BORDER_CONSTANT,52value=[0, 0, 0])53return img545556def wordTilt(img, height, border=True, borderSize=15):57""" Detect the angle for tiltByAngle function """58edges = cv2.Canny(img, 50, 150, apertureSize = 3)59lines = cv2.HoughLines(edges, 1, np.pi/180, 30)6061if lines is not None:62meanAngle = 063# Set min number of valid lines (try higher)64numLines = np.sum(1 for l in lines if l[0][1] < 0.7 or l[0][1] > 2.6)65if numLines > 1:66meanAngle = np.mean([l[0][1] for l in lines if l[0][1] < 0.7 or l[0][1] > 2.6])6768# Look for angle with correct value69if meanAngle != 0 and (meanAngle < 0.7 or meanAngle > 2.6):70img = tiltByAngle(img, meanAngle, height)71return cropAddBorder(img, height, 50, border, borderSize)727374def tiltByAngle(img, angle, height):75""" Tilt the image by given angle """76dist = np.tan(angle) * height77width = len(img[0])78sPoints = np.float32([[0,0], [0,height], [width,height], [width,0]])7980# Dist is positive for angle < 0.7; negative for angle > 2.681# Image must be shifed to right82if dist > 0:83tPoints = np.float32([[0,0],84[dist,height],85[width+dist,height],86[width,0]])87else:88tPoints = np.float32([[-dist,0],89[0,height],90[width,height],91[width-dist,0]])9293M = cv2.getPerspectiveTransform(sPoints, tPoints)94return cv2.warpPerspective(img, M, (int(width+abs(dist)), height))959697def sobelDetect(channel):98""" The Sobel Operator"""99sobelX = cv2.Sobel(channel, cv2.CV_16S, 1, 0)100sobelY = cv2.Sobel(channel, cv2.CV_16S, 0, 1)101# Combine x, y gradient magnitudes sqrt(x^2 + y^2)102sobel = np.hypot(sobelX, sobelY)103sobel[sobel > 255] = 255104return np.uint8(sobel)105106107class HysterThresh:108def __init__(self, img):109img = 255 - img110img = (img - np.min(img)) / (np.max(img) - np.min(img)) * 255111hist, bins = np.histogram(img.ravel(), 256, [0,256])112113self.high = np.argmax(hist) + 65114self.low = np.argmax(hist) + 45115self.diff = 255 - self.high116117self.img = img118self.im = np.zeros(img.shape, dtype=img.dtype)119120def getImage(self):121self.hyster()122return np.uint8(self.im)123124def hyster_rec(self, r, c):125h, w = self.img.shape126for ri in range(r-1, r+2):127for ci in range(c-1, c+2):128if (h > ri >= 0129and w > ci >= 0130and self.im[ri, ci] == 0131and self.high > self.img[ri, ci] >= self.low):132self.im[ri, ci] = self.img[ri, ci] + self.diff133self.hyster_rec(ri, ci)134135def hyster(self):136r, c = self.img.shape137for ri in range(r):138for ci in range(c):139if (self.img[ri, ci] >= self.high):140self.im[ri, ci] = 255141self.img[ri, ci] = 255142self.hyster_rec(ri, ci)143144145def hystImageNorm(image):146""" Word normalization using hystheresis thresholding """147gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)148# img = cv2.bilateralFilter(gray, 0, 10, 30)149img = cv2.bilateralFilter(gray, 0, 15, 30)150return HysterThresh(img).getImage()151152153def imageNorm(image, height, border=True, tilt=True, borderSize=15, hystNorm=False):154"""155Preprocess image156=> resize, get edges, tilt world157"""158image = resize(image, height, True)159160if hystNorm:161th = hystImageNorm(image)162else:163img = cv2.bilateralFilter(image, 0, 30, 30)164gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)165166edges = sobelDetect(gray)167ret,th = cv2.threshold(edges, 50, 255, cv2.THRESH_TOZERO)168169if tilt:170return wordTilt(th, height, border, borderSize)171return th172173174def resizeLetter(img, size = 56):175""" Resize bigger side of the image to given size """176if (img.shape[0] > img.shape[1]):177rat = float(size) / img.shape[0]178return cv2.resize(img, (int(rat * img.shape[1]), size), interpolation = cv2.INTER_CUBIC)179else:180rat = float(size) / img.shape[1]181return cv2.resize(img, (size, int(rat * img.shape[0])))182return img183184185def letterNorm(image, is_thresh=True, dim=False):186""" Preprocess an image - crop """187if is_thresh and image.shape[0] > 0 and image.shape[1] > 0:188image = cropAddBorder(image, height=0, threshold=80, border=False) # threshold=80189190resized = image191if image.shape[0] > 1 and image.shape[1] > 1:192resized = resizeLetter(image)193194result = np.zeros((64, 64), np.uint8)195offset = [0, 0]196# Calculate offset for smaller size197if image.shape[0] > image.shape[1]:198offset = [int((result.shape[1] - resized.shape[1])/2), 4]199else:200offset = [4, int((result.shape[0] - resized.shape[0])/2)]201# Replace zeros by image202result[offset[1]:offset[1] + resized.shape[0],203offset[0]:offset[0] + resized.shape[1]] = resized204205if dim:206return result, image.shape207return result208209210