我一直在尝试在Matlab中实现Beier-Neely变形算法(description)并遇到麻烦。
我大部分时间都在工作,除了最终图像旋转180度,对于非方形图像,目标图像尝试对源图像边界外的像素进行采样。
我对Matlab不是很有经验,所以这可能是一些愚蠢的错误,但是,我已经手工计算了几个像素,并获得了非矩形图像的越界坐标。我不确定我做错了什么,因为我没有在任何其他谈论Beier-Neely的网站上看到过这种行为的提法。
function morphed = bnmorph( im, inputLines, targetLines )
%BNMORPH Takes image and two sets of lines.
% Morphs image from inputLines to targetLines
[xSize,ySize,~] = size(im);
[numPoints,~] = size(targetLines);
numLineSegments = int32(numPoints/2);
% Make sure there are no horizontal or vertical lines
conditionlines(inputLines);
conditionlines(targetLines);
% Preallocate space
morphed = im;
% For each pixel in the destination image, calculate the pixel to
% sample from the source image.
for y = 1:ySize
for x = 1:xSize
X = [x y];
Xsource = zeros(1,2);
dsum = zeros(1,2);
weightsum = 0;
% For each line segment
for i = 1:numLineSegments
% Indices for the endpoints of the segments
i1 = (i-1)*2+1;
i2 = i1 + 1;
% Get Pi, Qi, the end points for the line segment i
% in the dst image
Pi = targetLines(i1, :);
Qi = targetLines(i2, :);
% Get the vector QPi
QPi = Qi - Pi;
% Get Pi', Qi', the end points for the line segment i
% in the src image
Pisource = inputLines(i1,:);
Qisource = inputLines(i2,:);
% Get the vector QPi'
QPisource = Qisource - Pisource;
% Calculate u = (X-Pi).(QPi) / ||QPi||^2
u = dot((X - Pi), QPi) / (QPi(1).^2 + QPi(2).^2);
% Calculate v = (X-Pi).perp(QPi) / ||QPi||
% where perp(QPi) = [-QPi(2), QPi(1)]
v = dot((X - Pi), perp(QPi)) / sqrt(QPi(1).^2 + QPi(2).^2);
% Calculate Xi', the pixel to sample in src image
% Xi' = Pi'+u*QPi' + v*perp(QPi') / ||QPi'||
Xisource = Pisource+u*QPisource+(v*perp(QPisource) / sqrt(QPisource(1).^2 + QPisource(2).^2));
% Add this pixel to the weight
% Does nothing when only one line segment
Di = Xisource - X;
if u < 0
dist = sqrt((X(1)-Pi(1)).^2+(X(2)-Pi(2)).^2);
elseif u > 1
dist = sqrt((X(1)-Qi(1)).^2+(X(2)-Qi(2)).^2);
else
dist = abs(v);
end
length = sqrt(QPi(1).^2 + QPi(2).^2);
p = 0.5; % Defines strength of lines relative to length. Range: [0,1]. If 0, all lines have same weight, if 1, longer lines carry more weight than shorter ones
a = 0.1; % Defines strength of line based on distance from point. Lower values = more control, larger value = more smooth warping
b = 1; % Defines strength fall-off based on distance from point. Good Range: [0.5,2]. If 0, pixel affected by all lines equally, if large, then only affected by nearest lines
weight = (length.^p / (a + dist)).^b;
dsum = dsum + (Di * weight);
weightsum = weightsum + weight;
end
% Calculate final source pixel
% Will equal Xisource when only one line segment
Xsource = X + dsum / weightsum;
% Bounds check to set out of bounds pixels to teal
% Shouldn't be needed as far as I'm aware
[xSize, ySize, ~] = size(im);
nullCol = false;
if int32(Xsource(1)) <= 0
Xsource(1) = 1;
nullCol = true;
elseif int32(Xsource(1)) > xSize
Xsource(1) = xSize;
nullCol = true;
end
if int32(Xsource(2)) <= 0
Xsource(2) = 1;
nullCol = true;
elseif int32(Xsource(2)) > ySize
Xsource(2) = ySize;
nullCol = true;
end
if nullCol == true
morphed(X(1), X(2), :) = [0, 255, 255];
else
% Set pixel X in dst image
morphed(X(1), X(2), :) = im(int32(Xsource(1)), int32(Xsource(2)), :);
end
end
end
subplot(1, 2, 1);
imshow(im);
line([inputLines(1,1) inputLines(2,1)], [inputLines(1,2) inputLines(2,2)], 'Color',[.0 1.0 .0]);
subplot(1, 2, 2);
imshow(morphed);
line([targetLines(1,1) targetLines(2,1)], [targetLines(1,2) targetLines(2,2)], 'Color',[.0 1.0 .0]);
end
以上是上述代码的一些输出。该功能应将源图像中的点P'变形为目标图像中的P点。同样,将Q'指向Q.
这是正确的,除了应旋转180度
这个中间图像(带有蓝绿色)也应旋转180度,并沿三角形的长边伸展,而不是宽边。
我在matlab网站上看到提到像素坐标是在(y,x)而不是(x,y)中完成的。使用morphed(X(2), X(1), :) = im(int32(Xsource(2)), int32(Xsource(1)), :);
修复了方形图像的旋转问题,然而,它将矩形图像转换为更大的正方形(即如果输入图像为192 * 128,则会尝试输出为192 * 192而不是192 * 128)),但不再有任何越界访问。
任何帮助都将不胜感激。
答案 0 :(得分:1)
原来翻转问题是索引问题。在循环开始时,我将其更改为X = [y x]
,然后在Xsource = X + dsum / weightsum;
后的所有行中将其更改为(1)
&{39}和(2)
&#39;第
通过添加第二条控制线来解决拉伸问题(横跨图像的水平线与垂直线一样)。