0

I'm looking for a example of code/library using Python to convert a 2D shape to 1D space based on following steps:

  1. Find the centroid of the shape.
  2. By choosing the centroid as a reference origin, unwrap the outer contour counterclockwise to turn it into a distance signal that is composed of all between each boundary pixel and the centroid (like the image)

Convert 2d shape to 1d space

Thank you!

Tony TRAN
  • 2,118
  • 1
  • 15
  • 16
  • Don't know if it helps, but center of mass can be calculated with scipy: https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.ndimage.measurements.center_of_mass.html Scipy also has a module for calculating distance between two points in an array: https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.distance.cdist.html#scipy.spatial.distance.cdist – BoboDarph Dec 04 '17 at 10:35
  • Also note that Countours in OpenCV might be better tailored to your needs: http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.html – BoboDarph Dec 04 '17 at 10:42
  • Thank you, Bobo. I will check it. Seem it could help. – Tony TRAN Dec 05 '17 at 01:12
  • Are you trying to use this as a shape descriptor for shape matching? – dhanushka Dec 05 '17 at 11:37
  • @dhanushka it is shape descriptor, bro. The image a will be convert to image b. – Tony TRAN Dec 05 '17 at 14:07

1 Answers1

3

I did something like this a while back for fun, inspired by a Kaggle competition on leaf classification. I used opencv for finding the contours of the images. Below is the code for python 2.7. See here for the orientation of the returned contour. You may have to adapt it for your needs, specifically the thresholding part. Hope this helps.

import cv2
import numpy as np
import matplotlib.pyplot as plt


def shape_desc(im):
    # threshold image
    _, bw = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY)
    # find contours
    contours, hierarchy = cv2.findContours(im.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    # extract largest contour
    largest_idx = np.argmax([len(contours[i]) for i in range(0, len(contours))])
    # get (x,y) coordinates
    x = np.array([contours[largest_idx][i][0][0] for i in range(0, len(contours[largest_idx]))], dtype = np.float).reshape((len(contours[largest_idx]), 1))
    y = np.array([contours[largest_idx][i][0][1] for i in range(0, len(contours[largest_idx]))], dtype = np.float).reshape((len(contours[largest_idx]), 1))
    # find the centroid
    m = cv2.moments(np.array([[x[i][0], y[i][0]] for i in range(0, len(x))]).reshape((-1, 1 ,2)).astype(np.int32))
    x_bar = m['m10']/m['m00']
    y_bar = m['m01']/m['m00']

    x_1 = np.array([i[0] for i in x])
    y_1 = np.array([i[0] for i in y])
    # take the centroid as the reference
    x = x_1 - x_bar
    y = y_1 - y_bar

    return np.sqrt(x*x + y*y)

Here are the results of applying this for the following images that are similar in shape. Note that the images and plots have been rescaled.

filename = '19.jpg'
im = cv2.imread(filename, 0)

desc = shape_desc(im)
plt.stem(desc)

1619 plot16plot19

dhanushka
  • 10,492
  • 2
  • 37
  • 47