【问题标题】:Beier-Neely Warp ImplementationBeier-Neely Warp 实现
【发布时间】: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) ),但不再有任何越界访问。

任何帮助将不胜感激。

【问题讨论】:

    标签: matlab image-processing


    【解决方案1】:

    原来翻转问题是索引问题。在循环开始时,我将其更改为X = [y x],然后在Xsource = X + dsum / weightsum; 之后的所有行中,我交换了所有(1)(2)

    通过添加第二条控制线解决了拉伸问题(水平控制线像垂直控制线一样跨越图像)。

    【讨论】:

      猜你喜欢
      • 2018-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-27
      • 2019-01-14
      • 2016-12-08
      相关资源
      最近更新 更多