How to remove noise in image OpenCV, Python?

20,792

Solution 1

Before binarization, it is necessary to correct the nonuniform illumination of the background. For example, like this:

import cv2

image = cv2.imread('9qBsB.jpg')
image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
se=cv2.getStructuringElement(cv2.MORPH_RECT , (8,8))
bg=cv2.morphologyEx(image, cv2.MORPH_DILATE, se)
out_gray=cv2.divide(image, bg, scale=255)
out_binary=cv2.threshold(out_gray, 0, 255, cv2.THRESH_OTSU )[1] 

cv2.imshow('binary', out_binary)  
cv2.imwrite('binary.png',out_binary)

cv2.imshow('gray', out_gray)  
cv2.imwrite('gray.png',out_gray)

Result: enter image description here enter image description here

Solution 2

Im assuming that you are preprocessing the image for OCR(Optical Character Recognition)

I had a project to detect license plates and these were the steps I did, you can apply them to your project. After greying the image try applying equalize histogram to the image, this allows the area's in the image with lower contrast to gain a higher contrast. Then blur the image to reduce the noise in the background. Next apply edge detection on the image, make sure that noise is sufficiently removed as ED is susceptible to it. Lastly, apply closing(dilation then erosion) on the image to close all the small holes inside the words.

Solution 3

You can do slightly better using division normalization in Python/OpenCV.

Input:

enter image description here

import cv2
import numpy as np

# load image
img = cv2.imread("license_plate.jpg")

# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# blur
blur = cv2.GaussianBlur(gray, (0,0), sigmaX=33, sigmaY=33)

# divide
divide = cv2.divide(gray, blur, scale=255)

# otsu threshold
thresh = cv2.threshold(divide, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# write result to disk
cv2.imwrite("hebrew_text_division.jpg", divide)
cv2.imwrite("hebrew_text_division_threshold.jpg", thresh)
cv2.imwrite("hebrew_text_division_morph.jpg", morph)

# display it
cv2.imshow("gray", gray)
cv2.imshow("divide", divide)
cv2.imshow("thresh", thresh)
cv2.imshow("morph", morph)
cv2.waitKey(0)
cv2.destroyAllWindows()

Division Image:

enter image description here

Thresholded Image:

enter image description here

Morphology Cleaned Image:

enter image description here

Solution 4

Instead of erode and dilate, you can check this, that is basically both in one.

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,2))
morphology_img = cv2.morphologyEx(img_grey, cv2.MORPH_OPEN, kernel,iterations=1)
plt.imshow(morphology_img,'Greys_r')

MORPHOLOGICAL_TRANSFORMATIONS

Share:
20,792
Ugurcan
Author by

Ugurcan

Computer Vision Research Engineer who has 3 years hands on experience. Worked on OCR project, medical projects with using machine learning and deep learning.

Updated on November 25, 2021

Comments

  • Ugurcan
    Ugurcan over 2 years

    I have some cropped images and I need images that have black texts on white background. Firstly I apply adaptive thresholding and then I try to remove noise. Although I tried a lot of noise removal techniques but when the image changed, the techniques I used failed.

    enter image description here

    The best method for converting image color to binary for my images is Adaptive Gaussian Thresholding. Here is my code:

    im_gray = cv2.imread("image.jpg",  cv2.IMREAD_GRAYSCALE)
    image = cv2.GaussianBlur(im_gray, (5,5), 1)
    th =  cv2.adaptiveThreshold(image,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,3,2)
    

    enter image description here

    I need smooth values, Decimal separator(dot) and postfix letters. How can I do this?