簡體   English   中英

將固定矩形擬合到點集

[英]Fit fixed rectangle to set of points

我想知道是否每個人都試圖將固定大小的矩形適合給定的一組點。

假設您有一組未排序的點,並不總是顯示矩形的完整外殼。 下圖應該可以說明問題: 在此處輸入圖像描述

點集可能會有所不同,並且點可能會丟失。 我想找到一種最小二乘法來找到具有固定邊長的最佳擬合矩形。

也許我可以先找到回歸線,但它可能以不同的方式到達 go。

我會很感激任何提示。

只是解決方案的概述:

  1. 你的矩形的高度和寬度是固定的,所以你可以用三個參數(x0,y0,theta)來定義它:比如左下角和旋轉。
  2. 使用距離 function 就像pnt2line給出的pnt2line http://www.fundza.com/vectors/point2line/index.html
  3. 現在編寫一個包裝器 function:對於每個點,計算到矩形所有四個邊的距離,並將distance[i]指定為這四個距離中的最小值
  4. scipy.optimize.curve_fit中使用此distance數組來找到最適合的參數

如果有異常值,RANSAC 可以成為你的好朋友。 要進行擬合,您需要從不同側面取三個點。 因此,只需選擇三個隨機點並假設其中兩個屬於一側,另一個屬於正交側。 找到姿勢參數沒什么大不了的。 您可以按照@VBB 的描述從距離 function 計算擬合誤差(對於每個點,到邊的距離最短)。

根據您的喜好,您可以一次使用相同的三個點,並進行任意的邊分配,或者嘗試不同的分配並保持最佳狀態。

對於內點的最終擬合,您可以使用一個技巧。

  • 將每個內點分配給最近的一側;

  • 將每一側的簇集中在其各自的質心上;

  • 將每隔一邊的簇旋轉90°;

  • 這會產生一個單一方向的單一集群; 執行普通線擬合以獲得該方向。

定義position P處的固定大小矩形R(P)與點Q之間的距離d(R(P), Q)為連接兩者的最短直線的長度。 這很容易定義為 function 案例推理。

現在只需使用某種形式的梯度下降來找到最佳 P*,使點集中 Q 的 d(R(P*), Q)^2 之和最小化。

我找不到它所以自己寫了一個代碼。 您可以使用最小二乘矩形來擬合它。

參考結果

import torch
import numpy as np
import matplotlib.pyplot as plt

import cv2

import matplotlib.pyplot as plt

def plot_graph(X,Y, slopes,constants):
  plt.plot(X,Y,"go")
  
  def abline(slope, intercept):
    """Plot a line from slope and intercept"""
    axes = plt.gca()
    x_vals = np.array(axes.get_xlim())
    y_vals = intercept + slope * x_vals
    plt.plot(x_vals, y_vals, '--')

  abline(float(slopes[0]),float(constants[0]))
  abline(float(slopes[0]),float(constants[2]))
  abline(float(slopes[1]),float(constants[1]))
  abline(float(slopes[1]),float(constants[3]))  
  plt.show()

points = torch.tensor([[0,2],[2,0],[0.5,1.5],[1,1],[2,2],[3,3],[3,0.8],[2.5,3.5],[2,4],[3,1.5],[0,2.3],[1.5,3],[1,3]])

Y = points[:,1]
X = points[:,0]
learning_rate = 0.01

epochs = 10000
n = X.shape[0]

import cv2
import numpy as np

rect = cv2.minAreaRect(np.array(points))
m = np.tan(np.pi*rect[2]/180)
slope = torch.tensor([[m]],requires_grad=True)
box = cv2.boxPoints(rect)

c0 = box[0][1] - (m*box[0][0])
c1 = box[0][1] + (box[0][0]/m)
c2 = box[2][1] - (m* box[2][0])
c3 = box[2][1] + (box[2][0]/m)

constants = torch.tensor([[c0],[c1],[c2],[c3]],requires_grad=True)
# slope = torch.rand([1,1],requires_grad=True)
# constants = torch.rand([4,1],requires_grad=True)

for i in range(epochs):

  slopes = torch.cat((slope,-1/slope) ,0)
  num  = abs(torch.cat((Y - slopes*X, Y - slopes*X), 0) - constants)
  den = torch.cat((torch.sqrt(1 + slopes*slopes), torch.sqrt(1 + slopes*slopes)), 0)
  distances = num/den
  dists_min = torch.amin(distances,0).sum()/n
  dists_min.backward()

  if i % 1000 == 0:
    print(i) 

  if i%1000==0:
    plot_graph(X,Y, slopes,constants)

  with torch.no_grad():
      slope -= learning_rate * slope.grad
      constants -= learning_rate *10* constants.grad
      
      slope.grad.zero_()
      constants.grad.zero_()

Github - https://github.com/PuneetMadan9/fitting_least_square_rectangle/blob/main/least_square_rectangle.py谷歌 Colab - https://colab.research.google.com/drive/1VyxJGLfKkzFuN-MF_38J-Y_Rqroll#bTJqroll#

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM