Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert image contours to polar coordinates

I'm trying to categorize the type of jigsaw puzzle pieces (number of heads, if it is a border or a corner...) by analyzing their contours.

The approach I'm trying to follow is analyzing this type of plot (from this paper) that "unwinds" the cartesian coordinates of the contours of the puzzle piece by converting it to polar coordinates; however I'm not able to replicate it.

polar plot of puzzle pieces coordinates

I've tried with:

import cv2
import matplotlib.pyplot as plt

def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return(rho, phi)

# load image and find contours
img = cv2.imread("example.png", cv2.IMREAD_GRAYSCALE)
contours, _ = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# get contour points in polar coordinates
rhos = []
for i in range(len(contours[0])):
    x, y = contours[0][i][0]
    rho, _ = cart2pol(x, y)
    rhos.append(rho)

plt.show()
plt.plot(rhos)

but that produces a different plot, like this:

plot of distance by center

from this image:

jigsaw puzzle piece

Trying this on other images I can see how the peaks and valleys correspond to heads and holes of the pieces, but I would like a plot (not properly a function from what I see) like the one above. Can you help me to get that?

like image 809
rikyeah Avatar asked Oct 24 '25 16:10

rikyeah


2 Answers

Find the center of the tile:

M = cv2.moments(contours[0])
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])

Calculate the vectors from the center to the points on the contour and convert the vectors to polar coordinates:

ds, phis = [], []
for i in range(len(contours[0])):
    x, y = contours[0][i][0]
    d, rho = cart2pol(x-cx, y-cy)
    ds.append(d)
    phis.append(rho)

Plot the polar coordinates with angle on the x-axis and distance on the y-axis:

plt.plot(phis, ds)

Complete example:

import os
os.chdir(os.path.abspath(os.path.dirname(__file__)))
import cv2
import matplotlib.pyplot as plt
import numpy as np

def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return (rho, phi)

img = cv2.imread('opencv_so_9_example.png', cv2.IMREAD_GRAYSCALE)
contours, _ = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

M = cv2.moments(contours[0])
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])

polar = [cart2pol(c[0][0] - cx, c[0][1] - cy) for c in contours[0][:]]
max_i = polar.index(max(polar, key = lambda x: x[1]))
polar = polar[max_i:] + polar[:max_i]
ds, phis = zip(*polar)

plt.gcf().set_size_inches(6, 3)     
plt.plot(phis, ds)
plt.show()
like image 164
Rabbid76 Avatar answered Oct 26 '25 05:10

Rabbid76


One can also do this with the binary image and warpPolar in Python/OpenCV.

Input:

enter image description here

import cv2
import numpy as np
import math

# read image
img = cv2.imread('puzzle.png')
ht, wd = img.shape[:2]

# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

 # get non-zero points (i.e. white)
points = np.column_stack(np.where(thresh.transpose() > 0))

# get centroid
M = cv2.moments(points)
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"]) 

# compute maxradius = furthest corner - center
maxrad = math.sqrt( (wd-cx)*(wd-cx) + (ht-cy)*(ht-cy) )

# convert to polar image relative to centroid
polar1 = cv2.warpPolar(thresh, (ht,wd), (cx,cy), maxrad, cv2.INTER_CUBIC+cv2.WARP_POLAR_LINEAR+cv2.WARP_FILL_OUTLIERS)

# rotate 270 clocwise
polar2 = cv2.rotate(polar1, cv2.ROTATE_90_COUNTERCLOCKWISE)
ht, wd = polar2.shape[:2]

# save image
cv2.imwrite('puzzle_polar1.png',polar1)
cv2.imwrite('puzzle_polar2.png',polar2)

# show the images
cv2.imshow("polar1", polar1)
cv2.imshow("polar2", polar2)
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here

like image 25
fmw42 Avatar answered Oct 26 '25 05:10

fmw42



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!