通过输出知识解决真正的拼图游戏

时间:2015-12-27 10:42:34

标签: java algorithm puzzle

我想通过运算算法来解决维度为n * m的Java中的真正拼图游戏。实际输出,即图像是预先已知的。到目前为止,这些是我的想法。

  1. 将所有拼图对齐在一张纸上,拼图本身不包含的颜色并拍照。

  2. 将所有碎片裁剪为n * m个子图像。

  3. 获取每件中每个像素的RGB值,忽略包含纸张颜色的像素(考虑每件的特殊形状)。

  4. 从实际输出图像中获取n * m个子图像。

  5. 这是我遇到麻烦的地方。如果我想比较这些作品,我该如何考虑拼图形状?

  6. 总结一下,比较RGB值是一种很有前景的方法吗?我将如何继续?是否有更好,更简单的方法,如FFT或某种类型?

    感谢您的投入!

3 个答案:

答案 0 :(得分:2)

如果您的图像质量足够,只有当多个部分适合给定的插槽时,您才可以解决查看图片的问题。以下伪代码可能有效:

  1. 获取作品概述,使用高对比度背景照片,并确保补偿任何镜头失真。

  2. 通过识别所有外圈(具有一个或两个直边)并将它们与其他所有外圈形状匹配来构建外圈。当两个部分紧密贴合在一起时考虑一个匹配:最小化(overlapArea + emptyArea),其中overlapArea是一个接一个地放置各个部分时的重叠量,以及emptyArea之间的可用空间量当它们彼此相邻放置时的碎片。使用颜色信息打破关系(和近距离)。将初始4角与盒子上的图像匹配应该相对简单。

  3. 通过取一个现有的环形角并找到放置在该角落的下一个部分(放置的部分将具有2个邻居)来构建连续的环。在第2步结束时,将有4个角。将另一件放在那个角落后,就会有5个。只需继续将角件放在角落里,直到最后一块放在最后一个空间内。

  4. 这种方法的几何部分需要两个成分:

    1. 获取图片大纲:

      • 校正失真(相机会在侧面附近引入球面失真;如果照片不是直接从照片上方拍摄,则可能会关闭透视)。 一般情况下这并不容易,请在单独的问题中询问一些图像专家
      • 使用轮廓查找算法查找每个棋子的轮廓几何。我已成功使用marching squares执行此任务。
    2. 要匹配图像轮廓,您可以使用几个快捷方式来过滤掉不匹配的内容。例如,匹配边框必须具有相似的长度相反的方向。首先匹配每对件的两个角(必须具有相同的间距);然后使用几何库(我推荐JTS)来查看它们重叠的程度,最小化(overlapArea + emptyArea)定义。您可以找到混合JTS和顶点序列here的代码。

    3. 图像匹配部分还需要两个成分:

      1. 准备匹配的图像:

        • 在片段图像和盒子图像中都固定了失真。此外,请确保在与图像相同的光照条件下拍摄盒子图像,否则匹配将更加困难。这很难做到 - 再次,如果您需要详细信息,可以在另一个问题中提问
        • 使用均匀的半径来获取每个片段的中心像素的直方图,以确保不包括片边。这是旋转不变的。
        • 根据盒子图像从片段中心获取相同的直方图。请注意,大多数拼图遵循相当严格的网格,具有等间距的行和列。在执行此操作之前,您需要输入或检测网格尺寸。
      2. 在确定某件作品是否与某一点匹配时,请检查其中心的颜色直方图与该网格位置的预期框直方图。例如,使用均方误差作为匹配度量。也就是说,如果你有两对红色,绿色和蓝色直方图(R1,R2,G1,G2,B1,B2),每个直方图有256个值(8bbp),每个直方图都有一个浮点值来计算像素的比例在具有该像素强度的相应圆圈中,然后将所有差异平方并将它们相加以得到误差值:error = (R1[0]-R2[0])*(R1[0]-R2[0]) + ... + (B1[255]-B2[255])*(B1[255]-B2[255])

      3. 仅几何只有在所有作品都是独一无二的情况下才会起作用,通常情况并非如此(多个谜题一遍又一遍地重复使用作品轮廓)。只有在没有重复图案的情况下才能使用仅图像,例如大面积的天空或树木,窗户或砖石。一般方法必须使用两种信息来源才能成功。

        编辑添加一些图像匹配,因为仅仅几何图形是不够的,因为OP链接的拼图示例

答案 1 :(得分:0)

您正在寻找模板匹配(在另一幅图像(原始图像)中查找图像(拼图))。

您可以迭代您的棋子并将每个棋子滑动到原始图像(通过棋子大小的一步)比较所有像素的相似性。如果需要旋转碎片,则需要存储4个值(每个位置的方向)。

最大相似度将为您提供正确的位置方向。如果碎片是从原始图像中裁剪出来的(并且具有相同的质量,相对尺寸),那么您将期望找到每件作品的完美匹配。

对于图像比较,最简单的方法是存储每个像素的聚合RGB距离,请参阅herepHash(在java here上)。

由于在正常的拼图游戏中,棋子不是矩形(某种程度上是不规则的形状),因此在比较时,请确保只比较原始图像的重叠部分(实现该目标的各种方式)。

仅供参考:解决拼图游戏是NP完全的(参见相关论文here)(想象一下最糟糕的情况,图像纯绿色,没有形状,没有;因此输出可能无法提供任何线索:))

仅供参考2:曾经有Eternity Puzzle比赛获得真钱奖,获奖者(数学家)在7个月内使用两台国产PC解决了这场比赛。然后Eternity II,没有赢家! 所以你明白这是一个艰难的项目!

答案 2 :(得分:0)

初步想法

我会先尝试依次添加每一部分

  1. 几何学(这件作品紧紧贴合在哪里?),

  2. 按颜色(如果不同的部分放在同一个地方)。

  3. 为此,您将保留一张放置了之前作品的图片,并保留背景颜色。

    在尝试新作品之前,您必须获得自由区域的边界,这是一条曲线。 (添加一篇文章后,可以在本地更新此曲线。)

    然后拿一块并在其轮廓上选择一个点。通过在曲线上扫描这一点,您可以找到一个适合的位置,具有显着的重叠。保持实现最长合适的作品。

    如果是关系(或准关系),请检查具有相似性得分的颜色,例如SAD。

    但是,这将非常耗费时间。

    第二个想法

    现在可能有办法知道碎片的确切方向(除非轮廓的某些部分保证水平/垂直)。尝试不同的角度会加剧运行时间。

    另一种方法是选取两个点,一个已知的距离在一个部分的轮廓上。然后滑动边界曲线上的第一个点,找到另一个点的位置,在轮廓的前面并遵守距离约束。

    <强>更新

    如果碎片全部相同,则几何搜索变得无关紧要。但好消息是这些碎片的位置变得非常可预测(碎片只是在常规网格上)。

    因此,可以在所需的位置依次尝试每一件,并且正确的匹配基于已知图像的颜色,或者基于公共边缘的相邻片段中的颜色。

    建议首先放置最佳匹配的碎片,以尽量减少错误匹配的可能性。