4

I'm trying to get the edges of this object from a TEM(microscope) image and the problem is that the contact is low especially in the upper edge, I tried several things thresholding, contrast equalization... but I wasn't able to get the upper edge.

N.B: I'm trying to calculate the angle between the droplet and the tube I'm not sure if this is the best way to approach this problem.

The original image:

enter image description here

The Canny Edge detection I get:

enter image description here

the steps I got to get this result are:

  1. Contrast enhancement
  2. Thresholding
  3. Gauss filter
  4. Canny Edge detection

Code:

clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(grid_size, grid_size))
equ = clahe.apply(img)
val = filters.threshold_otsu(equ)
mask = img < val
# denoising part
mask = filters.gaussian(mask,sigma=sigmaG)
# edge detection
edge = feature.canny(mask,sigma=sigmaC)
edge = img_as_ubyte(edge)
Red
  • 26,798
  • 7
  • 36
  • 58
Khalil.h
  • 65
  • 1
  • 6
  • You could try using [difference of gaussians](https://imgur.com/a/YUtbaUt) and then edge detect on the result. – forgetso Apr 09 '21 at 10:31
  • It is a little miracle that you can get something from this horribly noisy image. You will improve by reducing the image size (blur and decimate). –  Apr 09 '21 at 19:36

1 Answers1

2

We have this image and we want to detect the edges of the microphone:

enter image description here

Basically, I converted the image to grayscale, added a Gaussian blur, and detected the edges using the canny edge detector. One more important part is to fill in the gaps in the detected edges by dilating the edges and then eroding them.

All of the above is implemented in the process function; the draw_contours function basically utilizes the process function, and detects the greatest contour:

import cv2
import numpy as np

def process(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_blur = cv2.GaussianBlur(img_gray, (11, 11), 7)
    img_canny = cv2.Canny(img_blur, 0, 42)
    kernel = np.ones((19, 19))
    img_dilate = cv2.dilate(img_canny, kernel, iterations=4)
    img_erode = cv2.erode(img_dilate, kernel, iterations=4)
    return img_erode

def draw_contours(img):
    contours, hierarchies = cv2.findContours(process(img), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cnt = max(contours, key=cv2.contourArea)
    peri = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.004 * peri, True)
    cv2.drawContours(img, [approx], -1, (255, 255, 0), 2)

img = cv2.imread("image.jpg")
h, w, c = img.shape

img = cv2.resize(img, (w // 2, h // 2))
draw_contours(img)

cv2.imshow("Image", img)
cv2.waitKey(0)

Output:

enter image description here

You can omit the drop by tweaking some values int the process function. For example, the values

def process(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_blur = cv2.GaussianBlur(img_gray, (11, 11), 10)
    img_canny = cv2.Canny(img_blur, 0, 38)
    kernel = np.ones((13, 13))
    img_dilate = cv2.dilate(img_canny, kernel, iterations=3)
    img_erode = cv2.erode(img_dilate, kernel, iterations=4)
    return img_erode

Output:

enter image description here

Red
  • 26,798
  • 7
  • 36
  • 58