CV2 morphology open does not work as expected - python

I have a problem with OpenCV where the function morphology opening is not working as expected. As you can see in image below, the morphology opening of the image cause the thresholded pattern to move down and right.
Do you have some idea why this moving of the pattern occurs?
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("originalImg.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh1 = cv2.threshold(img,0,255,cv2.THRESH_TRIANGLE)
print("Calculated threshold", ret)
f, axarr = plt.subplots(1,5)
kernel = np.ones((2,2),np.uint8)
thresh = thresh/255
opened = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
axarr[0].imshow(img,cmap='gray')
axarr[0].set_title('original image')
axarr[1].imshow(thresh1,cmap='gray')
axarr[1].set_title('threshold triangle')
axarr[2].imshow(opened,cmap='gray')
axarr[2].set_title('morphology open')
plt.show()
Generated images: https://imgur.com/a/N6RMy4T.

Related

Seeds segmentation in OpenCV/Python

I know that this topic has been covered before but I'm stuck.
I'm quite new and I trying to segment a seeds using Python and OpenCV
Here is my steps
And now I'm stuck on how to separate the 3 seeds in the center of the image. Then I use the distance transformation, but the result is not satisfactory (why it is hardly visible?). I don't know how to proceed further. I would like to achive something like this.
Distance transform
In more circular object dt works well but not in my case.
My code:
import cv2
from google.colab.patches import cv2_imshow
import numpy as np
img = cv2.imread('connected_seeds.jpg')
img = cv2.resize(img,(600,400))
# Gray scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Blur image
blur_img = cv2.medianBlur(gray, 7)
# Thresholding
ret, thresh = cv2.threshold(blur_img, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Closing
kernel = np.ones((5,5), np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
sure_bg = cv2.dilate(closing,kernel,iterations=2)
# Distance transform
dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform,0.5*dist_transform.max(),255,0)
here is the article I'm following:
https://learning.rc.virginia.edu/notes/opencv/

Detection and segmentation of region of interest from X-ray images

I am working on some Xray images and I want to detect and segment region of interest from the image.
Consider input image
I want to detect square like shapes in the image, as highlighted in the image
Output: region of interest will somehow look like this
This is my code which I have done so far
import cv2
import numpy as np
import pandas as pd
import os
from PIL import Image
import matplotlib.pyplot as plt
from skimage.io import imread, imshow
img = cv2.imread('image.jpg',0)
imshow(img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imshow(gray)
equ = cv2.equalizeHist(img)
imshow(equ)
img_resize = cv2.resize(img, (300, 300))
print(img_resize.shape)
figure_size = 9
new_image_gauss = cv2.GaussianBlur(img_resize, (figure_size, figure_size),0)
imshow(new_image_gauss)
img_edge = cv2.Canny(equ,100,200)
# show the image edges on the newly created image window
imshow(img_edge)
kernel = np.ones((5,5), np.uint8)
img_erosion = cv2.erode(img_edge, kernel, iterations=1)
img_dilation = cv2.dilate(img_edge, kernel, iterations=1)
imshow(img_erosion)
Results which I have got;
Please guide me.
TIA
One thing that might help is to do morphology gradient on your image to emphasize the edges in Python OpenCV before you do your Canny edge detection.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread("xray2.jpg")
# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# do morphology gradient
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (3,3))
morph = cv2.morphologyEx(gray, cv2.MORPH_GRADIENT, kernel)
# apply gain
morph = cv2.multiply(morph, 5)
# write results
cv2.imwrite("xray2_gradient_edges.jpg",morph)
# show lines
cv2.imshow("morph", morph)
cv2.waitKey(0)

How to remove the noise on the border without losing data in the middle of mask

I am trying to segment out the tissue blobs from the image. I did some initial preprocessing and obtained the following result. My concern is the noise on the borders. If i erode with horizontal/vertical kernel, i loose some data in the middle as well. I am not sure what is a better to achieve the results, or should i go through a different approach for segmentation.
Here is the sample image:
import numpy as np
import os
import matplotlib.pyplot as plt
from skimage import io
from skimage.filters import threshold_mean
from skimage.exposure import adjust_sigmoid, adjust_gamma
from skimage.morphology import opening
from skimage import morphology
import scipy.ndimage as ndi
def create_binary_mask(path_to_file):
file = io.imread(path_to_file)
#APPLY FILTERS FOR BETTER THRESHOLD
img_med = ndi.median_filter(file, size=20) #REDUCE NOISE
adjusted_gamma = adjust_gamma(img_med, 1.8, 2) #INCREASE GAMMA
adjusted_sigmoid = adjust_sigmoid(adjusted_gamma, 0.01) #INCREASE CONTRAST
#DO THE MEAN THRESHOLD
thresh = threshold_mean(adjusted_sigmoid)
binary = adjusted_sigmoid > thresh
#REMOVE SMALL NOISE WITHIN THE IMAGE
disk = morphology.disk(radius=7)
opening = morphology.binary_opening(binary, disk)
fig, axis = plt.subplots(1,4, figsize=(10,10))
axis[0].imshow(file, cmap='gray')
axis[0].set_title('Original File')
axis[1].imshow(adjusted_sigmoid, cmap='gray')
axis[1].set_title('Adjusted Sigmoid')
axis[2].imshow(binary, cmap='gray')
axis[2].set_title('Mean Threshold')
axis[3].imshow(opening, cmap='gray')
axis[3].set_title('After opening')
plt.savefig('results.png')
plt.show()
path_to_file = "sample_img.png"
create_binary_mask(path_to_file)
It might be useful to use attribute operators, specifically skimage.morphology.diameter_opening, to remove long lines while leaving smaller-radius objects untouched. See this example for details:
https://scikit-image.org/docs/dev/auto_examples/filters/plot_attribute_operators.html
You can find a long explanation of how the method works here:
https://scikit-image.org/docs/dev/auto_examples/developers/plot_max_tree.html
A simple approach is to perform morphological closing on the binary image to connect the noise together into a single contour. From here we can find contours and filter using contour area. We can effectively remove the noise on the border by drawing in the contour. Here's the result with the noise colored in with the background color. If you wanted to remove it on the mask you could simply paint it in with black (0,0,0).
import cv2
import numpy as np
# Load image, grayscale, Gaussian blur, adaptive threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7,7), 0)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,61,5)
# Morph close to connect noise
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=5)
# Filter using contour area and fill in contour to remove noise
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area > 250000:
cv2.drawContours(image, [c], -1, (43,43,43), -1)
cv2.imwrite('image.png', image)
cv2.waitKey()

Middle line between 2 contour lines in opencv python?

I have an image
After my code runs,
The new image is
I need to find the line between them like this
How do I do?
My code
import numpy as np
import cv2
import cv2 as cv
ima = cv2.imread('track1.pNg')
imgray = cv2.cvtColor(ima,cv2.COLOR_BGR2GRAY)
im = cv2.cvtColor(ima,cv2.COLOR_BGR2GRAY)
imm = cv2.inRange(im,(0),(49))
kernel = np.ones((5,5),np.uint8)
gradient = cv2.morphologyEx(imm, cv2.MORPH_GRADIENT, kernel)
il = cv2.dilate(gradient, kernel, iterations=7)
ol = cv2.erode(il, kernel, iterations=7)
contours,hei = cv2.findContours(ol,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(ima, contours, -1, (200,255,0), 3)
cv2.imshow('window',ima)
How can i achieve this?
This answer explains how to find a line that runs between two sides of a shape. The center can be found by iteratively eroding the image.
This is the result:
This is the code I used:
import cv2
import numpy as np
img = 255-cv2.imread('/home/stephen/Desktop/PITqe.png',0)
kernel = np.ones((20,20), np.uint8)
img = cv2.erode(img, kernel, iterations=2)
size = np.size(img)
skel = np.zeros(img.shape,np.uint8)
ret,img = cv2.threshold(img,127,255,0)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
done = False
while( not done):
eroded = cv2.erode(img,element)
temp = cv2.dilate(eroded,element)
temp = cv2.subtract(img,temp)
skel = cv2.bitwise_or(skel,temp)
img = eroded.copy()
zeros = size - cv2.countNonZero(img)
cv2.imshow('img', img)
cv2.waitKey(100)
if zeros==size:
done = True
cv2.imshow("img",skel)
cv2.waitKey(0)
cv2.destroyAllWindows()
Here is another way to skeletonize in OpenCV (without explicitly iterating) by using distance transform and top hat morphology.
Input:
import cv2
import numpy as np
# read image and invert so blob is white on black background
img = 255-cv2.imread('tall_blob.png',0)
# do some eroding of img, but not too much
kernel = np.ones((20,20), np.uint8)
img = cv2.erode(img, kernel, iterations=2)
# threshold img
ret, thresh = cv2.threshold(img,127,255,0)
# do distance transform
dist = cv2.distanceTransform(thresh, distanceType=cv2.DIST_L2, maskSize=5)
# set up cross for tophat skeletonization
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
skeleton = cv2.morphologyEx(dist, cv2.MORPH_TOPHAT, kernel)
# threshold skeleton
ret, skeleton = cv2.threshold(skeleton,0,255,0)
# display skeleton
cv2.imshow("skeleton",skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save results
cv2.imwrite('tall_blob_skeleton.png', skeleton)

Detect a scratch on noise image with OpenCV

I am trying to get a small scratch from the noise image as shown. It is quite noticeable by eyes, but I would like to identify it using OpenCV Python.
I tried to use image blurring and subtract it from the original image, and then threshold to get a image as the second.
Could any body please advise to get this scratch?
Original image:
Image after blurring, subtraction, and threshold:
This is how I process this image:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("scratch0.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.blur(gray,(71,71))
diff = cv2.subtract(blur, gray)
ret, th = cv2.threshold(diff, 13, 255, cv2.THRESH_BINARY_INV)
cv2.imshow("threshold", th)
cv2.waitKey(0)

Categories