2017-04-20 22 views
0

我想通過圖像中的各個點來適應飛機,但我遇到了強制通過圖像中特定點的線的問題。特別是當線是90度時會發生這種情況。如何正確合適一條線,並強制它通過圖像中的特定點?

我的代碼如下:

I = [3 3 3 3 3 2 2 
    3 3 3 3 2 2 2 
    3 3 3 3 2 2 2 
    3 3 1 2 2 2 2 
    1 1 1 2 2 2 2 
    1 1 1 1 1 2 2 
    1 1 1 1 1 1 1]; 

% force the line through point p 
p = [3,3]; 

% points to fit plane through 
edgeA = [3,3.5; 3,4; 2.5,4; 2,4; 1.5,4]; 
edgeB = [3.5,3; 4,3; 4.5,3; 5,3]; 


% fit a plane through p and edgeA 
xws = [p(2), edgeA(:,2)']'; 
yws = [p(1), edgeA(:,1)']'; 
Cws = [xws ones(size(xws))]; 
dws = yws; 
Aeqws = [p(2) 1]; 
beqws = [p(1)]; 

planefitA = lsqlin(Cws ,dws,[],[],Aeqws, beqws); 


% fit a plane through p and edgeB 
xwn = [p(2), edgeB(:,2)']'; 
ywn = [p(1), edgeB(:,1)']'; 
Cwn = [xwn ones(size(xwn))]; 
dwn = ywn; 
Aeqwn = [p(2) 1]; 
beqwn = [p(1)]; 

planefitB = lsqlin(Cwn ,dwn,[],[],Aeqwn, beqwn); 



%%%%% plot the fitted planes: 
xAxis = linspace(0, size(I, 2), 12); 

%obtain linear curve 
fA = planefitA(1)*xAxis + planefitA(2); 
fB = planefitB(1)*xAxis + planefitB(2); 

%plot the fitted curve 
RI = imref2d(size(I),[0 size(I, 2)],[0 size(I, 1)]); 
figure, imshow(I, RI, [], 'InitialMagnification','fit')  
grid on; 
hold on; 
plot(xAxis,fA, 'Color', 'b', 'linewidth', 2); 
plot(xAxis,fB, 'Color', 'r', 'linewidth', 2); 

所有點edgeB落在一個90 degrees line。但是,該功能最終會通過這些點擬合錯誤的線條。我知道這是因爲使用

planefitB = polyfit([p(2), edgeB(:,2)'], [p(1), edgeB(:,1)'], 1); 

作品這一行,但問題是,我有這些過程中我的形象反覆在不同的位置太多次,所以我不知道怎樣建議polyfit當行會是90度。

請問,我有什麼想法/建議可以使這項工作?非常感謝。

+0

我正在努力與你的詞彙有點。你正在交換'line'和'plane'。看起來你想讓(3,3)點完全在線,並且最小平方適合其他噪點? – Peter

+0

飛機在哪裏?一切看起來像2d? polyfit從哪裏來?這與你在上面做的約束優化有什麼關係? 「我」是什麼?我沒有看到它在任何地方使用 – Peter

+0

@彼得感謝您的回覆。是的,一切都是二維的,我現在沒有數據,但稍後會添加第三個維度。其次,就像你說的那樣,我希望線條穿過點(3,3),並且通過其他點適合最小二乘方。第三,'edgeB'數據中的所有點是共線的,因此在這種情況下使用'polyfit'不是不合適的。最後,「我」是形象;所有數據點都來自'I',如果你運行代碼,你會看到'I'的使用。 – User110

回答

0

這相當於只有線的角度的最小二乘解。偏移量是由它必須經過的事實確定的(3,3)。表達這個最簡單的方法是通過已知道口來抵消數據點。也就是說,從您的數據點中減去(3,3),並將最好的m代入y=mx,將b固定爲0.

對於非垂直情況,可以使用經典最小二乘公式,但不要將常數1加到範德蒙矩陣中:

slope = (edgeA(:,2) - p(2)) \ (edgeA(:,1) - p(1)); 

這給出了與約束lsq解決方案完全相同的答案。

現在對於垂直線:非垂直線可以用y = mx的標準函數形式表示,其中最小二乘方公式隱含地假設獨立變量和因變量。一條垂直線並不遵循這一點,所以唯一的一般選擇是「總體最小二乘」公式,其中考慮了兩個變量的誤差,而不僅僅是依賴(y)變量中的殘差。

最簡單的寫法是在最小二乘意義上選擇a和b來最小化ax - by。 [x_k -y_k]*[a b].'應儘可能接近零矢量。這是最接近[x -y]矩陣的零空間的矢量,可以用svd計算。交換列和捏造的跡象讓我們只需直接使用SVD:

[u s v] = svd(bsxfun(@minus, edgeA, p)); 

v的最後一列是最接近於零空間,所以映射回您的X/Y的定義,(edgeA-P)×V( :,2)是線,所以y乘數在頂部位置,而x在下部,帶有符號翻轉。要轉換爲表達式y = mx形式,只是劃分:

slope = -v(2,2)/v(1,2); 

注意,這個答案會比普通最小二乘回答有點不同,因爲你是區別對待的殘差。而且,由於我們已經討論過的原因(它產生Inf),計算「斜率」的最後一步在垂直情況下將不起作用,所以你最好離開線作爲標準化的2矢量,沒有任何角落案例。