OpenCV erode what kernel to choose? - python

I'm trying to erode my image:
in order to get something close to this (my goal):
I use this basic kernel of OpenCV
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
image_1 = cv2.erode(gray_overlay, kernel, iterations=1)
I know there are custom kernels, I have tried kernels with different weights, different sizes, but I can't get a satisfactory result (separation of squares without losing too much white surface)
Could someone advise me on a kernel?
Thanks you! :)

You may use wide and short kernel (shape of a horizontal line).
By trial and error, I found that kernel size 21x2 gives the best results (if don't care about overfitting the kernel to the input).
For keeping the white surface, you need to apply eroding and then dilation.
The morphological operation of eroding and than dilation is named "closing".
Here is a code sample:
import cv2
gray_overlay = cv2.imread("image.png", cv2.IMREAD_GRAYSCALE) # Read image as grayscale.
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 2))
# Erode then dilate
image_1 = cv2.erode(gray_overlay, kernel)
image_2 = cv2.dilate(image_1, kernel)
# Erode then dilate is called "open"
image_3 = cv2.morphologyEx(gray_overlay, cv2.MORPH_OPEN, kernel)
cv2.imshow('gray_overlay', gray_overlay)
cv2.imshow('image_1', image_1)
cv2.imshow('image_2', image_2)
cv2.imshow('image_3', image_3)
cv2.waitKey()
cv2.destroyAllWindows()
Results:
image_1 (after erode):
image_2 (after erode and dilate):
image_3 (after closing):

If you are not concerned about the specific shapes of the boxes and only care about the gaps between them, you should try morphological opening instead of applying erosion only.
Try this:
import cv2 as cv
image = cv.imread("image.png")
kernel = np.ones((9, 9), np.uint8)
eroded_image = cv.erode(image, kernel, iterations = 2)
dilated_image = cv.dilate(eroded_image, kernel, iterations = 2)
You can adjust the size of the kernel and the number of iterations to manipulate the final output.
You can also use:
cv.morphologyEx(image, cv.MORPH_OPEN, kernel)

Related

Remove noise from image using OpenCV

I have these images
enter image description here
enter image description here
I want to remove noise from these images so I can convert them into text using pytesseract. The noise is only in blue colour so I tried to remove blue from the image. Still not good results.
This is what I did
import cv2
import pytesseract
# Extract the blue channel
blue = img[:, :, 0]
# Apply thresholding to the blue channel
thresh = cv2.threshold(blue, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
# Perform morphological operations to remove noise
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,1))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=7)
# Apply blur to smooth out the image
blur = opening#cv2.medianBlur(opening, 1)
cv2.imwrite("/Users/arjunmalik/Desktop/blur.png",blur)
display("/Users/arjunmalik/Desktop/blur.png")
The result was
enter image description here
The OCR results were FL1S4y.
As stated by Sembei, You need to use a closing operator which's a must for a situation like this because you want to close black points on the object to improve the image quality.
Solution:
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4,4))
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)
You can modify your code to this one to achieve the following output for the second image.
Output:
Result
You might need to change the size of the kernel for different input images.
Thoughts:
I think it'd be better if you do the character segmentation first before applying the closing operator in order to achieve the finest results.

How to decide on the kernel to use for dilations (OpenCV/Python)?

I'm very new to OpenCV and recently, I'm trying to compare two images of rails, one with a train and one without. After the comparison, I apply a threshold, and there are some 'holes' in the white regions which I do not want. Currently, I am using dilation with 4 iterations and kernel set to "None", which defaults to a 3x3 by my understanding.
How do I decide what sort of kernel to use so that the dilation does a better job at making the white region continuous? Would also be nice if I could remove the small white blobs in the background. Here is the code:
resized = imutils.resize(img2, width=1050)
resized2 = imutils.resize(img3, width=1050)
grayA = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(resized2, cv2.COLOR_BGR2GRAY)
grayA = cv2.GaussianBlur(grayA,(7,7),0)
grayB = cv2.GaussianBlur(grayB,(7,7),0)
frameDelta = cv2.absdiff(grayA, grayB)
thresh = cv2.threshold(frameDelta, 20, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=4)
Complete beginner in this, so even general tips/advice to improve these comparisons would be vastly appreciated!
Perhaps this will give you some idea about morphology in Python/OpenCV. First I use a square "open" kernel about the size of the small white spots to remove them. Then I use a horizontal rectangle "close" kernel about the size of the black gap to fill it. "Open" removes white regions (or fills black gaps) and close removes black regions (or fills white gaps)
Input:
import cv2
import numpy as np
# read image as grayscale
img = cv2.imread('blob3.png', cv2.IMREAD_GRAYSCALE)
# threshold to binary
thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY)[1]
# apply morphology open with square kernel to remove small white spots
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (19,19))
morph1 = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# apply morphology close with horizontal rectangle kernel to fill horizontal gap
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (101,1))
morph2 = cv2.morphologyEx(morph1, cv2.MORPH_CLOSE, kernel)
# write results
cv2.imwrite("blob3_morph1.png", morph1)
cv2.imwrite("blob3_morph2.png", morph2)
# show results
cv2.imshow("thresh", thresh)
cv2.imshow("morph1", morph1)
cv2.imshow("morph2", morph2)
cv2.waitKey(0)
Morphology Square Open:
Morphology Rectangle Close:
Alternate Morphology Square Close:

