对给定模式中的以下坐标进行排序:

Posted

技术标签:

【中文标题】对给定模式中的以下坐标进行排序:【英文标题】:Sorting the following coordinates in the given pattern: 【发布时间】:2016-07-09 01:26:42 【问题描述】:

我有以下图片:

图像中白色斑点对应的坐标按照x坐标的递增值排序。但是,我希望他们遵循以下模式:

(从左下角到左上角呈锯齿形。)

任何线索我该怎么做?任何有关该算法的线索将不胜感激。

坐标集如下:

[46.5000000000000,104.500000000000]
[57.5000000000000,164.500000000000]
[59.5000000000000,280.500000000000]
[96.5000000000000,66.5000000000000]
[127.500000000000,103.500000000000]
[142.500000000000,34.5000000000000]
[156.500000000000,173.500000000000]
[168.500000000000,68.5000000000000]
[175.500000000000,12.5000000000000]
[198.500000000000,37.5000000000000]
[206.500000000000,103.500000000000]
[216.500000000000,267.500000000000]
[225.500000000000,14.5000000000000]
[234.500000000000,62.5000000000000]
[251.500000000000,166.500000000000]
[258.500000000000,32.5000000000000]
[271.500000000000,13.5000000000000]
[284.500000000000,103.500000000000]
[291.500000000000,61.5000000000000]
[313.500000000000,32.5000000000000]
[318.500000000000,10.5000000000000]
[320.500000000000,267.500000000000]
[352.500000000000,57.5000000000000]
[359.500000000000,102.500000000000]
[360.500000000000,167.500000000000]
[366.500000000000,11.5000000000000]
[366.500000000000,34.5000000000000]
[408.500000000000,9.50000000000000]
[414.500000000000,62.5000000000000]
[419.500000000000,34.5000000000000]
[451.500000000000,12.5000000000000]
[456.500000000000,97.5000000000000]
[457.500000000000,168.500000000000]
[465.500000000000,62.5000000000000]
[465.500000000000,271.500000000000]
[468.500000000000,31.5000000000000]
[498.500000000000,10.5000000000000]
[522.500000000000,105.500000000000]
[524.500000000000,32.5000000000000]
[533.500000000000,60.5000000000000]
[534.500000000000,11.5000000000000]
[565.500000000000,164.500000000000]
[576.500000000000,33.5000000000000]
[581.500000000000,10.5000000000000]
[582.500000000000,67.5000000000000]
[586.500000000000,267.500000000000]
[590.500000000000,102.500000000000]
[622.500000000000,10.5000000000000]
[630.500000000000,32.5000000000000]
[646.500000000000,58.5000000000000]
[653.500000000000,94.5000000000000]
[669.500000000000,8.50000000000000]
[678.500000000000,167.500000000000]
[680.500000000000,31.5000000000000]
[705.500000000000,57.5000000000000]
[719.500000000000,9.50000000000000]
[729.500000000000,271.500000000000]
[732.500000000000,33.5000000000000]
[733.500000000000,97.5000000000000]
[757.500000000000,11.5000000000000]
[758.500000000000,59.5000000000000]
[778.500000000000,157.500000000000]
[792.500000000000,31.5000000000000]
[802.500000000000,10.5000000000000]
[812.500000000000,94.5000000000000]
[834.500000000000,59.5000000000000]
[839.500000000000,30.5000000000000]
[865.500000000000,160.500000000000]
[866.500000000000,272.500000000000]
[885.500000000000,58.5000000000000]
[892.500000000000,97.5000000000000]
[955.500000000000,94.5000000000000]
[963.500000000000,163.500000000000]
[972.500000000000,265.500000000000]

【问题讨论】:

@JorensM 你有效率限制吗?对于示例中的小尺寸值,O(N^2) 算法看起来足够高效,正如当前答案中提出的那样。 @JorensM 您能否准确说明您在寻找什么 【参考方案1】:

根据 uSemSurprise 的回答,我将采用 3 步方法:

