File size: 2,367 Bytes
e121a44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import cv2
import numpy as np
from PIL import ImageOps, ImageEnhance, Image


def enhance(crop: Image.Image) -> Image.Image:
    """
    prepare crop for ocr - grayscale, contrast, sharpness, resize
    :param crop: image to prepare
    :rtype: Image.Image
    :return: processed image
    """
    image = ImageOps.grayscale(crop)
    image = ImageEnhance.Contrast(image).enhance(5)
    image = ImageEnhance.Sharpness(image).enhance(5)
    image = ImageOps.scale(image, 3.5)

    image = _remove_dark_frame(image)
    image = _remove_shades(image)
    return image


def _remove_dark_frame(img: Image.Image) -> Image.Image:
    # Convert PIL Image to OpenCV format
    open_cv_image = np.array(img.convert('RGB'))
    open_cv_image = cv2.cvtColor(open_cv_image, cv2.COLOR_RGB2BGR)

    # Convert to grayscale
    gray = cv2.cvtColor(open_cv_image, cv2.COLOR_BGR2GRAY)

    # Blur the image to reduce noise
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)

    # Apply a binary threshold after blurring
    _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    # Find contours from the binary image
    cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    # Assume the largest contour is the frame
    c = max(cnts, key=cv2.contourArea)

    # Find the bounding box coordinates from the contour
    x, y, w, h = cv2.boundingRect(c)

    # Crop the original image using the bounding box coordinates
    cropped = open_cv_image[y:y+h, x:x+w]

    # Convert back to PIL format
    cropped_pil = Image.fromarray(cv2.cvtColor(cropped, cv2.COLOR_BGR2RGB))
    return cropped_pil

def _remove_shades(image: Image.Image, threshold: int = 64) -> Image.Image:
    """
    Remove shades between white and black from an image using PIL.

    Parameters:
    - image_path: The path to the image.
    - threshold: The cutoff for determining whether a pixel should be white or black.

    Returns:
    - A new PIL Image object with shades removed.
    """
    # Convert the image to grayscale
    gray_img = image.convert("L")

    # Apply the threshold
    # All pixels value > threshold will be set to 255 (white)
    # All pixels value <= threshold will be set to 0 (black)
    binary_img = gray_img.point(lambda x: 255 if x > threshold else 0, '1')

    return binary_img