Android:图像对齐
Android: Images alignment
我需要使用 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用户写的三种方法我都试过了。不管怎样,前两种方法return与输入的"Bitmap A"相同的图片;第三种方法确实对齐了图片,但结果图像曝光过度:
原文:https://i.imgur.com/cknHM23.jpg
对齐:https://i.imgur.com/kXCQl6x.jpg
有没有人找到不同的解决方案?还是这些方法真的有效而我做错了什么?
对我来说最好的解决方案是更正 alignImagesHomography 方法。它实际上做了一些事情,因为处理最终图片大约需要 30 秒,但它与输入图像完全相同。
我从未使用过 findTransformECC(),您的第一个和第二个方法都使用了它,而且我不熟悉该算法。这两种方法之间的唯一区别是要求 findTransformECC() 查找的转换类型;单应变换是欧几里德变换的超集,因此第一种方法(使用 MOTION_HOMOGRAPHY)对于您的用例来说是最稳健的,尽管它也可能更慢。
the first two methods return the same picture as the "Bitmap A" given as input
如果这两种方法都正常工作,结果应该看起来与图像 A 几乎相同,即使它是从图像 B 的像素生成的。您是否检查过结果与位图 A 按位相同,并且不只是看起来相似?
我想我可以在两种方法中看到相同的错误:findTransformECC() 找到从 matBgray 到 matAgray 的映射(请参阅文档),但是 warpPerspective() 和 warpAffine() 分别用于将生成的转换应用于 matA,存储matBaligned 中的结果;它们应该应用于matB。我能看到你会得到与图像 A 按位相同的结果的唯一方法是,如果你的单应性计算失败,那么结果单应性 ("warpMatrix") 仍然包含它的初始状态,即单位矩阵。恒等单应性错误地应用于 matA(由于上述错误),当然会在 matBaligned 中给出 matA 的另一个精确副本。您可以通过在计算后打印 warpMatrix 并查看它是否是单位矩阵来检查这一点。您还应该添加一些错误检查,因为此时您根本不知道您调用的方法是否失败,或者为什么(例如输入参数错误,无法找到任何对应关系等)。
你的第三种方法alignExposures()使用的是AlignMTB,它是为HDR成像设计的,我不知道它是如何对齐的。它可能只处理 2D 平移。该方法中的循环将输出图像添加回源图像之一,因此它将饱和为白色。如果您想要的结果是将对齐的图像平均在一起(这就是您想要的吗?)您应该创建一个具有更大数据类型(例如 CV_16UC3)的新输出矩阵来累积结果图像并计算平均值,然后使用 cv::convertTo() 将该缓冲区还原为原始数据类型(例如 CV_8UC3)。
另一种我成功用于单应对齐的算法是:
- 创建一个特征检测器,例如。 SIFT,来自 features2d 或 xfeatures2d 库。我用的是AKAZE,因为SIFT有专利。
- 使用 detectAndCompute() 检测图像中的特征和描述符。
- 创建一个 BFMatcher 并使用 match() 对两个图像的特征点执行强力匹配。
- 此时如果需要,可以打印匹配的特征点,绘制到图像上并查看等
- 将找到的对应关系组织成适合 findHomography() 的两个列表(源点和目标点)。
- 使用 RANSAC 标志调用 findHomography()。
- 使用 warpPerspective() 应用单应性。
使用此方法可以有更多机会检查和验证您的数据,这将有助于调试。
我需要使用 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用户写的三种方法我都试过了。不管怎样,前两种方法return与输入的"Bitmap A"相同的图片;第三种方法确实对齐了图片,但结果图像曝光过度:
原文:https://i.imgur.com/cknHM23.jpg
对齐:https://i.imgur.com/kXCQl6x.jpg
有没有人找到不同的解决方案?还是这些方法真的有效而我做错了什么?
对我来说最好的解决方案是更正 alignImagesHomography 方法。它实际上做了一些事情,因为处理最终图片大约需要 30 秒,但它与输入图像完全相同。
我从未使用过 findTransformECC(),您的第一个和第二个方法都使用了它,而且我不熟悉该算法。这两种方法之间的唯一区别是要求 findTransformECC() 查找的转换类型;单应变换是欧几里德变换的超集,因此第一种方法(使用 MOTION_HOMOGRAPHY)对于您的用例来说是最稳健的,尽管它也可能更慢。
the first two methods return the same picture as the "Bitmap A" given as input
如果这两种方法都正常工作,结果应该看起来与图像 A 几乎相同,即使它是从图像 B 的像素生成的。您是否检查过结果与位图 A 按位相同,并且不只是看起来相似? 我想我可以在两种方法中看到相同的错误:findTransformECC() 找到从 matBgray 到 matAgray 的映射(请参阅文档),但是 warpPerspective() 和 warpAffine() 分别用于将生成的转换应用于 matA,存储matBaligned 中的结果;它们应该应用于matB。我能看到你会得到与图像 A 按位相同的结果的唯一方法是,如果你的单应性计算失败,那么结果单应性 ("warpMatrix") 仍然包含它的初始状态,即单位矩阵。恒等单应性错误地应用于 matA(由于上述错误),当然会在 matBaligned 中给出 matA 的另一个精确副本。您可以通过在计算后打印 warpMatrix 并查看它是否是单位矩阵来检查这一点。您还应该添加一些错误检查,因为此时您根本不知道您调用的方法是否失败,或者为什么(例如输入参数错误,无法找到任何对应关系等)。
你的第三种方法alignExposures()使用的是AlignMTB,它是为HDR成像设计的,我不知道它是如何对齐的。它可能只处理 2D 平移。该方法中的循环将输出图像添加回源图像之一,因此它将饱和为白色。如果您想要的结果是将对齐的图像平均在一起(这就是您想要的吗?)您应该创建一个具有更大数据类型(例如 CV_16UC3)的新输出矩阵来累积结果图像并计算平均值,然后使用 cv::convertTo() 将该缓冲区还原为原始数据类型(例如 CV_8UC3)。
另一种我成功用于单应对齐的算法是:
- 创建一个特征检测器,例如。 SIFT,来自 features2d 或 xfeatures2d 库。我用的是AKAZE,因为SIFT有专利。
- 使用 detectAndCompute() 检测图像中的特征和描述符。
- 创建一个 BFMatcher 并使用 match() 对两个图像的特征点执行强力匹配。
- 此时如果需要,可以打印匹配的特征点,绘制到图像上并查看等
- 将找到的对应关系组织成适合 findHomography() 的两个列表(源点和目标点)。
- 使用 RANSAC 标志调用 findHomography()。
- 使用 warpPerspective() 应用单应性。
使用此方法可以有更多机会检查和验证您的数据,这将有助于调试。