Python connecting divided contours on image - python

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)

Related

OpenCV erode what kernel to choose?

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)

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 remove noise in image OpenCV, Python?

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.
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)
I need smooth values, Decimal separator(dot) and postfix letters. How can I do this?
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:
You can do slightly better using division normalization in Python/OpenCV.
Input:
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:
Thresholded Image:
Morphology Cleaned Image:
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.
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

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.

smoothen edges of pixelated binary image python code

I'm using pytesseract to convert images into text, however the accuracy isn't 100% since the images pixelate on resizing. Applying gaussian blur would smoothen the edges but blur the image making it impossible for OCR to detect text.
What sort of filter would smoothen the edges without blurring the image too much. The image looks something like this
Image
You can median blur image then try a series of morphological transformations, specifically cv2.MORPH_CLOSE with a 3x3 kernel seems to work well here. You can play with the kernel size and number of iterations to get desired results
import cv2
image = cv2.imread('1.png')
blur = cv2.medianBlur(image, 7)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,125, 255,cv2.THRESH_BINARY_INV)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
result = 255 - close
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('result', result)
cv2.imwrite('result.png', result)
cv2.waitKey()

Categories