【发布时间】:2014-07-02 05:56:52
【问题描述】:
我一直在尝试在 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) ),但不再有任何越界访问。
任何帮助将不胜感激。
【问题讨论】: