pythonopencvimage-processingcontourx-ray

Contour Axis for Image


For a radiographic scan, I have been able to acquire the contours.

I would be interested to find the center axis. How could I do it in python?

enter image description here

Here is my code for contours:

import cv2


img = cv2.imread("A.png")


imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(img,60,200)

contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

hierarchy = hierarchy[0]


cv2.drawContours(img, contours, -1, (255,0,0), 3)

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Solution

  • I am probably making this world a slightly worse place by answering a "gimme the working Python code" type of "question", but then again, I myself need to use PCA from time to time and can never remember the correct way of using it, so this may serve as a little memo.

    Let's say we have a black and white image of a separate toe bone contour:

    enter image description here

    Let's find the bone direction with PCA:

    import cv2
    import numpy as np
    
    #loading our BW image
    img = cv2.imread("test_images/toe.bmp", 0)
    h, w = img.shape
    
    #From a matrix of pixels to a matrix of coordinates of non-black points.
    #(note: mind the col/row order, pixels are accessed as [row, col]
    #but when we draw, it's (x, y), so have to swap here or there)
    mat = np.argwhere(img != 0)
    mat[:, [0, 1]] = mat[:, [1, 0]]
    mat = np.array(mat).astype(np.float32) #have to convert type for PCA
    
    #mean (e. g. the geometrical center) 
    #and eigenvectors (e. g. directions of principal components)
    m, e = cv2.PCACompute(mat, mean = np.array([]))
    
    #now to draw: let's scale our primary axis by 100, 
    #and the secondary by 50
    center = tuple(m[0])
    endpoint1 = tuple(m[0] + e[0]*100)
    endpoint2 = tuple(m[0] + e[1]*50)
    
    cv2.circle(img, center, 5, 255)
    cv2.line(img, center, endpoint1, 255)
    cv2.line(img, center, endpoint2, 255)
    cv2.imwrite("out.bmp", img)
    

    The result:

    enter image description here

    How about a different bone? Hard to see the lines, but still works:

    enter image description here