1

我需要使用 OpenCV 库在我的 android 应用程序中对齐不同的图像。我在这个线程中找到了解决方案。

public static Bitmap alignImagesHomography(Bitmap A, Bitmap B)
{
   final int warp_mode = MOTION_HOMOGRAPHY;
   Mat matA = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8UC3);
   Mat matAgray = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8U);
   Mat matB = new Mat(B.getHeight(), B.getWidth(), CvType.CV_8UC3);
   Mat matBgray = new Mat(B.getHeight(), B.getWidth(), CvType.CV_8U);
   Mat matBaligned = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8UC3);
   Mat warpMatrix = Mat.eye(3, 3, CV_32F);
   Utils.bitmapToMat(A, matA);
   Utils.bitmapToMat(B, matB);
   Imgproc.cvtColor(matA, matAgray, Imgproc.COLOR_BGR2GRAY);
   Imgproc.cvtColor(matB, matBgray, Imgproc.COLOR_BGR2GRAY);
   int numIter = 5;
   double terminationEps = 1e-10;
   TermCriteria criteria = new TermCriteria(TermCriteria.COUNT +  TermCriteria.EPS, numIter, terminationEps);
   findTransformECC(matAgray, matBgray, warpMatrix, warp_mode, criteria, matBgray);
   Imgproc.warpPerspective(matA, matBaligned, warpMatrix, matA.size(), Imgproc.INTER_LINEAR + Imgproc.WARP_INVERSE_MAP);
   Bitmap alignedBMP = Bitmap.createBitmap(A.getWidth(), A.getHeight(), Bitmap.Config.RGB_565);
   Utils.matToBitmap(matBaligned, alignedBMP);
   return alignedBMP;
}

public static Bitmap alignImagesEuclidean(Bitmap A, Bitmap B)
{
   final int warp_mode = MOTION_EUCLIDEAN;
   Mat matA = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8UC3);
   Mat matAgray = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8U);
   Mat matB = new Mat(B.getHeight(), B.getWidth(), CvType.CV_8UC3);
   Mat matBgray = new Mat(B.getHeight(), B.getWidth(), CvType.CV_8U);
   Mat matBaligned = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8UC3);
   Mat warpMatrix = Mat.eye(2,3,CV_32F);
   Utils.bitmapToMat(A, matA);
   Utils.bitmapToMat(B, matB);
   Imgproc.cvtColor(matA, matAgray, Imgproc.COLOR_BGR2GRAY);
   Imgproc.cvtColor(matB, matBgray, Imgproc.COLOR_BGR2GRAY);
   int numIter = 5;
   double terminationEps = 1e-10;
   TermCriteria criteria = new TermCriteria(TermCriteria.COUNT + TermCriteria.EPS, numIter, terminationEps);
   findTransformECC(matAgray, matBgray, warpMatrix, warp_mode, criteria, matBgray);
   Imgproc.warpAffine(matA, matBaligned, warpMatrix, matA.size(), Imgproc.INTER_LINEAR + Imgproc.WARP_INVERSE_MAP);
   Bitmap alignedBMP = Bitmap.createBitmap(A.getWidth(), A.getHeight(), Bitmap.Config.RGB_565);
   Utils.matToBitmap(matBaligned, alignedBMP);
   return alignedBMP;
}

public static Bitmap alignExposures(Bitmap A, Bitmap B) {
    Mat matA = new Mat(A.getHeight(), A.getWidth(), CvType.CV_8UC3);
    Mat matB = new Mat(B.getHeight(), B.getWidth(), CvType.CV_8UC3);
    Utils.bitmapToMat(A, matA);
    Utils.bitmapToMat(B, matB);

    List<Mat> src = new ArrayList<>();
    src.add(matA);
    src.add(matB);
    Bitmap output = Bitmap.createBitmap(A.getWidth(),A.getHeight(), Bitmap.Config.RGB_565);
    AlignMTB align = createAlignMTB(8, 4, false);
    align.process(src,src);
    for(int i = 1; i < src.size(); i++) {
        add(src.get(0),src.get(i),src.get(0));
    }
    Utils.matToBitmap(src.get(0),output);
    return output;
}

我尝试了用户 wegenerEDV 编写的所有三种方法。无论如何,前两个方法返回与作为输入给出的“位图 A”相同的图片;第三种方法实际上是对齐图片,但生成的图像曝光过度:

原文:https ://i.imgur.com/cknHM23.jpg

对齐:https ://i.imgur.com/kXCQl6x.jpg

有没有人找到不同的解决方案?还是这些方法真的有效而我做错了什么?

对我来说最好的解决方案是更正 alignImagesHomography 方法。它实际上做了一些事情,因为处理最终图片大约需要 30 秒,但它与输入图像完全相等。

4

1 回答 1

1

我从未使用过您的第一种和第二种方法使用的 findTransformECC(),而且我不熟悉该算法。这两种方法之间的唯一区别是要求 findTransformECC() 查找的变换类型;单应变换是欧几里得变换的超集,因此第一种方法(使用 MOTION_HOMOGRAPHY)对于您的用例来说是最稳健的,尽管它也可能更慢。

前两种方法返回与作为输入给出的“位图 A”相同的图片

如果这两种方法正常工作,结果应该看起来与图像 A 几乎相同,即使它是由图像 B 的像素产生的。您是否检查过结果与位图 A 按位相同,并且不只是看起来相似?我想我可以在两种方法中看到相同的错误:findTransformECC() 找到从 matBgray 到 matAgray 的映射(请参阅文档),但是分别使用 warpPerspective() 和 warpAffine() 将生成的变换应用于 matA,存储matBaligned 中的结果;它们应该应用于 matB。我可以看到您将获得与图像 A 按位相同的结果的唯一方法是,如果您的单应性计算失败,那么结果单应性(“warpMatrix”)仍然包含其初始状态,即单位矩阵。身份单应性,错误地应用于 matA(由于上述错误),当然会在 matBaligned 中给出 matA 的另一个精确副本。您可以通过在计算后打印 warpMatrix 并查看它是否是单位矩阵来检查这一点。您还应该添加一些错误检查,因为目前您不知道您调用的方法是否完全失败,或者为什么(例如,错误的输入参数,无法找到任何对应关系等)。

您的第三种方法 alignExposures() 使用了用于 HDR 成像的 AlignMTB,我不知道它是如何进行对齐的。它可能只处理 2D 平移。该方法中的循环是将输出图像添加回源图像之一,因此它将饱和为白色。如果您想要的结果是将对齐的图像平均在一起(这是您想要的吗?),您应该创建一个具有更大数据类型(例如 CV_16UC3)的新输出矩阵来累积结果图像并计算平均值,然后使用 cv: :convertTo() 将该缓冲区减少回原始数据类型(例如 CV_8UC3)。

我成功用于单应对齐的另一种算法是:

  • 创建一个特征检测器,例如。SIFT,来自 features2d 或 xfeatures2d 库。我使用了 AKAZE,因为 SIFT 已获得专利。
  • 使用 detectAndCompute() 检测两个图像中的特征和描述符。
  • 创建一个 BFMatcher 并使用 match() 对两个图像的特征点进行强力匹配。
  • 如果你想在这一点上,你可以打印匹配的特征点,将它们绘制到图像上并查看它们等等。
  • 将找到的对应关系组织成两个适合 findHomography() 的列表(源点和目标点)。
  • 使用 RANSAC 标志调用 findHomography()。
  • 使用 warpPerspective() 应用单应性。

使用此方法有更多机会检查和验证您的数据,这将有助于调试。

于 2018-07-23T00:55:44.103 回答