📚 The CoCalc Library - books, templates and other resources
License: OTHER
123```python4%matplotlib inline5import matplotlib6matplotlib.rcParams['image.cmap'] = 'gray'7matplotlib.rcParams['image.interpolation'] = 'nearest'8```910# RANSAC1112From WikiPedia:1314> Random sample consensus (RANSAC) is an iterative method to estimate15> parameters of a mathematical model from a set of observed data which16> contains outliers. Therefore, it also can be interpreted as an17> outlier detection method.1819[Gallery example](http://scikit-image.org/docs/dev/auto_examples/plot_matching.html)20212223```python24import numpy as np25from matplotlib import pyplot as plt2627from skimage.measure import ransac, LineModelND28```2930Let's set up some random data points:31323334```python35np.random.seed(seed=1)3637# generate coordinates of line38x = np.arange(-200, 200)39y = 0.2 * x + 2040data = np.column_stack([x, y])4142# add faulty data43faulty = np.array(30 * [(180., -100)])44faulty += 5 * np.random.normal(size=faulty.shape)45data[:faulty.shape[0]] = faulty4647# add gaussian noise to coordinates48noise = np.random.normal(size=data.shape)49data += 0.5 * noise50data[::2] += 5 * noise[::2]51data[::4] += 20 * noise[::4]5253plt.plot(data[:, 0], data[:, 1], '.');54```555657585960Now, fit a line to the data. We start with our model:6162$$\mathbf{y} = m \mathbf{x} + c$$6364Or, in matrix notation:6566$$\mathbf{y} = \left[ \begin{array}{c} \vdots \\ \mathbf{x} \\ \vdots \end{array}67\ \begin{array}{c} \vdots \\ \mathbf{1} \\ \vdots \end{array} \right]68\left[ \begin{array}{c} m \\ c \end{array} \right]69= X \mathbf{p}$$7071TODO: the above is not rendered correctly. p is column vector.7273Since we have an over-determined system, we use least squares to solve:74757677```python78x = data[:, 0]79y = data[:, 1]8081X = np.column_stack((x, np.ones_like(x)))8283p, _, _, _ = np.linalg.lstsq(X, y)84p85```8687888990```output91array([ 0.04829453, 12.45526055])92```93949596With those parameters in hand, let's plot the resulting line:979899100```python101m, c = p102plt.plot(x, y, 'b.')103104xx = np.arange(-250, 250)105plt.plot(xx, m * xx + c, 'r-');106```107108109110111112Scikit-image provides an N-dimensional LineModel object that encapsulates the above:113114115116```python117model = LineModelND()118model.estimate(data)119model.params120```121122123124125```output126(array([ 27.3093349 , 13.77415203]), array([-0.99847184, -0.05526279]))127```128129130131Instead of ``m`` and ``c``, it parameterizes the line by ``origin``132and ``direction`` --- much safer when dealing with vertical lines,133e.g.!134135136137```python138origin, direction = model.params139plt.plot(x, y, 'b.')140plt.plot(xx, model.predict_y(xx), 'r-');141```142143144145146147Now, we robustly fit the line using inlier data selecte with the RANSAC algorithm:148149150151```python152model_robust, inliers = ransac(data, LineModelND, min_samples=2,153residual_threshold=10, max_trials=1000)154outliers = (inliers == False)155156yy = model_robust.predict_y(xx)157158fig, ax = plt.subplots()159160ax.plot(data[inliers, 0], data[inliers, 1], '.b', alpha=0.6, label='Inlier data')161ax.plot(data[outliers, 0], data[outliers, 1], '.r', alpha=0.6, label='Outlier data')162ax.plot(xx, yy, '-b', label='Robust line model')163164plt.legend(loc='lower left')165plt.show()166```167168169170171172## Going interplanetary173174The sun is one of the most spherical objects in our solar system.175According to an [article in Scientific American](http://www.scientificamerican.com/gallery/well-rounded-sun-stays-nearly-spherical-even-when-it-freaks-out/):176177> Earth's closest star is one of the roundest objects humans have178> measured. If you shrank the sun down to beach ball size, the179> difference between its north-south and the east-west diameters would180> be thinner than the width of a human hair, says Jeffery Kuhn, a181> physicist and solar researcher at the University of Hawaii at182> Manoa. "Not only is it very round, but it's too round," he adds. The183> sun is more spherical and more invariable than theories predict.184185If the sun is spherical, we should be able to fit a circle to a 2D186slice of it! Let's load an example image:187188189190```python191from skimage import io192193image = io.imread('../../images/superprom_prev.jpg')194195f, ax = plt.subplots(figsize=(8, 8))196ax.imshow(image);197```198199200201202203In this specific image, we got a bit more than we bargained for in the204form of magnificently large solar flares. Let's see if some *canny205edge detection* will help isolate the sun's boundaries.206207208209```python210from skimage import feature, color211212f, ax = plt.subplots(figsize=(10, 10))213214edges = feature.canny(color.rgb2gray(image), sigma=2)215ax.imshow(edges, cmap='gray')216```217218219220221```output222<matplotlib.image.AxesImage at 0x7f99be1dbe48>223```224225226227228229230231The edges look good, but there's a lot going on inside the sun. We232use RANSAC to fit a robust circle model.233234235236```python237from skimage.measure import CircleModel238239points = np.array(np.nonzero(edges)).T240241model_robust, inliers = ransac(points, CircleModel, min_samples=3,242residual_threshold=2, max_trials=1000)243```244245The parameters of the circle are center x, y and radius:246247248249```python250model_robust.params251```252253254255256```output257array([ 287.07798476, 306.07014353, 225.70127981])258```259260261262Let's visualize the results, drawing a circle on the sun, and also263highlighting inlier vs outlier edge pixels:264265266267```python268from skimage import draw269270cy, cx, r = model_robust.params271272f, (ax0, ax1) = plt.subplots(1, 2, figsize=(15, 8))273274ax0.imshow(image)275ax1.imshow(image)276277ax1.plot(points[inliers, 1], points[inliers, 0], 'b.', markersize=1)278ax1.plot(points[~inliers, 1], points[~inliers, 0], 'g.', markersize=1)279ax1.axis('image')280281circle = plt.Circle((cx, cy), radius=r, facecolor='none', linewidth=2)282ax0.add_patch(circle);283```284285286287288289The circular fit is, indeed, excellent, and rejects all the inner290squiggly edges generated by solar turbulence!291292Note a general principle here: algorithms that aggregate across an293entire path are often robust against noise. Here, we have *high294uncertainty* in the solar edge, but also know that only the solar edge295pixels contribute coherently to the full circular path around the296solar edge.297298## Exercises299300Your small start-up, CardShark, run from your garage over nights and301evenings, takes photos of credit cards and turns them into machine302readable information.303304The first step is to identify where in a photo the credit card is305located.3063071. Load the photo `../../images/credit_card.jpg`3082. Using RANSAC and LineModelND shown above, find the first most309prominent edge of the card3103. Remove the datapoints belonging to the most prominent edge, and311repeat the process to find the second, third, and fourth312313314315```python316f, ax = plt.subplots()317318image = io.imread('../../images/credit_card.jpg')319ax.imshow(image);320```321322323324325326----327### Warning: SPOILER ALERT. Solution follows!328----329330331332```python333f, ax = plt.subplots(figsize=(10, 10))334335edges = feature.canny(color.rgb2gray(image), sigma=3)336edge_pts = np.array(np.nonzero(edges), dtype=float).T337edge_pts_xy = edge_pts[:, ::-1]338339for i in range(4):340model_robust, inliers = ransac(edge_pts_xy, LineModelND, min_samples=2,341residual_threshold=1, max_trials=1000)342343x = np.arange(800)344plt.plot(x, model_robust.predict_y(x))345346edge_pts_xy = edge_pts_xy[~inliers]347348plt.imshow(edges);349```350351352353354355356