Как получить эффект Magic Color, например, Cam Scanner, используя OpenCV

Это исходное изображение.

Оригнальное изображение

Cam Scanner Магический эффект цвета Эффект сканера Cam

Мой фильтр на изображении.

Мой фильтр

Я меняю контраст изображения.

dst.convertTo(dst, -1, 2, 0);

Затем, используя гауссовское размытие для сглаживания.

cv::GaussianBlur(dst,result,cv::Size(0,0),3);
cv::addWeighted(dst, 1.5, result, -0.5, 0, result);

Что мне делать, чтобы добиться такого эффекта на моем изображении?

UPDATE

После выравнивания гистограммы -

vector<Mat> channels;
Mat img_hist_equalized;
cvtColor(dst, img_hist_equalized, CV_BGR2YCrCb);
split(img_hist_equalized,channels);
equalizeHist(channels[0], channels[0]);
merge(channels,img_hist_equalized);
cvtColor(img_hist_equalized, img_hist_equalized, CV_YCrCb2BGR);

Уравнивание гистограммы

Ответ 1

Приложение для каскадеров может использовать какой-то сложный алгоритм для обработки различных случаев молнии и т.д. Но я попытаюсь осветить базовый подход к такой проблеме. Основная идея здесь - Бинаризация данного ввода image, или, точнее, мы можем сказать Порог заданное изображение. Если вы посмотрите на документацию OpenCV, существует множество ссылок на пороговое значение данного изображения. Поэтому давайте начнем с документация.

  • Глобальный порог. В этом подходе мы предполагаем, что значение интенсивности переднего плана всегда ниже определенного значения. В контексте печатных листов мы предполагаем, что цвет чернил всегда черный и цвет бумаги является однородным, а интенсивность больше, чем интенсивность цвета чернил, поэтому мы надежно принимаем некоторый порог (скажем, 40), (макс. 255) и порог входного изображения как:

    ret, thresh1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
    

    введите описание изображения здесь

    ret, thresh1 = cv2.threshold(img, 130, 255, cv2.THRESH_BINARY)
    

    введите описание изображения здесь

    Существует много недостатков этого метода: во-первых, он НЕ не зависит от дисперсии интенсивности. Поэтому вероятность того, что вы можете точно оценить пороговое значение, которое отделяет текст от данного изображение, оно имеет очень ограниченные приложения, может применяться только в том случае, если фоновая бумага точно белая с минимальным изменением интенсивности, поэтому этот процесс нельзя использовать для изображений Real world.

  • Адаптивное пороговое значение. Этот метод охватывает проблему изменения интенсивности в данном изображении, здесь пороговое значение выполняется для значений соседних пикселей, поэтому переходы от меньшей интенсивности к высшей и наоборот успешно захвачены этим методом как:

    thresh = cv2.adaptiveThreshold(original_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
    

    введите описание изображения здесь

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

  • Бинаризация Otu. Это еще один приятный подход, который интеллектуально вычисляет пороговое значение между максимами. В некоторых случаях он может работать очень хорошо, но, похоже, ваш случай.

    ret2,thresh = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    

    введите описание изображения здесь

В основном он делает то же самое глобальное пороговое значение. Но теперь пороговое значение рассчитывается автоматически таким образом, что порог лежит между 2 пиками и, следовательно, сегментирует чернила из бумаги.

Рекомендуемый метод: Я думаю, что наилучшим подходом для начала является Adaptive Thresholding, вы можете попробовать некоторые другие методы предварительной обработки, такие как резкость изображения, Уравнивание гистограммы и т.д. и проанализируйте, как он создает более реалистичный вывод. Вы также можете попытаться выполнить некоторую пост-обработку, такую ​​как шумоподавление изображения, Морфологические операции

Я попытался разобрать изображение и нашел его более эффективным для других подходов,

denoised = cv2.fastNlMeansDenoising(thresh, 11, 31, 9) # you may experiment with the constants here

введите описание изображения здесь

Но я приветствую вас, чтобы попробовать различные комбинации вышеупомянутых подходов, чтобы посмотреть, какой из них работает для всех случаев.

Ответ 2

Я написал код, который делает такие вещи, хотя не с OpenCV.

Как правило, я анализировал гистограмму, подсчитал, какие "белые" и "черные" основаны на гистограмме, а затем масштабируйте значения изображений, чтобы черный был масштабирован ниже 0, а белый был масштабирован выше 1 (или 255 в зависимости от ваше представление), наконец, зажатие значений цвета.

Однако с OpenCV может быть проще. Попробуйте использовать выравнивание гистограммы на вашей обрезанной странице перед применением контрастного фильтра - это должно более распространять значения пикселей, чтобы корректировать контрастность более надежно в других ситуациях. Вы можете попробовать использовать выравнивание гистограммы локализованного, чтобы помочь уменьшить градиенты на обрезанном изображении из-за освещения, но это может вызвать проблемы с пустыми областями страницы.

Ответ 3

Я понимаю, что немного опаздываю в игру, но я нашел это простое и простое решение:

src.convertTo(dst, -1, 1.9, -80);

src и dst могут быть одним и тем же изображением, если вы работаете в конвейере обработки.