Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove noise from threshold image opencv python

Tags:

I am trying to get the corners of the box in image. Following are example images, their threshold results and on the right after the arrow are the results that I need. You might have seen these images before too on slack because I am using these images for my example questions on slack.

enter image description here

Following is the code that allows me reach till the middle image.

import cv2 import numpy as np  img_file = 'C:/Users/box.jpg' img = cv2.imread(img_file, cv2.IMREAD_COLOR) img = cv2.blur(img, (5, 5))  hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) h, s, v = cv2.split(hsv)  thresh0 = cv2.adaptiveThreshold(s, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) thresh1 = cv2.adaptiveThreshold(v, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) thresh2 = cv2.adaptiveThreshold(v, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) thresh = cv2.bitwise_or(thresh0, thresh1)  cv2.imshow('Image-thresh0', thresh0) cv2.waitKey(0) cv2.imshow('Image-thresh1', thresh1) cv2.waitKey(0) cv2.imshow('Image-thresh2', thresh2) cv2.waitKey(0) 

Is there any method in opencv that can do it for me. I tried dilation cv2.dilate() and erosion cv2.erode() but it doesn't work in my cases.Or if not then what could be alternative ways of doing it ? Thanks

Canny version of the image ... On the left with low threshold and on the right with high threshold

enter image description here

like image 434
muazfaiz Avatar asked Feb 06 '17 10:02

muazfaiz


People also ask

How do I remove noise from an image in Python?

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.

How do you remove salt and pepper noise from OpenCV?

We can remove salt and pepper noise by using median filter.

What is fastNlMeansDenoisingColored?

1. cv.fastNlMeansDenoisingColored() As mentioned above it is used to remove noise from color images. ( Noise is expected to be gaussian).


2 Answers

Below is a python implementation of @dhanushka's approach

import cv2 import numpy as np  # load color image im = cv2.imread('input.jpg')  # smooth the image with alternative closing and opening # with an enlarging kernel morph = im.copy()  kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1)) morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel) morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)  kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))  # take morphological gradient gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)  # split the gradient image into channels image_channels = np.split(np.asarray(gradient_image), 3, axis=2)  channel_height, channel_width, _ = image_channels[0].shape  # apply Otsu threshold to each channel for i in range(0, 3):     _, image_channels[i] = cv2.threshold(~image_channels[i], 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)     image_channels[i] = np.reshape(image_channels[i], newshape=(channel_height, channel_width, 1))  # merge the channels image_channels = np.concatenate((image_channels[0], image_channels[1], image_channels[2]), axis=2)  # save the denoised image cv2.imwrite('output.jpg', image_channels) 

The above code doesn't give good results if the image you are dealing are invoices(or has large amount of text on a white background). In order to get good results on such images, remove

gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel) 

and pass morph obj to the split function and remove the ~ symbol inside for loop

like image 96
Shreesha N Avatar answered Sep 28 '22 03:09

Shreesha N


You can smooth the image to some degree by applying alternative morphological closing and opening operations with an enlarging structuring element.Here are the original and smoothed versions.

imsmooth im2smooth2

Then take the morphological gradient of the image.

grad grad2

Then apply Otsu threshold to each of the channels, and merge those channels.

merged merged2

If your image sizes are different (larger), you might want to either change some of the parameters of the code or resize the images roughly to the sizes used here. The code is in c++ but it won't be difficult to port it to python.

/* load color image */ Mat im = imread(INPUT_FOLDER_PATH + string("2.jpg")); /*  smooth the image with alternative closing and opening with an enlarging kernel */ Mat morph = im.clone(); for (int r = 1; r < 4; r++) {     Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(2*r+1, 2*r+1));     morphologyEx(morph, morph, CV_MOP_CLOSE, kernel);     morphologyEx(morph, morph, CV_MOP_OPEN, kernel); } /* take morphological gradient */ Mat mgrad; Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3)); morphologyEx(morph, mgrad, CV_MOP_GRADIENT, kernel);  Mat ch[3], merged; /* split the gradient image into channels */ split(mgrad, ch); /* apply Otsu threshold to each channel */ threshold(ch[0], ch[0], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); threshold(ch[1], ch[1], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); threshold(ch[2], ch[2], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); /* merge the channels */ merge(ch, 3, merged); 
like image 34
dhanushka Avatar answered Sep 28 '22 02:09

dhanushka