I'm working on surface roughness of an image, and I used the edge detection function from opencv, but it also detected the pores from the image. Is there a way to get rid of the pores?
picture of original image and the edges detected
I tried adjusting the threshold values but that only got rid of the edges on the side and made the pores more pronounced. I´m pretty new to opencv and this type of problem, so most of this code is just based on examples I saw online.
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
from scipy import ndimage
# need to add the scale to it
img = cv.imread('testim5.png', cv.IMREAD_GRAYSCALE)
blurred = ndimage.filters.gaussian_filter(img, 2, mode='nearest')
edges = cv.Canny(blurred,100,200) # adjusting thresholds will only eliminate the outside edges, not the pores
[testim5.png] https://i.sstatic.net/Vs6K8.png
First, you could use morphological operations to ensure that the interesting edges are connected. You can read more about morphological operations in the web of OpenCV: https://docs.opencv.org/4.x/d9/d61/tutorial_py_morphological_ops.html.
The code would be:
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
from scipy import ndimage
# Open the image
img = cv.imread('testim5.png', cv.IMREAD_GRAYSCALE)
# Note that `scipy.ndimage.filters.gaussian_filter` is deprecated, use `scipy.ndimage.gaussian_filter` instead
blurred = ndimage.gaussian_filter(img, 2, mode='nearest')
edges = cv.Canny(blurred,100,175)
# Apply morphological operation (closing) to the EDGES so they are connected
kernel = np.ones((5,3),np.uint8)
edges_closing = cv.morphologyEx(edges, cv.MORPH_CLOSE, kernel)
The result of this is that the vertical edges aren't so disjoint, as you can see in the following image.
The second step is to remove the pores. It can be seen as a problem of removing small connected objects and the solution of @Soltius in How to remove small connected objects using OpenCV works well.
The code in your case would be:
# Remove smallest connected components
# To understand the following lines, look the answer of @Soltius in https://stackoverflow.com/questions/42798659/how-to-remove-small-connected-objects-using-opencv
nb_blobs, im_with_separated_blobs, stats, _ = cv.connectedComponentsWithStats(edges_closing)
sizes = stats[:, -1]
sizes = sizes[1:]
nb_blobs -= 1
# Minimum size of particles we want to keep (number of pixels).
# Here, it's a fixed value, but you can set it as you want.
min_size = 80
final_edges = np.zeros_like(im_with_separated_blobs)
for blob in range(nb_blobs):
if sizes[blob] >= min_size:
final_edges[im_with_separated_blobs == blob + 1] = 255
fig, axs = plt.subplots(ncols=3)
axs[0].imshow(img, cmap='gray')
axs[1].imshow(edges, cmap='gray')
axs[2].imshow(final_edges, cmap='gray')
axs[0].set_title('Original image')
axs[1].set_title('Original edges')
axs[2].set_title('New edges')
fig.tight_layout()
plt.show()
The final edges are: