Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 寻找径向线段的最近邻_Algorithm_Matlab_Geometry_Nearest Neighbor_Feature Descriptor - Fatal编程技术网

Algorithm 寻找径向线段的最近邻

Algorithm 寻找径向线段的最近邻,algorithm,matlab,geometry,nearest-neighbor,feature-descriptor,Algorithm,Matlab,Geometry,Nearest Neighbor,Feature Descriptor,首先,不要被这个问题的外表吓到;) 我试图在matlab中实现一个称为圆形模糊形状模型的形状描述符,其中一部分是为每个径向段获取一个最近邻列表,如图1d所示) 我在MATLAB中进行了一个简单明了的实现,但我仍停留在算法的第5步和第6步,主要是因为我无法理解定义: Xb{c,s} = {b1, ..., b{c*s}} as the sorted set of the elements in B* so that d(b*{c,s}, bi*) <= d(b*{c,s}, bj*), i

首先,不要被这个问题的外表吓到;)

我试图在matlab中实现一个称为圆形模糊形状模型的形状描述符,其中一部分是为每个径向段获取一个最近邻列表,如图1d所示)

我在MATLAB中进行了一个简单明了的实现,但我仍停留在算法的第5步和第6步,主要是因为我无法理解定义:

Xb{c,s} = {b1, ..., b{c*s}} as the sorted set of the elements in B* 
so that d(b*{c,s}, bi*) <= d(b*{c,s}, bj*), i<j
全文可以找到

这篇论文谈论的是“区域邻国”;在欧几里得距离意义上,这些是“最近邻居”的解释是不正确的。它们只是某个区域的邻域,查找它们的方法很简单:

这些区域有2个坐标:(c,s),其中c表示它们属于哪个同心圆,从中心的1到边缘的c,s表示它们属于哪个扇区,从0°角开始的1到360°角结束的s

c和s坐标与区域坐标相差最多1的每个区域都是相邻区域(段号从s到1环绕)。根据区域的位置,有3种情况:(如图1d所示)

  • 该区域为中间区域(标记为MI),例如区域b(2,4)
    有2个相邻的圆圈和2个相邻的扇区,因此总共有9个区域:
    圆圈1、2或3以及扇区3、4或5中的每个区域:
    b(1,3),b(2,3),b(3,3),b(1,4),b(2,4),b(3,4),b(1,5),b(2,5),b(3,5)

  • 该区域为内部区域(标记为),例如区域b(1,8)
    只有一个相邻圆圈和两个相邻扇区,但所有内部区域都是相邻的,因此S+3区域总计:
    圈2和扇区7、8或1中的每个区域:
    b(2,7)、b(2,8)、b(2,1)

    以及内圈的每个区域:
    b(1,1)、b(1,2)、b(1,3)、b(1,4)、b(1,5)、b(1,6)、b(1,7)、b(1,8)

  • 该区域为外部区域(标记为EX),例如区域b(3,1)
    只有一个相邻圈和两个相邻区,因此总共有6个区域:
    圆圈2或3和扇区8、1或2中的每个区域:
    b(2,8),b(2,1),b(2,2),b(3,8),b(3,1),b(3,2)


要在@m69中添加一点matlab,您可以像下面这样自动化邻居的索引:

