使用 RANSAC 進行穩健的線模型估計#

在這個範例中,我們將看到如何使用 RANSAC(隨機樣本共識)演算法,將線模型穩健地擬合到有缺陷的資料。

首先,資料是透過在線性函數中加入高斯雜訊產生的。然後,將離群值點加入資料集中。

RANSAC 反覆從資料集中估計參數。在每次迭代時,都會執行下列步驟

  1. 從原始資料中選擇 min_samples 個隨機樣本,並檢查資料集是否有效(請參閱 is_data_valid 選項)。

  2. 在隨機子集上估計模型(model_cls.estimate(*data[random_subset]),並檢查估計的模型是否有效(請參閱 is_model_valid 選項)。

  3. 透過使用估計的模型計算殘差(model_cls.residuals(*data))將所有資料點分類為內點或離群值 - 所有殘差小於 residual_threshold 的資料樣本都會被視為內點。

  4. 如果內點樣本的數量大於以往,則將估計的模型儲存為最佳模型。如果目前估計的模型具有相同數量的內點,則只有在殘差總和小於的情況下,才會將其視為最佳模型。

這些步驟會執行最大次數,或直到滿足其中一個特殊停止條件為止。最後的模型是使用先前確定的最佳模型的所有內點樣本估計的。

import numpy as np
from matplotlib import pyplot as plt

from skimage.measure import LineModelND, ransac

rng = np.random.default_rng()

# generate coordinates of line
x = np.arange(-200, 200)
y = 0.2 * x + 20
data = np.column_stack([x, y])

# add gaussian noise to coordinates
noise = rng.normal(size=data.shape)
data += 0.5 * noise
data[::2] += 5 * noise[::2]
data[::4] += 20 * noise[::4]

# add faulty data
faulty = np.array(30 * [(180.0, -100)])
faulty += 10 * rng.normal(size=faulty.shape)
data[: faulty.shape[0]] = faulty

# fit line using all data
model = LineModelND()
model.estimate(data)

# robustly fit line only using inlier data with RANSAC algorithm
model_robust, inliers = ransac(
    data, LineModelND, min_samples=2, residual_threshold=1, max_trials=1000
)
outliers = inliers == False

# generate coordinates of estimated models
line_x = np.arange(-250, 250)
line_y = model.predict_y(line_x)
line_y_robust = model_robust.predict_y(line_x)

fig, ax = plt.subplots()
ax.plot(data[inliers, 0], data[inliers, 1], '.b', alpha=0.6, label='Inlier data')
ax.plot(data[outliers, 0], data[outliers, 1], '.r', alpha=0.6, label='Outlier data')
ax.plot(line_x, line_y, '-k', label='Line model from all data')
ax.plot(line_x, line_y_robust, '-b', label='Robust line model')
ax.legend(loc='lower left')
plt.show()
plot ransac

現在,我們將此範例推廣到 3D 點。

import numpy as np
from matplotlib import pyplot as plt
from skimage.measure import LineModelND, ransac


# generate coordinates of line
point = np.array([0, 0, 0], dtype='float')
direction = np.array([1, 1, 1], dtype='float') / np.sqrt(3)
xyz = point + 10 * np.arange(-100, 100)[..., np.newaxis] * direction

# add gaussian noise to coordinates
noise = rng.normal(size=xyz.shape)
xyz += 0.5 * noise
xyz[::2] += 20 * noise[::2]
xyz[::4] += 100 * noise[::4]

# robustly fit line only using inlier data with RANSAC algorithm
model_robust, inliers = ransac(
    xyz, LineModelND, min_samples=2, residual_threshold=1, max_trials=1000
)
outliers = inliers == False

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(
    xyz[inliers][:, 0],
    xyz[inliers][:, 1],
    xyz[inliers][:, 2],
    c='b',
    marker='o',
    label='Inlier data',
)
ax.scatter(
    xyz[outliers][:, 0],
    xyz[outliers][:, 1],
    xyz[outliers][:, 2],
    c='r',
    marker='o',
    label='Outlier data',
)
ax.legend(loc='lower left')
plt.show()
plot ransac

指令碼的總執行時間:(0 分鐘 0.527 秒)

由 Sphinx-Gallery 產生的圖庫