R.hagens
R.hagens

Reputation: 375

denoising binary image in python

For my project i'm trying to binarize an image with openCV in python. I used the adaptive gaussian thresholding from openCV to convert the image with the following result: enter image description here

I want to use the binary image for OCR but it's too noisy. Is there any way to remove the noise from the binary image in python? I already tried fastNlMeansDenoising from openCV but it doesn't make a difference.

P.S better options for binarization are welcome as well

Upvotes: 6

Views: 11204

Answers (3)

Cris Luengo
Cris Luengo

Reputation: 60494

You should start by adjusting the parameters to the adaptive threshold so it uses a larger area. That way it won't be segmenting out noise. Whenever your output image has more noise than the input image, you know you're doing something wrong.

I suggest as an adaptive threshold to use a closing (on the input grey-value image) with a structuring element just large enough to remove all the text. The difference between this result and the input image is exactly all the text. You can then apply a regular threshold to this difference.

Upvotes: 2

p13rr0m
p13rr0m

Reputation: 1297

It is also possible using GraphCuts for this kind of task. You will need to install the maxflow library in order to run the code. I quickly copied the code from their tutorial and modified it, so you could run it more easily. Just play around with the smoothing parameter to increase or decrease the denoising of the image.

import cv2
import numpy as np
import matplotlib.pyplot as plt
import maxflow 

# Important parameter
# Higher values means making the image smoother
smoothing = 110

# Load the image and convert it to grayscale image 
image_path = 'your_image.png'
img = cv2.imread('image_path')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = 255 * (img > 128).astype(np.uint8)

# Create the graph.
g = maxflow.Graph[int]()
# Add the nodes. nodeids has the identifiers of the nodes in the grid.
nodeids = g.add_grid_nodes(img.shape)
# Add non-terminal edges with the same capacity.
g.add_grid_edges(nodeids, smoothing)
# Add the terminal edges. The image pixels are the capacities
# of the edges from the source node. The inverted image pixels
# are the capacities of the edges to the sink node.
g.add_grid_tedges(nodeids, img, 255-img)

# Find the maximum flow.
g.maxflow()
# Get the segments of the nodes in the grid.
sgm = g.get_grid_segments(nodeids)

# The labels should be 1 where sgm is False and 0 otherwise.
img_denoised = np.logical_not(sgm).astype(np.uint8) * 255

# Show the result.
plt.subplot(121)
plt.imshow(img, cmap='gray')
plt.title('Binary image')
plt.subplot(122)
plt.title('Denoised binary image')
plt.imshow(img_denoised, cmap='gray')
plt.show()

# Save denoised image
cv2.imwrite('img_denoised.png', img_denoised)

Result

Upvotes: 4

aclown
aclown

Reputation: 101

You could try the morphological transformation close to remove small "holes". First define a kernel using numpy, you might need to play around with the size. Choose the size of the kernel as big as your noise.

kernel = np.ones((5,5),np.uint8)

Then run the morphologyEx using the kernel.

denoised = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)

If text gets removed you can try to erode the image, this will "grow" the black pixels. If the noise is as big as the data, this method will not help.

erosion = cv2.erode(img,kernel,iterations = 1)

Upvotes: 0

Related Questions