y-coord 对点列表进行排序。这是 O(n log n) 确定y-axis 范围。我只是遍历这些点并记下y-coord 差异大于阈值的位置。这当然是 O(n) 按x-coord 对代表y-axis 行的每个子列表进行排序。如果我们有 m 子列表 k 每个项目,这将是 O(m (k log k));所以整个过程还是O(n log n)

代码:

def zigzag(points, threshold=10.0)
    #step 1
    points.sort(key=lambda x:x[1])

    #step 2
    breaks = []
    for i in range(1, len(points)):
        if points[i][1] - points[i-1][1] > threshold:
            breaks.append(i)
    breaks.append(i)

    #step 3
    rev = False
    start = 0
    outpoints = []
    for b in breaks:
        outpoints += sorted(points[start:b], reverse = rev)
        start = b
        rev = not rev

    return outpoints

【讨论】:

点 1 和 2 可以用 y 坐标上的直方图代替,然后识别峰值并以这种方式分割 y 轴。可能是更复杂的代码,但对于大量的点集合会更好地扩展。【参考方案2】:

你可以对y-axis坐标对应的x-axis坐标进行排序,这里你认为一定的y-axis范围,即按照x-axis排序的坐标都属于同一个y-axis范围。每次向上移动到不同的 y-axis 范围时,您都可以翻转排序顺序,即先增加后减少,依此类推。

【讨论】:

【参考方案3】:

我能想到的最相似的算法是 Andrew 的凸包算法,特别是下包(虽然取决于坐标系,您可能需要改用上包)。

运行 lower hull 算法并删除点直到没有剩余点会得到你想要的。要获得之字形图案,请在每隔一次运行时颠倒顺序。

这是大多数语言的实现:

https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain

编辑:在模糊测量的情况下,缺点是精度。如果凸包不是您所需要的,您可能需要稍微调整算法。 IE:如果你想认为它仍然是船体的一部分,如果它在 0.1 以内,或者说 1% 在船体上等等。在给出的示例中,坐标正好在线上,所以它会很好地工作,但如果坐标是随机分布在它们实际位置的 0.1 范围内,则效果不会那么好。

【讨论】:

【参考方案4】:

这种方法假设您知道预期的行数,尽管我怀疑您可以通过编程方式来估算。

nbins = 6;                            % Number of horizontal rows we expect
[bin,binC] = kmedoids(A(:,2),nbins);  % Use a clustering approach to group them
bin = binC(bin);                      % Clusters in random order, fix it so that clusters
[~,~,bin] = unique(bin);              %   are ordered by central y value
xord = A(:,1) .* (-1).^mod(bin+1,2);    % flip/flop for each row making the x-coord +ve or -ve
                                      %   so that we can sort in a zig-zag
[~,idx] = sortrows([bin,xord], [1,2]); % Sort by the clusters and the zig-zag
B = A( idx, : );                      % Create re-ordered array

绘制这个,看起来就像你想要的

figure(99); clf; hold on;
plot( A(:,1), A(:,2), '-o' );
plot( B(:,1), B(:,2), '-', 'linewidth', 1.5 );
set(gca, 'YDir', 'reverse');
legend( 'Original','Reordered' );

【讨论】:

【参考方案5】:

使用nearest neighbor search,您可以在其中定义自定义距离度量,这使得 Y 方向上的距离比 X 方向上的距离更昂贵。然后从左下角开始算法。

Cartesian coordinates 中的“正常”Euclidean distance 由sqrt( (x2 - x1)^2 + (y2 - y1)^2 ) 计算得出

要使 y 方向更昂贵,请使用自定义距离公式,将 y 结果乘以一个常数: sqrt( (x2 - x1)^2 + k*(y2 - y1)^2 ) 如果常量k 大于 1 但不会大很多,我会从 2 开始。

【讨论】:

以上是关于对给定模式中的以下坐标进行排序:的主要内容,如果未能解决你的问题,请参考以下文章

根据bash中的模式对文件行进行排序

订购一组正则表达式模式或获取最大的正则表达式匹配

如何允许对不在编辑模式下的 SwiftUI 列表中的行进行重新排序?

对向量中的点进行排序以形成轮廓

渲染管道整体流程

JDBC排序数据实例