我正在寻找一种算法来有效地确定一幅2D图像到另一幅图像的最佳平移(限于x和y轴,不旋转).目标是找到最大的公共像素,其中像素在白色背景上被认为是黑色的,反之亦然.前景与背景的比率明显向背景倾斜.

示例:

enter image description here

enter image description here

这里,最好的翻译是[-171,97].

我已经实现了一个算法,它比较所有的像素,并通过递增x和y来迭代转换.然而,这种方法很耗时.为了解决这个问题,我试图通过只关注第二张图像中白色像素到其他白色像素的转换来加快这一过程.虽然它奏效了,但仍然很慢.

下面是我当前算法的代码片段(arrayImage只包含0和1,它是一个二进制图像).

public static int[] findBestTranslation(int[][] arrayImage1, int[][] arrayImage2) {
    int[] bestTranslation = new int[2];
    int bestSimilarity = Integer.MIN_VALUE;

    int img2Length = arrayImage2.length;
    int img2Width = arrayImage2[0].length;
    
    List<int[]> whitePixelsImage1 = findWhitePixels(arrayImage1);
    List<int[]> whitePixelsImage2 = findWhitePixels(arrayImage2);
    boolean[][] checkedOffsets = new boolean[img2Length * 2][img2Width * 2];
    
    int i = 0;
    for (int[] pixel1 : whitePixelsImage1) {
        System.out.println(i++ + ": " + bestSimilarity);
        for (int[] pixel2 : whitePixelsImage2) {
            //calculate translation
            int xOffset = pixel2[0] - pixel1[0];
            int yOffset = pixel2[1] - pixel1[1];

            // Check if this offset has been selected before
            if (checkedOffsets[xOffset + img2Length][yOffset + img2Width]) {
                continue;
            } else {
                checkedOffsets[xOffset + img2Length][yOffset + img2Width] = true;
            }

            int similarity = 0;
            for (int[] pixelNotTranslated : whitePixelsImage1) {
                int xTranslated = pixelNotTranslated[0] + xOffset;
                int yTranslated = pixelNotTranslated[1] + yOffset;
                if (xTranslated >= 0 && xTranslated < img2Length && yTranslated >= 0 && yTranslated < img2Width) {
                    similarity += arrayImage2[xTranslated][yTranslated];
                }
            }

            if (similarity > bestSimilarity) {
                bestSimilarity = similarity;
                bestTranslation[0] = xOffset;
                bestTranslation[1] = yOffset;
            }
        }
    }

    return bestTranslation;
}

推荐答案

我不会说Java,但我认为你想要"phase correlation",你可以用scikit-image在Python语言中做到如下所示:

#!/usr/bin/env python3

import numpy as np
from skimage import io
from skimage.registration import phase_cross_correlation

# Define image names and load them
im1name = 'MVlJh.png'
im2name = 'XSj05.png'
im1 = io.imread(im1name)
im2 = io.imread(im2name)

# Peform phase correlation
shift, error, diffphase = phase_cross_correlation(im1, im2)

print(f'Detected pixel offset (y, x): {shift}')

Output个个

对于您的两个图像,它在大约1秒内输出以下内容:

Detected pixel offset (y, x): [-97. 171.   0.]

我猜你可以用exec()system()函数将"shell out"转换为Python,或者找到相位相关技术的Java实现.


还有一个OpenCV实现,它可能有Java bindings.它明显快于上面的方法,并在1秒内得到结果:

#!/usr/bin/env python3

import numpy as np
import cv2 as cv

im1name = 'MVlJh.png'
im2name = 'XSj05.png'

im1 = cv.imread(im1name, cv.IMREAD_GRAYSCALE)
im2 = cv.imread(im2name, cv.IMREAD_GRAYSCALE)

# Peform phase correlation
retval, response = cv.phaseCorrelate(im1.astype(float), im2.astype(float))

print(f'{retval=}')

Output个个

retval=(-171.0011860055988, 97.00465314052326)

这是我得到的结果,如果我把一张图标为绿色,然后把第二张图标为红色,移动了计算出的量.

enter image description here

我使用了"hardmix"混合模式,所以黄色部分是红色和绿色重合的地方.作为我自己的参考,这是我对ImageMagick的混合命令:

magick MVlJh.png -fill lime -opaque white \( XSj05.png -geometry +171-97  -fill red -opaque white  \) -compose hardmix -composite result.png

Java相关问答推荐

';com.itextpdf.ext.html.WebColors已弃用

存根基类的受保护方法

在运行MVN测试时,为什么构建失败,并显示了java.lang.ClassNotFoundException:java.net.http.HttpResponse?

Mac上的全屏截图在使用JavaFX时不能正常工作吗?

无法在Java中处理PayPal支付响应

使用Jolt将字段转换为列表

S,要对Java复制构造函数深度克隆所有属性进行单元测试,最可靠的方法是什么?

迁移到Java 17后,日期显示不准确

Domino Designer 14中的保存代理添加了重影库

无法使用Freemarker从XML中读取重复的标记值

有没有办法在o(log(N))中以系统的方式将数组中的小块元素复制和移动到新增长的数组中的左侧?

在Java泛型中使用通配符时,如何推断类型

在Oracle中调用输出参数在索引处缺少IN或OUT参数的函数

本机方法(JNI)总是编译的吗?

模拟JUnit未检测到返回字符串的方法的任何声纳覆盖

Java 21内置http客户端固定运营商线程

读取ConcurrentHashMap中的可变对象

java中的网上购物车解析错误

为什么 Random() 的行为不符合预期?

在对象列表上调用提取后,如何判断没有值为空?