3
$\begingroup$

I'm doing a personal project in which I want to select some very specific lines in a microscopy image. The first picture is the raw image, the second picture is the image for the lines (in yellow) I would like to detect. Not straight lines yes, but lines indeed.

1st image, no lines detected

Lines of interest in yellow

Now, I made a very basic code for line detection that kind of "works" detecting lines, but it takes a lot of undesired detected lines in the process. See an example with another image (and the code below it, in Python, using OpenCV).

Outcome of my code

import cv2 as cv
import numpy as np

#Load and normalize .tif image:
img = 'imagenes.tif'
img = cv.imread(img, 0)
img_scaled = cv.normalize(img,  np.zeros((800, 800)), 0, 255, cv.NORM_MINMAX)

#Resizing images:
pct = 30
w = int(img.shape[1] * pct / 100)
h = int(img.shape[0] * pct / 100)
dim = (w, h)
resized = cv.resize(img_scaled, dim, interpolation = cv.INTER_AREA)

# First stage: Gaussian blur.
gaussian = cv.GaussianBlur(resized,(5, 5),0)
# Second Stage: edge detection with Canny.
low_threshold = 90
high_threshold = 150
edges = cv.Canny(gaussian, low_threshold, high_threshold)
# Third stage: Hough Line transform.
rho = 1
theta = np.pi / 180
threshold = 15
minLineLenght = 15
maxLineGap = 15
myBlankLines = resized.copy()
lines = cv.HoughLinesP(edges, rho, theta, threshold, np.array([]),
                    minLineLenght, maxLineGap)
for line in lines:
    for x1,y1,x2,y2 in line:
        cv.line(myBlankLines,(x1,y1),(x2,y2),(255,0,0),5)


cv.imshow('image_resized', resized)
cv.imshow('Stage 1: Gaussian', gaussian)
cv.imshow('Stage 2: Edges', edges)
cv.imshow('Stage 3: Lines', myBlankLines)
cv.waitKey(0)
cv.destroyAllWindows()

Now. I don't mind building a filter from zero and avoid using OpenCV or any other image processing/computer vision library. But I feel a bit lost on what direction I should go. I'm not sure if:

  1. Doing more pre-filtering.
  2. Adjust parameters for Hough Lines Transform.
  3. Something else related with Machine Learning perhaps.

What would you suggest? Thanks for any heads up you might have on this interesting task.

$\endgroup$

2 Answers 2

2
$\begingroup$

Instead of using a homegrown amalgamation of algorithms, I suggest you look in the scientific literature for existing solutions. People have solved the same problem over and over again, there exist many algorithms to detect lines.

One very popular such method is Frangi's vesselness measure (A.F. Frangi et al, “Multiscale Vessel Enhancement Filtering”, MICCAI 1998). There is an implementation in DIPlib (disclaimer: I wrote this implementation).

You can install DIPlib with pip install diplib. This code shows how to use it, including a second step where the (gray-scale) vesselness measure is thresholded:

import diplib as dip

img = dip.ImageRead('cfqZG.png')(1)

vesselness = dip.FrangiVesselness(img, sigmas=2.0, polarity='black')
out = dip.HysteresisThreshold(vesselness, 0.01, 0.15)

dip.Overlay(img, out).Show()

output of code above

Tweaking parameters in the code will give you more or fewer of the lines.

If you need thinner lines, simply add a thinning step (dip.ConditionalThinning2D).

$\endgroup$
1
$\begingroup$
  • I used Median Blur instead of Gaussian Blur, and used Sobel Filter to detect the edges, the results are not perfect, but you can improve them if you tuned the parameters well(and they are many!)

Result

#==================
# Import Libraries
#==================
import numpy as np
import cv2
import matplotlib.pyplot as plt

# Read Image
img = cv2.imread('1.png', 0)

# Median Blur
img = cv2.medianBlur(img, 3)

# Sobel filter for Edge detection
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
sobel = np.sqrt(sobelx**2+sobely**2)

# Threshold Sobel to locate the lines
maxi = 0.30*sobel.max()
sobel[sobel<maxi] = 0

# Normalize
sobel = (255*sobel) / (sobel.max()-sobel.min())
sobel = sobel.astype('uint8')

# Hough Line transform.
rho = 1
theta = np.pi / 180
threshold = 15
minLineLenght = 18
maxLineGap = 13
myBlankLines = img.copy()
lines = cv2.HoughLinesP(sobel, rho, theta, threshold, np.array([]),
                    minLineLenght, maxLineGap)
for line in lines:
    for x1,y1,x2,y2 in line:
        cv2.line(myBlankLines,(x1,y1),(x2,y2),(255,0,0),1)

# Visualize Results
plt.imshow(myBlankLines, cmap='gray')
plt.axis('off')
plt.show()
$\endgroup$
2
  • $\begingroup$ What you call "tunning the parameter well" will indeed be a key factor, the thing is I'm not sure what are the best and most convenient settings. I would love to read any suggestions for literature on this matternof course. $\endgroup$ Nov 6, 2020 at 13:57
  • $\begingroup$ @AquilesPáez The problem description isn't very clear to me, there are many lines in the image that you can spot visually, but you don't want them in your desired output, can you please specify on which basis did you chose only those desired specific lines? I mean in which manner they differ from the other lines? $\endgroup$
    – Bilal
    Nov 6, 2020 at 14:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.