Mex
Mex

Reputation: 306

Find Line in skeleton Images OpenCV python

I have the following picture:

and I want to find the lines to do some calculations, average length etc ... I tried to use HoughLinesP, but it doesn't find the lines. How can I do?

This is my code:

sk=skeleton(mask);
rows, cols = sk.shape
imgOut=np.zeros((rows,cols,3),np.uint8)
imgOut[:,:,0]=0
imgOut[:,:,1]=0
imgOut[:,:,2]=0


minLineLength = 0
maxLineGap = 0

lines = cv2.HoughLinesP(sk,1,np.pi/180,100,minLineLength,maxLineGap)
for x1,y1,x2,y2 in lines[0]:
    cv2.line(imgOut,(x1,y1),(x2,y2),(0,255,0),2)

print len(lines[0])

cv2.imshow('skel',sk)
cv2.imshow('Line',imgOut)
cv2.imwrite('Out.bmp',imgOut)

Output:

If i change the parameters of HoughLinesP I only get fragments of line, not a solid line.

Upvotes: 3

Views: 4913

Answers (1)

Jiby
Jiby

Reputation: 1885

Although the Hough lines algorithm is meant for lines only (and you're clearly dealing with curves), there might be a way to salvage your attempt, by greatly augmenting the rho and theta parameters.

This should make the curved sides point to the same bin rather than be split in different bins.


EDIT : You have a bit of a problem : OpenCV's definition of cv2.HoughLinesP. From the documentation :

cv2.HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]])

As you might see, the 5th parameter is lines, the output variable. Your call is

cv2.HoughLinesP(sk,1,np.pi/180,100,minLineLength,maxLineGap)
                                   ^^^^^^^^^^^^^
                                   lines         

So your given minLineLength parameter has no effect (it becomes an output variable), and maxLineGap has wrong interpretation too.

I suggest to explicitly write parameter names (without parameter tweaks yet)

cv2.HoughLinesP(sk.astype(np.uint8),rho=1,theta=np.pi/180,threshold=100,
                minLineLength=minLineLength,maxLineGap=maxLineGap)

a bit long to write, but at least OpenCV doesn't mix the parameters anymore

Visualizing the lines

I changed the line color for each line for an easier time visualizing which segment is where :

    color = np.random.uniform(0,255,3)
    cv2.line(imgOut,(x1,y1),(x2,y2),color,2)

Changing parameters

By having less bins for rho and theta (achieved by increasing the parameters) you will have more chances of having the edges of a curve vote for the same line-bin.

Here are some attempts (full code below)

rho=5,theta=np.deg2rad(10),threshold=10,minLineLength=5,maxLineGap=2

Too many lines Too many lines shown. Lowering the parameters

Why skeletonize ?

Your input image (as given) looks like edges are already there. The output of skeletonize is only the central line of edges, which sounds like a positive thing, but for Hough Lines, it means reducing the number of pixels "voting" for line segments.

# sk = skeletonize(mask==255)
sk = mask==255

This didn't change much in specifics, but I thought it couldn't hurt the task at hand.

Why not label ?

What you're trying to get is individual line segments. Why not just label the image ?

from matplotlib import pyplot as plt
from scipy import ndimage 

labels,nblabels = ndimage.label(sk)
plt.imshow(labels,'jet')
plt.show()

Labelled image

By applying a little morphological operators you will get individual lines or in the worst case, line branchings.

Now you can select the lines individually by doing

line = labels == 2 # select the pixels with label 2 only

Applying Hough lines to these might be overkill to untangle them, but you'd have significantly broken down your problems already.

Calculation of metrics is now super easy (see ndimage.measurement documentation) and iteration over arrays is super simple.

Upvotes: 6

Related Questions