Хобрук: Ваш путь к мастерству в программировании

как сгладить 2 разных слоя изображения?

У меня есть 2 объекта Mat, overlay и background.

Как разместить мат overlay поверх мата background так, чтобы только непрозрачные пиксели мата overlay полностью закрывали мат background?

Я пробовал addWeighted(), который сочетает в себе 2 мата, но оба «слоя» все еще видны.

  • Мат overlay имеет прозрачный канал, а мат background — нет.
  • Пиксель в мате overlay либо полностью прозрачен, либо полностью затемнен.
  • Оба коврика одинакового размера.
09.05.2016

  • Проверьте это, вы должны понять 09.05.2016

Ответы:


1

Функция addWeighted не будет работать, поскольку она будет использовать одно и то же значение альфа-канала для всех пикселей. Чтобы сделать именно то, что вы говорите, чтобы заменить только непрозрачные значения в фоновом режиме, вы можете создать для этого небольшую функцию, например:

cv::Mat blending(cv::Mat& overlay, cv::Mat& background){
    //must have same size for this to work
    assert(overlay.cols == background.cols && overlay.rows == background.rows);
    cv::Mat result = background.clone();
    for (int i = 0; i < result.rows; i++){
        for (int j = 0; j < result.cols; j++){
            cv::Vec4b pix = overlay.at<cv::Vec4b>(i,j);
            if (pix[3] == 0){
                result.at<cv::Vec3b>(i,j) = cv::Vec3b(pix[0], pix[1], pix[2]);
            }
        }
    }
    return result;
}

Я не уверен, что прозрачное значение в opencv равно 0 или 255, поэтому измените его соответствующим образом.... Я думаю, что это 0 для непрозрачного и 255 для полностью прозрачного.

Если вы хотите использовать значение альфа-канала в качестве скорости смешивания, то немного измените его на это:

cv::Mat blending(cv::Mat& overlay, cv::Mat& background){
    //must have same size for this to work
    assert(overlay.cols == background.cols && overlay.rows == background.rows);
    cv::Mat result = background.clone();
    for (int i = 0; i < result.rows; i++){
        for (int j = 0; j < result.cols; j++){
            cv::Vec4b pix = overlay.at<cv::Vec4b>(i,j);
            double alphaRate = 1.0 - pix[3]/255.0;
            result.at<cv::Vec3b>(i,j) = (1.0 - alphaRate) * cv::Vec3b(pix[0], pix[1], pix[2]) + result.at<cv::Vec3b>(i,j) * alphaRate;
        }
    }
    return result;
}

Извините за код на C++, а не на JAVA, но я думаю, что вы можете получить представление. В основном это просто цикл в пикселях и изменение пикселей в копии фона на пиксели наложения, если они не прозрачны.

* ИЗМЕНИТЬ *

Я отвечу на ваш комментарий этим редактированием, так как это может занять место. Проблема в том, как работает матрица OpenCV. Для изображения с альфой данные организованы в виде массива типа BGRA BGRA .... BGRA, а основные операции, такие как сложение, умножение и т. д., работают в матрицах с одинаковыми размерами..... всегда можно попробовать разделить матрицу с помощью разделения ( это перезапишет матрицу, так что это может быть медленным), затем измените альфа-канал на двойной (опять же, перепишите), а затем выполните умножение и добавление матриц. Это должно быть быстрее, так как OpenCV оптимизирует эти функции.... также вы можете сделать это в графическом процессоре....

Что-то вроде этого:

cv::Mat blending(cv::Mat& overlay, cv::Mat& background){
    std::vector<cv::Mat> channels;
    cv::split(overlay, channels);
    channels[3].convertTo(channels[3], CV_64F, 1.0/255.0);
    cv::Mat newOverlay, result;
    cv::merge(channels, newOverlay);
    result = newOverlay * channels[3] + ((1 - channels[3]) * background);
    return result;
}

Не уверен, позволяет ли OpenCV CV_8U умножать CV_64F, будет ли это быстрее или нет.... но может быть.

Кроме того, те, у которых есть циклы, не имеют проблем с потоками, поэтому их можно оптимизировать... выполнение этого в режиме выпуска также значительно увеличит скорость, поскольку функция .at OpenCV выполняет несколько утверждений... что в режиме выпуска нет Выполнено. Не уверен, что это можно изменить в JAVA...

09.05.2016
  • Этот подход слишком медленный для меня, так как я работаю с 12-мегапиксельными изображениями или больше. Можете ли вы предоставить реализацию с использованием функций матричного массива, таких как add(), subtract(), multiply() и т. д.? 09.05.2016

  • 2

    Мне удалось перенести отредактированный ответ api55 для java:

    private void merge(Mat background, Mat overlay) {
                List<Mat> backgroundChannels = new ArrayList<>();
                Core.split(background, backgroundChannels);
    
            List<Mat> overlayChannels = new ArrayList<>();
            Core.split(overlay, overlayChannels);
    
            // compute "alphaRate = 1 - overlayAlpha / 255"
            Mat overlayAlphaChannel = overlayChannels.get(3);
            Mat alphaRate = new Mat(overlayAlphaChannel.size(), overlayAlphaChannel.type());
            Core.divide(overlayAlphaChannel, new Scalar(255), alphaRate);
            Core.absdiff(alphaRate, new Scalar(1), alphaRate);
    
            for (int i = 0; i < 3; i++) {
                // compute "(1 - alphaRate) * overlay"
                Mat overlayChannel = overlayChannels.get(i);
                Mat temp = new Mat(alphaRate.size(), alphaRate.type());
                Core.absdiff(alphaRate, new Scalar(1), temp);
                Core.multiply(temp, overlayChannel, overlayChannel);
                temp.release();
    
                // compute "background * alphaRate"
                Mat backgroundChannel = backgroundChannels.get(i);
                Core.multiply(backgroundChannel, alphaRate, backgroundChannel);
    
                // compute the merged channel
                Core.add(backgroundChannel, overlayChannel, backgroundChannel);
            }
    
            alphaRate.release();
            Core.merge(backgroundChannels, background);
        }
    

    это намного быстрее по сравнению с вычислением двойного вложенного цикла.

    12.05.2016
    Новые материалы

    Учебные заметки JavaScript Object Oriented Labs
    Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

    Разбор строк запроса в vue.js
    Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

    Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
    «Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..