python中ransac算法擬合圓的實(shí)現(xiàn)
RANSAC為Random Sample Consensus隨機(jī)樣本一致算法的縮寫,它是根據(jù)一組包含異常數(shù)據(jù)的樣本數(shù)據(jù)集,計算出數(shù)據(jù)的數(shù)學(xué)模型參數(shù),得到有效樣本數(shù)據(jù)的算法。它于1981年由Fischler和Bolles最先提出。
RANSAC算法經(jīng)常用于計算機(jī)視覺中。例如,在立體視覺領(lǐng)域中同時解決一對相機(jī)的匹配點(diǎn)問題及基本矩陣的計算。
算法流程
RANSAC 通過反復(fù)選擇數(shù)據(jù)中的一組隨機(jī)子集來達(dá)成目標(biāo)。被選取的子集被假設(shè)為局內(nèi)點(diǎn),并用下述方法進(jìn)行驗(yàn)證:
- 一個模型適用于假設(shè)的局內(nèi)點(diǎn),即所有的未知參數(shù)都能從假設(shè)的局內(nèi)點(diǎn)計算得出。
- 用1中得到的模型去測試所有的其它數(shù)據(jù),如果某個點(diǎn)適用于估計的模型,認(rèn)為它也是局內(nèi)點(diǎn)。
- 如果有足夠多的點(diǎn)被歸類為假設(shè)的局內(nèi)點(diǎn),那么估計的模型就足夠合理。
- 然后,用所有假設(shè)的局內(nèi)點(diǎn)去重新估計模型,因?yàn)樗鼉H僅被初始的假設(shè)局內(nèi)點(diǎn)估計過。
- 最后,通過估計局內(nèi)點(diǎn)與模型的錯誤率來評估模型。
算法的問題
- 隨機(jī)找點(diǎn)作為“內(nèi)點(diǎn)”多少有點(diǎn)隨機(jī)。但這個會影響算法嘛?有更好的辦法嘛?
- 如何判斷模型好壞?
- 如何設(shè)置內(nèi)外點(diǎn)的判斷條件?
迭代次數(shù)推導(dǎo)
迭代的次數(shù),是可以估算出來的。假設(shè)“內(nèi)點(diǎn)”在數(shù)據(jù)中的占比為p:
“內(nèi)點(diǎn)”的概率 p 通常是一個先驗(yàn)值。然后z是我們希望 RANSAC 得到正確模型的概率。如果事先不知道p的值,可以使用自適應(yīng)迭代次數(shù)的方法。也就是一開始設(shè)定一個無窮大的迭代次數(shù),然后每次更新模型參數(shù)估計的時候,用當(dāng)前的“內(nèi)點(diǎn)”比值當(dāng)成p來估算出迭代次數(shù)。
python擬合平面圓
import numpy as np import matplotlib.pyplot as plt def fit_circle(points): """Fit a circle to the given points using least squares method.""" x, y = points[:, 0], points[:, 1] A = np.vstack([-x, -y, np.ones(len(x))]).T #print(A.shape) B = -np.array([x ** 2 + y ** 2]).T # print(B.shape) C_matrix = A.T.dot(A) result = np.linalg.inv(C_matrix).dot(A.T.dot(B)) #print(result.shape) center = [result[0] * 0.5, result[1] * 0.5] return center, np.sqrt(center[0] ** 2 + center[1] ** 2 - result[2]) # (x-a)^2+(y-b)*2=^2 # x^2 + a^2 - 2ax + y^2 + b^2 - 2bx =r^2 # -2ax -2by + a^2 + b^2 - r^2 = - (x^2 + y^2) # [-x -y 1] [2a 2b (a^2 + b^2 - r^2) ] = - (x^2 + y^2) #center = np.linalg.lstsq(A, y, rcond=None)[0] #radius = np.sqrt((center[0]**2 + center[1]**2 - (x**2 + y**2).mean())**2) #return center, radius def ransac_circle(points, max_trials=1000, threshold=1): """Fit a circle to points using the RANSAC algorithm.""" best_fit = 0 best_error = np.inf n_points = len(points) for _ in range(max_trials): sample_indices = np.random.choice(n_points, 3, replace=False) sample_points = points[sample_indices] center, radius = fit_circle(sample_points) # Calculate distance from each point to the fitted circle distances = np.sqrt((points[:, 0] - center[0])**2 + (points[:, 1] - center[1])**2) # - radius inliers = np.logical_and( np.abs(distances) <= (radius + threshold) , np.abs(distances) >= (radius - threshold)) # Check if this is the best fit so far if sum(inliers) > best_fit: best_fit = sum(inliers) center, radius = fit_circle(points[inliers]) best_center = center best_radius = radius best_inliers = inliers return best_center, best_radius, best_inliers # Generate some example data points including noise # np.random.seed(0) n_samples = 100 true_center = (1, 0) true_radius = 10 angles = np.linspace(0, 2 * np.pi, n_samples) true_points = np.vstack([true_center[0] + true_radius * np.cos(angles), true_center[1] + true_radius * np.sin(angles)]).T noise = np.random.normal(size=(n_samples, 2), scale=1) points = true_points + noise # Fit circle using RANSAC center, radius, inliers = ransac_circle(points, max_trials=1000, threshold=1.5) # Plot results print(f"true_center {true_center}, true_radius {true_radius} ") print(f"center {center}, radius {radius} ") plt.figure(figsize=(5, 5)) plt.scatter(points[:, 0], points[:, 1], label='Data Points') plt.scatter(points[inliers, 0], points[inliers, 1], color='red', label='Inliers') plt.scatter([center[0]], [center[1]], color='black') theta = np.linspace(0, 2 * np.pi, 100) plt.plot(center[0] + radius * np.cos(theta), center[1] + radius * np.sin(theta), label='Fitted Circle') plt.legend(loc='upper right') plt.show()
擬合直線
import numpy as np import matplotlib.pyplot as plt import random import math # 數(shù)據(jù)量。 SIZE = 50 # 產(chǎn)生數(shù)據(jù)。np.linspace 返回一個一維數(shù)組,SIZE指定數(shù)組長度。 # 數(shù)組最小值是0,最大值是10。所有元素間隔相等。 X = np.linspace(0, 10, SIZE) Y = 3 * X + 10 fig = plt.figure() # 畫圖區(qū)域分成1行1列。選擇第一塊區(qū)域。 ax1 = fig.add_subplot(1,1, 1) # 標(biāo)題 ax1.set_title("RANSAC") # 讓散點(diǎn)圖的數(shù)據(jù)更加隨機(jī)并且添加一些噪聲。 random_x = [] random_y = [] # 添加直線隨機(jī)噪聲 for i in range(SIZE): random_x.append(X[i] + random.uniform(-0.5, 0.5)) random_y.append(Y[i] + random.uniform(-0.5, 0.5)) # 添加隨機(jī)噪聲 for i in range(SIZE): random_x.append(random.uniform(0,10)) random_y.append(random.uniform(10,40)) RANDOM_X = np.array(random_x) # 散點(diǎn)圖的橫軸。 RANDOM_Y = np.array(random_y) # 散點(diǎn)圖的縱軸。 # 畫散點(diǎn)圖。 ax1.scatter(RANDOM_X, RANDOM_Y) # 橫軸名稱。 ax1.set_xlabel("x") # 縱軸名稱。 ax1.set_ylabel("y") # 使用RANSAC算法估算模型 # 迭代最大次數(shù),每次得到更好的估計會優(yōu)化iters的數(shù)值 iters = 100000 # 數(shù)據(jù)和模型之間可接受的差值 sigma = 1 # 最好模型的參數(shù)估計和內(nèi)點(diǎn)數(shù)目 best_a = 0 best_b = 0 pretotal = 0 # 保存的最好的內(nèi)點(diǎn) best_inner_x = [] best_inner_y = [] # 希望的得到正確模型的概率 P = 0.99 for i in range(iters): print("i", i) # 隨機(jī)在數(shù)據(jù)中紅選出兩個點(diǎn)去求解模型 sample_index = random.sample(range(SIZE * 2),2) x_1 = RANDOM_X[sample_index[0]] x_2 = RANDOM_X[sample_index[1]] y_1 = RANDOM_Y[sample_index[0]] y_2 = RANDOM_Y[sample_index[1]] # y = ax + b 求解出a,b a = (y_2 - y_1) / (x_2 - x_1) b = y_1 - a * x_1 # 算出內(nèi)點(diǎn)數(shù)目 total_inlier = 0 best_inner_x_dummpy = [] best_inner_y_dummpy = [] for index in range(SIZE * 2): y_estimate = a * RANDOM_X[index] + b if abs(y_estimate - RANDOM_Y[index]) < sigma: best_inner_x_dummpy.append(RANDOM_X[index]) best_inner_y_dummpy.append(RANDOM_Y[index]) total_inlier = total_inlier + 1 # 判斷當(dāng)前的模型是否比之前估算的模型好 if total_inlier > pretotal: iters = math.log(1 - P) / math.log(1 - pow(total_inlier / (SIZE * 2), 2)) pretotal = total_inlier best_a = a best_b = b best_inner_x = best_inner_x_dummpy best_inner_y = best_inner_y_dummpy print(f"iters {iters}, pretotal {pretotal}, best_a {best_a}, best_b {best_b}") if i >= iters: break # 用我們得到的最佳估計畫圖 Y = best_a * RANDOM_X + best_b # 直線圖 ax1.plot(RANDOM_X, Y) # 畫散點(diǎn)圖。 ax1.scatter(best_inner_x, best_inner_y) text = "best_a = " + str(best_a) + "\nbest_b = " + str(best_b) plt.text(5,10, text, fontdict={'size': 8, 'color': 'r'}) plt.show()
到此這篇關(guān)于python中ransac算法擬合圓的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)python ransac擬合圓內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python標(biāo)準(zhǔn)庫之sqlite3使用實(shí)例
這篇文章主要介紹了Python標(biāo)準(zhǔn)庫之sqlite3使用實(shí)例,本文講解了創(chuàng)建數(shù)據(jù)庫、插入數(shù)據(jù)、查詢數(shù)據(jù)、更新與刪除數(shù)據(jù)操作實(shí)例,需要的朋友可以參考下2014-11-11詳解django的serializer序列化model幾種方法
序列化是將對象狀態(tài)轉(zhuǎn)換為可保持或傳輸?shù)母袷降倪^程。這篇文章主要介紹了詳解django的serializer序列化model幾種方法。具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-10-10詳細(xì)解析Python當(dāng)中的數(shù)據(jù)類型和變量
這篇文章主要介紹了Python當(dāng)中的數(shù)據(jù)類型和變量,是Python學(xué)習(xí)當(dāng)中的基礎(chǔ)知識,需要的朋友可以參考下2015-04-04解決Pyinstaller 打包exe文件 取消dos窗口(黑框框)的問題
今天小編就為大家分享一篇解決Pyinstaller 打包exe文件 取消dos窗口(黑框框)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06Python實(shí)現(xiàn)在tkinter中使用matplotlib繪制圖形的方法示例
這篇文章主要介紹了Python實(shí)現(xiàn)在tkinter中使用matplotlib繪制圖形的方法,結(jié)合實(shí)例形式分析了Python使用tkinter與matplotlib進(jìn)行正弦曲線圖形繪制的相關(guān)操作技巧,需要的朋友可以參考下2018-01-01