Where exactly to use Morphological Operations (Dilation, Erosion, Opening or Closing) while binarizing image using OpenCv

I have built a code for Image Binarization and it works kind of well but the texts in my binary images either get too big or there's some white noise in them. What I want to do it to try Erosion, Dilation, Opening, Closing individually and then see which one is improving the results for me. Where should I use these morphological operations in my code. For example In Between Sharpened and binary image or between division and sharpened?
import numpy as np
import cv2
import skimage.filters as filters
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
smooth = cv2.GaussianBlur(gray, (93,93), 0,)
division = cv2.divide(gray, smooth, scale=255)
# kernel = np.ones((5,5),np.uint8) # use operations here
# opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
sharp = filters.unsharp_mask(division, radius=1.5, amount=1.5, multichannel=False, preserve_range=False)
sharp = (255*sharp).clip(0,255).astype(np.uint8)
# kernel = np.ones((5,5),np.uint8) # or here
# opening = cv2.morphologyEx(sharp, cv2.MORPH_OPEN, kernel)
thresh = cv2.threshold(sharp, 0, 255, cv2.THRESH_OTSU )[1]

How to smooth and make thinner these very rough images using OpenCV?

I have some black and white images of a single digit. I am using a NN model trained on MNIST to classify them. However, the digits are too rough and thick compared to the MNIST dataset. For example:
TLDR: I need to smoothen image and possibly make overall shape thinner using OpenCV.
You can use a combination of morphology close, open and erode (and optionally skeletonize and dilate) in Python/OpenCV as follows:
Input:
import cv2
import numpy as np
from skimage.morphology import skeletonize
# load image
img = cv2.imread("5.png")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold image
thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)[1]
# apply morphology close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology open
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# apply morphology erode
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (21,21))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_ERODE, kernel)
# write result to disk
cv2.imwrite("5_thinned.png", thresh)
# skeletonize image and dilate
skeleton = cv2.threshold(thresh,0,1,cv2.THRESH_BINARY)[1]
skeleton = (255*skeletonize(skeleton)).astype(np.uint8)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15,15))
skeleton_dilated = cv2.morphologyEx(skeleton, cv2.MORPH_DILATE, kernel)
# write result to disk
cv2.imwrite("5_skeleton_dilated.png", skeleton_dilated)
cv2.imshow("IMAGE", img)
cv2.imshow("RESULT1", thresh)
cv2.imshow("RESULT2", skeleton_dilated)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result1 (close, open, erode):
Result2 (close, open, erode, skeletonize, dilate):
You will most likely benefit from morphological operations. Specifically it sounds like you want erosion.
You do have some noise though. You should try OpenCV's smoothing operations. Based on my experience, I think you need to use a median blur with a kernel area of maybe around 9 (although it depends on what you want). Then you need to use erode.

Python connecting divided contours on image

HERE is the 6 contours in different color.
I want to connecting two biggest part.
In the image green and blue parts.
Is there any algorithms or library to handle this problem??
Using the dilate function mentioned earlier in addition to using the closing operations will most likely yield the best results.
import cv2
import numpy as np
image = cv2.imread("images/S1lTI.png")
cv2.imshow('Original', image)
cv2.waitKey(0)
kernel = np.ones((5,5), np.uint8)
dilation = cv2.dilate(image, kernel, iterations = 3)
cv2.imshow('Dilation', dilation)
cv2.waitKey(0)
closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Closing', closing)
cv2.waitKey(0)

Categories