FarthestPointSampling(FPS)算法學習&實踐

最近工作需要用到最遠點采樣fps算法, 找了一些blog學習學習, 寫了個原型:

def distance(p1, p2):
    return np.sqrt(np.sum((p1 - p2)**2))

def FPS(sample, num, center_idx: int = 0):
    '''sample:采樣點云數(shù)據(jù),
    num:需要采樣的數(shù)據(jù)點個數(shù)'''
    n = sample.shape[0]
    select_p = [center_idx]  # 儲存采集點索引
    L = np.full(n, 1e20, dtype=np.float64)
    for i in range(num - 1):
        for p in range(n):
            d = distance(sample[select_p[-1]], sample[p])
            if d < L[p]:
                L[p] = d
        select_p.append(np.argmax(L).item())
    return select_p

測試一下, 跑的沒問題, 但是速度感人

所有點的歐氏距離計算做個向量化優(yōu)化:

def fps(points, n_samples, first_idx: int = 0):
    """
    points: (N, D) array of points
    n_samples: number of points to sample
    first_idx: index of first point to sample
    """
    N = points.shape[0]
    selected_indices = [first_idx]
    distances = np.full(N, np.inf)

    for _ in range(n_samples - 1):
        # 計算所有點到最新選擇點的距離
        last_selected = points[selected_indices[-1]]
        dist = np.sum((points - last_selected) ** 2, axis=1)

        # 更新最小距離
        distances = np.minimum(distances, dist)

        # 選擇距離最大的點
        new_idx = np.argmax(distances).item()
        selected_indices.append(new_idx)

        distances[new_idx] = 0

    return selected_indices

這一下子快了100多倍, 能用了
找了個開源基于rust實現(xiàn)核心的python接口包: https://github.com/leonardodalinky/fpsample

對比了一下結(jié)果, 是沒問題的, 但是他比我這個快個4,5倍
最后借助ai優(yōu)化一下:

def fps_optimized(points, n_samples, first_idx: int = 0):
    """
    Optimized FPS implementation
    points: (N, D) array of points
    n_samples: number of points to sample
    first_idx: index of first point to sample
    """
    N = points.shape[0]
    selected_indices = np.zeros(n_samples, dtype=np.int64)
    distances = np.full(N, np.inf)
    selected_indices[0] = first_idx

    # 預計算點的平方和,避免重復計算
    point_squares = np.sum(points ** 2, axis=1)

    for i in range(1, n_samples):
        last_selected = points[selected_indices[i - 1]]

        # 使用廣播來計算距離,避免創(chuàng)建臨時數(shù)組
        # ||a-b||^2 = ||a||^2 + ||b||^2 - 2<a,b>
        dist = point_squares + np.sum(last_selected ** 2) - 2 * np.dot(points, last_selected)

        # 更新最小距離
        np.minimum(distances, dist, out=distances)

        # 選擇距離最大的點
        new_idx = np.argmax(distances)
        selected_indices[i] = new_idx
        distances[new_idx] = 0

    return selected_indices.tolist()

又快了6,7倍, 中小規(guī)模點云用這個看起來就沒啥問題了
后面如果有超大規(guī)模的需求或許可以關(guān)注fpsample作者的另一個repo: https://github.com/leonardodalinky/pytorch_fpsample

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容