Регистрация изображения и наложение фокуса

Предыстория: я пытаюсь выровнять изображения для приложения стекирования фокуса с помощью смартфона. Ссылки на изображения:

Первый в стеке: 1, последний в стеке: 2, окончательные сложенные изображения: 3

т.е. изображения номинально одинаковы, НО содержат:

  1. Систематическое изменение FOCUS при смещении фокальной плоскости между изображениями
  2. Немного меняется увеличение (функция смартфона при изменении фокуса!)
  3. Камера слегка двигается из-за случайных вибраций.

Изображения должны быть выровнены для работы приложения фокус-стекинга.

Прогресс на сегодняшний день: я использую OpenCV findTransformECC() для выравнивания. Он хорошо работает после некоторых экспериментов, т.е. см. cv2.MOTION_EUCLIDEAN для warp_mode в методе выравнивания изображения ECC, который был полезен для улучшения инициализации матрицы деформации:

  1. Изображения выровнены на уровне пикселей
  2. 60 секунд для обработки 8-мегапиксельного изображения (1 с для 0,5-мегапиксельного изображения) (на портативном ПК трехлетней давности с библиотеками выпуска OpenCV)

См. ссылку на сложенное изображение выше.

Я кратко изучил детектор признаков (SIFT). Он плохо выравнивал изображения, по-видимому, из-за изменения фокуса между изображениями.

Код:

 int scale = 1;
 int scaleSmall = 4;
 float scaleDiff = scaleSmall / scale;

     for (i = 0; i< numImages; i++) {
        file = dir + image + to_string(i) + ".jpg";
        col[i] = imread(file);

        resize(col[i], z[i], Size(col[i].cols/scale, col[i].rows/scale));       
        cvtColor(z[i], zg[i], CV_BGR2GRAY);
        resize(zg[i], zgSmall[i],  Size(col[i].cols / scaleSmall, col[i].rows / scaleSmall));
     }

    // Set a 2x3 or 3x3 warp matrix depending on the motion model.
    // See https://www.learnopencv.com/image-alignment-ecc-in-opencv-c-python/
    // Define the motion model
    const int warp_mode = MOTION_HOMOGRAPHY;

    // Initialize the matrix to identity
    if (warp_mode == MOTION_HOMOGRAPHY) {
        warp_init = Mat::eye(3, 3, CV_32F);
        warp_matrix = Mat::eye(3, 3, CV_32F);
        warp_matrix_prev = Mat::eye(3, 3, CV_32F);
        scaleTX = (Mat_<float>(3, 3) << 1, 1, scaleDiff, 1, 1, scaleDiff, 1 / scaleDiff, 1 / scaleDiff, 1);
    }
    else {
        warp_init = Mat::eye(2, 3, CV_32F);
        scaleTX = Mat::eye(2, 3, CV_32F);
        warp_matrix = Mat::eye(2, 3, CV_32F);
        warp_matrix_prev = Mat::eye(2, 3, CV_32F);
        scaleTX = (Mat_<float>(2, 3) << 1, 1, scaleDiff, 1, 1, scaleDiff);
    }

    // Specify the number of iterations.
    int number_of_iterations = 5000;

    // Specify the threshold of the increment
    // in the correlation coefficient between two iterations
    double termination_eps = 1e-8;

    // Define termination criteria
    TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS, number_of_iterations, termination_eps);

    for (i = 1; i < numImages; i++) {
        // Check images right size
        if (zg[0].rows < 10 || zg[1].rows < 10)
            return;

        // Run the ECC algorithm at start to get an initial guess. The results are stored in warp_matrix.
        if (i == 1) {
            findTransformECC(zgSmall[0], zgSmall[i], warp_init, warp_mode, criteria     );

            // See https://stackoverflow.com/questions/45997891/cv2-motion-euclidean-for-the-warp-mode-in-ecc-image-alignment-method
            warp_matrix = warp_init * scaleTX;
        }

        // Warp Matrix from previous iteration is used as initialisation  
        findTransformECC(zg[0], zg[i], warp_matrix, warp_mode,  criteria);

        if (warp_mode != MOTION_HOMOGRAPHY) {
            warpAffine(zg[i], ag[i], warp_matrix, zg[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
            warpAffine(z[i], acol[i], warp_matrix, zg[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
        }
        else {
            // Use warpPerspective for Homography
            warpPerspective(z[i], acol[i], warp_matrix, z[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
            warpPerspective(zg[i], ag[i], warp_matrix, zg[i].size(), INTER_LINEAR + WARP_INVERSE_MAP);
           }
        }
    }

Вопрос. Можно ли значительно повысить скорость регистрации изображений (при использовании того же оборудования)?


person MartinR    schedule 16.09.2019    source источник
comment
Можете ли вы разместить образцовые изображения? Какие настройки вы используете для выравнивания изображений? Также, пожалуйста, опубликуйте код.   -  person Piotr Siekański    schedule 16.09.2019
comment
См. ссылки на изображения и вставленный код   -  person MartinR    schedule 17.09.2019


Ответы (1)


есть как минимум 3 улучшения, которые можно сделать:

  1. 5000 итераций могут быть ненужными. Попробуйте ограничить его до 500. Кроме того, может помочь преобразование изображений в градиентный домен. См. функцию GetGradient из этого учебника.

  2. Вы можете предположить, что эффекты перспективы незначительны, поэтому вы можете изменить warp_mode на MOTION_AFFINE, чтобы ограничить количество степеней свободы с 8 до 6.

  3. Вы также можете попробовать другой, гораздо более быстрый подход, основанный на фазовой корреляции (в частотной области). Стандартным образом он только оценивает перевод между изображениями, но вы можете перевести их в логарифмическое полярное пространство, чтобы получить инвариантность перевода, поворота и масштаба. Этот код реализует третий подход.

person Piotr Siekański    schedule 18.09.2019
comment
Подход с фазовой корреляцией очень быстрый, но я изо всех сил пытаюсь получить достаточную точность. Какие-нибудь мысли? Подходит ли он для сравнения изображения с эквивалентом, который не в фокусе и немного не выровнен? - person MartinR; 21.09.2019