0

I have about a hundred photos that aren't very sharp and I'd like to make them sharper.

introducir la descripción de la imagen aquí

So I created a script with python that already tries with one. I have tried with PIL, OpenCV and OCR readers to read texts from Images.

# External libraries used for
# Image IO
from PIL import Image

# Morphological filtering
from skimage.morphology import opening
from skimage.morphology import disk

# Data handling
import numpy as np

# Connected component filtering
import cv2

black = 0
white = 255
threshold = 160

# Open input image in grayscale mode and get its pixels.
img = Image.open("image3.png").convert("LA")
pixels = np.array(img)[:,:,0]

# Remove pixels above threshold
pixels[pixels > threshold] = white
pixels[pixels < threshold] = black


# Morphological opening
blobSize = 1 # Select the maximum radius of the blobs you would like to remove
structureElement = disk(blobSize)  # you can define different shapes, here we take a disk shape
# We need to invert the image such that black is background and white foreground to perform the opening
pixels = np.invert(opening(np.invert(pixels), structureElement))


# Create and save new image.
newImg = Image.fromarray(pixels).convert('RGB')
newImg.save("newImage1.PNG")

# Find the connected components (black objects in your image)
# Because the function searches for white connected components on a black background, we need to invert the image
nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(np.invert(pixels), connectivity=8)

# For every connected component in your image, you can obtain the number of pixels from the stats variable in the last
# column. We remove the first entry from sizes, because this is the entry of the background connected component
sizes = stats[1:,-1]
nb_components -= 1

# Define the minimum size (number of pixels) a component should consist of
minimum_size = 100

# Create a new image
newPixels = np.ones(pixels.shape)*255

# Iterate over all components in the image, only keep the components larger than minimum size
for i in range(1, nb_components):
    if sizes[i] > minimum_size:
        newPixels[output == i+1] = 0

# Create and save new image.
newImg = Image.fromarray(newPixels).convert('RGB')
newImg.save("newImage2.PNG")

But it returns:

introducir la descripción de la imagen aquí introducir la descripción de la imagen aquí

I would prefer it not to be black and white, the best output would be one which upscale both text and image

Revolucion for Monica
  • 2,848
  • 8
  • 39
  • 78

1 Answers1

0

As mentioned in the comments, the quality is very bad. This is not an easy problem. However, there may be a couple of tricks you can try.

This looks like it is due to some anti-aliasing that has been applied to the image/scan. I would try reversing anti-aliasing if possible. As descriped in the post the steps would be similar to this:

  1. Apply low pass filter
  2. difference = original_image - low_pass_image
  3. sharpened_image = original_image + alpha*difference

Code may look something like this:

from skimage.filters import gaussian

alpha = 1   # Sharpening factor

low_pass_image = gaussian(image, sigma=1)
difference = original_image - low_pass_image
sharpened_image = original_image + alpha*difference

Also, scikit image has an implementation of an unsharp mask as well as the wiener filter.

gnodab
  • 850
  • 6
  • 15