%pylab inline
from skimage import io
import matplotlib.pyplot as plt

"""
Explanation: Computer Vision for Image Feature Extraction
End of explanation
"""


image = io.imread('uploads/df947b7905ec613a239a1c4d531e8eab45ccbd6d.jpg')

from skimage.transform import rescale
small = rescale(image, 0.1)

imshow(small)

from skimage.color import rgb2gray
gray = rgb2gray(small)
imshow(gray)

"""
Explanation: A smaller size allows computation intensive algoritms to run reasonably on a PC
End of explanation
"""


from skimage.filters import gaussian_filter
blurry = gaussian_filter(gray, 2)
imshow(blurry)

from skimage.feature import canny
# Don't use the blurry image
edges = canny(gray, sigma=2)
imshow(edges)

"""
Explanation: Part of the canny edge detection algorithm is a gaussian blur.
This image is just to demonstrate that gaussian blur reduces noise while keeping major edges intact.
End of explanation
"""


from skimage.transform import hough_circle

hough_radii = np.arange(15, 30)
hough_res = hough_circle(edges, hough_radii)

"""
Explanation: Hough Transforms
Finds circles (or ellipsis) in images
End of explanation
"""


from skimage.feature import peak_local_max
from skimage.draw import circle_perimeter
from skimage.color import gray2rgb

centers = []
accums = []
radii = []

for radius, h in zip(hough_radii, hough_res):
    # For each radius, extract two circles
    num_peaks = 2
    peaks = peak_local_max(h, num_peaks=num_peaks)
    centers.extend(peaks)
    accums.extend(h[peaks[:, 0], peaks[:, 1]])
    radii.extend([radius] * num_peaks)

coin_center = 0
coin_radius = 0
    
# Draw the most prominent 5 circles
gray_copy = gray2rgb(gray)
for idx in np.argsort(accums)[::-1][:1]:
    coin_center = centers[idx]
    center_x, center_y = centers[idx]
    coin_radius = radii[idx]
    cx, cy = circle_perimeter(center_y, center_x, coin_radius)
    gray_copy[cy, cx] = (220, 20, 20)

imshow(gray_copy)

"""
Explanation: This is largely a sorting and aggregation step
End of explanation
"""


from skimage.exposure import equalize_hist

equal = equalize_hist(gray)
imshow(equal)

"""
Explanation: Equalizes the histogram of the image to stretch image across the spectrum
End of explanation
"""


y,x = np.ogrid[:gray.shape[0],:gray.shape[1]]
cx = 90
cy = 45
radius = 30
r2 = (x-cx)*(x-cx) + (y-cy)*(y-cy)

mask = r2 <= radius * radius


"""
Explanation: On the server the center (cx, cy) and the radius is retrieved from the user
End of explanation
"""


from skimage.feature import canny

mole_edge = canny(equal, sigma=2, mask=mask)
imshow(mole_edge)

from skimage.measure import find_contours
contours = find_contours(mole_edge, 0.9, fully_connected='high')

fig, ax = plt.subplots()
ax.imshow(equal, interpolation='nearest', cmap=plt.cm.gray)

ax.plot(contours[0][:, 1], contours[0][:, 0], linewidth=1)

from mahotas.polygon import fill_polygon
from skimage.transform import resize

canvas = np.zeros((gray.shape[0], gray.shape[1]))
fill_polygon(contours[0].astype(np.int), canvas)

import numpy.ma as ma
from skimage.color import rgb2hsv

hsv = rgb2hsv(small)

deviations = []
for color in (0,1,2):
    masked = ma.array(hsv[:,:,color], mask=~canvas.astype(np.bool))
    deviations.append(masked.std())
    
print(deviations)

"""
Explanation: We surveyed several algorithms:
Canny -> Marching Squares -> Fill Polygon 
Faired the best
End of explanation
"""


from skimage.measure import CircleModel

circle_model = CircleModel()
circle_model.estimate(contours[0])
symmetry = circle_model.residuals(contours[0]).mean()
print(symmetry)

diameter = (19.05 / coin_radius) * (circle_model.params[2])
print(diameter )

from skimage.draw import circle
from skimage.color import gray2rgb
gray_copy = gray2rgb(gray)
cx, cy = circle(circle_model.params[1], circle_model.params[0], circle_model.params[2])
gray_copy[cy, cx] = (220, 20, 20)
center_x, center_y = coin_center
cx, cy = circle(center_y, center_x, coin_radius)
gray_copy[cy, cx] = (220, 20, 20)
imshow(gray_copy)

"""
Explanation: Circle estimation is a suboptimal measure for symmetry, but sufficient for our purposes.
End of explanation
"""


