Android: выравнивание изображений
Мне нужно выровнять разные изображения в моем приложении для Android, используя библиотеку OpenCV. Я нашел решение в этой теме.
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 секунд, но затем он точно равен входному изображению.
1 ответ
Я никогда не использовал findTransformECC(), используемый вашим первым и вторым методами, и я не знаком с этим алгоритмом. Единственное различие между этими двумя методами заключается в том, что тип преобразования findTransformECC () предлагается найти; Гомографические преобразования - это расширенный набор евклидовых преобразований, поэтому первый метод (использующий MOTION_HOMOGRAPHY) будет наиболее устойчивым для вашего варианта использования, хотя он также может быть медленнее.
первые два метода возвращают ту же картинку, что и "Растровое изображение A", указанное в качестве входных данных
Если эти два метода работают правильно, результат должен выглядеть почти идентично изображению A, даже если он получен из пикселей изображения B. Проверяли ли вы, что результат поразрядно идентичен растровому изображению A, а не просто выглядит похожим? Я думаю, что я вижу ту же ошибку в обоих методах: findTransformECC() находит отображение из matBgray на matAgray (см. Документы), но warpPerspective() и warpAffine(), соответственно, используются для применения результирующего преобразования к matA, сохраняя результат в matBaligned; они должны применяться к matB. Единственный способ увидеть, что вы получили бы результат, который побитово идентичен изображению А, - это если ваш расчет гомографии завершится неудачно, так что результат гомографии ("warpMatrix") все еще содержит свое начальное состояние, которое является единичной матрицей. Гомография идентичности, неправильно примененная к matA (из-за вышеуказанной ошибки), конечно, даст другую точную копию matA в matBaligned. Вы можете проверить это, распечатав warpMatrix после расчета и посмотрев, является ли это единичной матрицей. Вы также должны добавить некоторую проверку ошибок, потому что в данный момент вы не знаете, что методы, которые вы вызываете, вообще терпят неудачу, или почему (например, неверные входные параметры, не удается найти никаких соответствий и т. Д.).
Ваш третий метод, alignExposures(), использует AlignMTB, который предназначен для создания изображений HDR, и я не знаю, как он выполняет выравнивание. Он может обрабатывать только 2D-перевод. Цикл в этом методе добавляет выходные изображения обратно к одному из исходных изображений, поэтому он будет насыщаться белым. Если вы хотите, чтобы выровненные изображения были усреднены вместе (это то, что вы хотите?), Вы должны создать новую выходную матрицу с большим типом данных (например, CV_16UC3), чтобы накапливать результирующие изображения и вычислять среднее значение, затем используйте cv::convertTo(), чтобы уменьшить этот буфер до исходного типа данных (например, CV_8UC3).
Другой алгоритм, который я успешно использовал для гомографического выравнивания:
- Создать детектор функций, например. SIFT, из библиотеки features2d или xfeatures2d. Я использовал AKAZE, потому что SIFT запатентован.
- Обнаружение функций и дескрипторов на обоих ваших изображениях с помощью detectAndCompute().
- Создайте BFMatcher и выполните сопоставление с помощью грубой силы характерных точек обоих изображений с помощью match().
- Если вы хотите на этом этапе, вы можете напечатать соответствующие характерные точки, нарисовать их на изображениях и просмотреть их и т. Д. И т. Д.
- Организовать найденные соответствия в два списка (исходная и конечная точки), подходящих для findHomography().
- Вызовите findHomography (), используя флаг RANSAC.
- Примените гомографию, используя warpPerspective().
С этим методом есть больше возможностей для проверки и проверки ваших данных, что поможет с отладкой.