%assume C and S defined according to the answer of @m69
iif=@(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();
ncfun=@(c) iif(c==1,c+1,c==C,c-1,true,[c-1, c+1]);
nsfun=@(s)mod([s-1, s+1]-1,S)+1;
neighbs=@(c,s) [b(c,nsfun(s)), b(ncfun(c),s)', reshape(b(ncfun(c),nsfun(s)),1,[])];
  • 第一个定义用于匿名函数,以避免在单独的文件中定义函数(这对于
    c
    案例是必需的)。这具有语法
    iif(条件1,结果1,条件2,结果2,…)
    ,其中每个条件一个接一个地进行测试,并返回与产生
    true
    的第一个条件对应的结果

  • 第二个使用if:return[c-1,c+1]定义径向邻域索引,除非其中任何一个未定义(这将导致数组绑定冲突)

  • 第三个定义了角扇区的周期索引,例如对于
    S=4
    nsfun(2)=[1,3]
    nsfun(4)=[3,1]

  • 我刚刚添加了一个示例,其中对于给定的一对有效的
    c,s
    neighbs(c,s)
    将返回
    b(1:c,1:s)
    的子数组,它们是相邻的:首先是上下/左右相邻的,然后是(最多)四个角相邻的


  • 在花了太多的时间之后,我明白了,计算元素b{c,s}的相邻区域的诀窍是:

    • 取c的相邻环的所有段,包括c本身,即
      c-1,c,c+1
      ,如果它是最内圈,那么只有
      c,c+1
      如果它是最外圈,则取
      c-1,c

    • 计算从b{c,s}到上一步中所有选定质心的欧氏距离,包括点b{c,s}本身

    • 按升序对距离进行排序,并取前N段

    描述符工作得很好,但是它的旋转不变性取决于具有最高密度的轴。在某些情况下,这对噪声/遮挡非常敏感,即描述符可能处于+/-1旋转关闭状态

    以下是完整的CBSM描述符在MATLAB中的实现,没有以任何方式进行优化(我听说MATLAB讨厌循环):

    csbm.m

    function [descriptor] = csbm(I, R, C, S)
        % Input:
        % ------
        % I = The image, binary, must be square in sice
        % R = The radius of the correlogram, could be half the image width
        % C = Number of circles
        % S = Number of segments per circle
    
        % Output:
        % -------
        % A C*S-by-1 row vector, the descriptor
    
        [width, height] = size(I);
        assert(width == height, 'Image must be square in size!');
    
        % "width" of ring segments
        d = R/C;
    
        % angle of one segment in degrees
        g = 2*pi/S;
    
        % centroid coordinates for bins
        B_star = zeros(C*S,2);
    
        % initialize the descriptor
        descriptor = zeros(C*S,1);
    
        % calculate centroids of bins
        for c=1:C
            for s=1:S
                alpha = max(s-1, 0)*g + g/2;
                r     = d*max((c-1),0) + d/2;
                ind   = (c-1)*S+s; %sub2ind(cs_size, c,s);
    
                B_star(ind, :) = [r*cos(alpha), r*sin(alpha)];
            end
        end
    
        % calculate nearest neighbor regions
        B_NN = cell(C*S,1);
    
        for c=1:C
            min_circle = max(1,c-1);
            max_circle = min(C,c+1);
    
            start_sel  = (min_circle-1)*S+1;
            end_sel    = (max_circle)*S;
    
            centroids  = B_star(start_sel:end_sel, :);
    
            for s=1:S
                current_ind   = (c-1)*S+s;
                centroid      = B_star(current_ind, :);
                num_centroids = length(centroids);
                distances     = sqrt(sum((centroids-repmat(centroid, num_centroids,1)).^2,2));
    
                distances     = horzcat(distances, transpose((start_sel:end_sel)));
                distances     = sortrows(distances, [1,2]);
    
                neighbour_count = 9;
    
                if c == 1
                    % inner region has S+3 neighbours
                    neighbour_count = S+3;
                elseif c == C
                    % outer most ring has 6 neighbours
                    neighbour_count = 6;
                end
    
    
                B_NN{current_ind} = distances(1:neighbour_count, 2);
            end
        end
    
        for x=1:width
            x_centered = x-width/2;
    
            for y=1:width
                if I(x,y) == 0
                    continue;
                end
    
                y_centered = y-width/2;
    
                % bin the image point
                r = sqrt(x_centered^2 + y_centered^2);
                a = wrapTo2Pi(atan2(y_centered, x_centered));
    
                % get bin
                c_pixel = max(1, floor(r/d));
                s_pixel = max(1, floor(a/g));
    
                if c_pixel > C
                    continue;
                end
    
                ind_pixel = (c_pixel-1)*S+s_pixel;
                pt_pixel  = [x_centered, y_centered];
    
                % get neighbours of this bin
                neighbours = B_NN{ind_pixel};
    
                % calculate distance to neighbours
                nn_dists   = sqrt(sum((B_star(neighbours, :) - repmat(pt_pixel, length(neighbours), 1)).^2,2));
    
                D = sum(1./nn_dists);
    
                % update the probabilities vector
                descriptor(neighbours) = descriptor(neighbours) + 1./(nn_dists.*D);
            end
        end
    
        % normalize the vector v
        descriptor   = descriptor./sum(descriptor);
    
        % make it rotationally invariant
        G = zeros(S/2, 2*C);
    
        for s=1:S/2
            for c=1:C
                G(s,c)   = descriptor((c-1)*S+s);
                G(s,c+C) = descriptor((c-1)*S+s+S/2);
            end
        end
    
        [~, max_G_idx] = max(sum(G,2));
    
        L_G = 0;
        R_G = 0;
    
        for j=1:C
            for k=1:S
                if k > (max_G_idx) && k < (max_G_idx+S/2)
                    L_G = L_G + descriptor((j-1)*S+k); 
                elseif k ~= max_G_idx && k ~= (max_G_idx+S/2)
                    R_G = R_G + descriptor((j-1)*S+k); 
                end
            end
        end
    
        if L_G > R_G
            % B is rotated k=i+S/2-1 positions to the left:
            fprintf('rotate %d to the left\n', max_G_idx+S/2-1);
            rotate_by = -(max_G_idx+S/2-1);
        else
            % B is rotated k=i-1 positions to the right:
            fprintf('rotate %d to the right\n', max_G_idx-1);
            rotate_by = -(max_G_idx-1);
        end
    
        % segments are grouped by circle
        % so for every circle we get all segments and circular shift them
        for c=1:C
           range_sel = ((c-1)*S+1):(c*S);
           segments  = descriptor(range_sel);
           descriptor(range_sel) = circshift(segments, [rotate_by,0]);
        end
    end
    
    function plot_descriptor(R,C,S, descriptor)
        % Input:
        % ------
        % R Radius for the correlogram in pixels, can be arbitrary
        % C Number of circles
        % S Number of segments per circle
        % descriptor The C*S-by-1 descriptor vector
    
    
        % "width" of ring segments
        d = R/C;
    
        % angle of one segment in degrees
        g = 2*pi/S;
    
        % full image
        [x,y] = meshgrid(-R:R);
        [theta, rho] = cart2pol(x,y);
        theta = wrapTo2Pi(theta);
        brightness   = zeros(size(rho));
    
        min_val     = min(descriptor);
        max_val     = max(descriptor);
        scale_fact  = 1/(max_val-min_val);
    
        for c=1:C
            rInner = (c-1)*d;
            rOuter = c*d;
    
            for s=1:S
                idx = (c-1)*S+s;
    
                minTheta = (s-1)*g;
                maxTheta = (s*g);
    
                matching_theta = find(theta > minTheta & theta < maxTheta);
                matching_rho   = find(rho > rInner & rho < rOuter);
                matching_idx   = intersect(matching_theta, matching_rho);
    
                intensity = descriptor(idx)*scale_fact;
    
                brightness(matching_idx) = intensity;
            end
        end
    
        figure; imshow(mat2gray(brightness));
    
    输出:

    只是为了好玩,在编写代码时出现了一些可怕的图片:


    其中在论文中指出哪些是
    b{4,1}
    的最近邻?在其中一个图中有一个bat。在步骤2和插图(a)
    g
    中,连续扇区之间的度数应该是
    360/S
    而不是
    S/360
    。你考虑过不使用欧几里德距离吗,但是其他指标呢?比如保持极坐标(只有自然坐标),使用标准化距离,其中一个角线段的宽度与一个径向线段的宽度相同。或者更好:将角度*径向离散化保留为2d索引[1:n1,1:n2],并将邻域识别为每个索引相差不超过1的段(考虑到角度变量的周期边界)。图1D中显示的似乎不是最近的段,而是相邻的段,这完全是另一回事。谢谢你添加这个;我对Matlab一窍不通。非常感谢!我确实需要更深入地了解Matlab
    for
    循环在matlab中并不邪恶,但通常有更好的矢量化替代方案。近年来,如果使用得当,
    for
    循环与内置循环一样高效。这当然取决于应用。你也可以做其他的速记:比如去掉
    find
    s并使用逻辑索引:
    matching_theta=theta>minTheta&thetafunction plot_descriptor(R,C,S, descriptor)
        % Input:
        % ------
        % R Radius for the correlogram in pixels, can be arbitrary
        % C Number of circles
        % S Number of segments per circle
        % descriptor The C*S-by-1 descriptor vector
    
    
        % "width" of ring segments
        d = R/C;
    
        % angle of one segment in degrees
        g = 2*pi/S;
    
        % full image
        [x,y] = meshgrid(-R:R);
        [theta, rho] = cart2pol(x,y);
        theta = wrapTo2Pi(theta);
        brightness   = zeros(size(rho));
    
        min_val     = min(descriptor);
        max_val     = max(descriptor);
        scale_fact  = 1/(max_val-min_val);
    
        for c=1:C
            rInner = (c-1)*d;
            rOuter = c*d;
    
            for s=1:S
                idx = (c-1)*S+s;
    
                minTheta = (s-1)*g;
                maxTheta = (s*g);
    
                matching_theta = find(theta > minTheta & theta < maxTheta);
                matching_rho   = find(rho > rInner & rho < rOuter);
                matching_idx   = intersect(matching_theta, matching_rho);
    
                intensity = descriptor(idx)*scale_fact;
    
                brightness(matching_idx) = intensity;
            end
        end
    
        figure; imshow(mat2gray(brightness));
    
    I = imread('bat-18.gif');
    I = transpose(im2bw(I, graythresh(I)));
    I = edge(I);
    
    [width, height] = size(I);
    R = width/2;
    C = 24;
    S = 24;
    
    descriptor = csbm(I, R, C, S);
    plot_descriptor(R,C,S,descriptor);