最大公共前景像素的图像平移优化算法

Optimizing Algorithm for Image Translation with maximum common foreground pixel

提问人:No Grad 提问时间:11/12/2023 最后编辑:Mark SetchellNo Grad 更新时间:11/13/2023 访问量:83

问:

我正在寻找一种算法来有效地确定一个 2D 图像到另一个 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 图像处理 对齐 配准 像素操作

评论

0赞 Mark Setchell 11/12/2023
两张具有代表性的图像和相应的慢速方法的最佳放置可能有助于提供一些见解。
0赞 No Grad 11/13/2023
已编辑,感谢您的评论

答:

4赞 Mark Setchell 11/13/2023 #1

我不会说 Java,但我认为你想要一个“相位相关性”,你可以在 Python 中使用 scikit-image 来做到这一点,如下所示:

#!/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}')

输出

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

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

我想你可以用某种类型的 or 函数“掏出”到 Python,或者找到相位相关技术的 Java 实现。exec()system()


还有一个可用的 OpenCV 实现,它可能具有 Java 绑定。它明显比上述方法快,并在不到 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=}')

输出

retval=(-171.0011860055988, 97.00465314052326)

如果我用绿色绘制一张图像,然后第二张红色图像按计算量移动,我会得到这样的结果。

enter image description here

我使用了“硬混”混合模式,所以黄色部分是红色和绿色重合的地方。供我参考,这是我使用 ImageMagick 的混合命令:

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

评论

2赞 Cris Luengo 11/13/2023
如果您有可用的 FFT,那么重新实现互相关应该是微不足道的(无论是否使用“相位”方法添加的归一化)。但是在处理图像时,使用一些图像处理库确实是有意义的,无论哪个可用,大多数都会实现某种互相关方法。