Удалить цветовой оттенок с помощью libvips

У меня есть изображения sRGB с цветовыми оттенками. Чтобы удалить его вручную, я обычно использую Photoshop Level Adjustments. В Photoshop также есть инструменты для этого: Автоконтраст или, что еще лучше, Автотон, который также учитывает тени, средние тона и блики.

Если я удаляю приведение вручную, я настраиваю каждый из каналов RGB по отдельности, чтобы самые темные пиксели устанавливались как чисто черные, а самые светлые — как чисто белые, а затем перераспределялись все остальные значения (расширяя гистограмму). Это простой подход, но он показывает хорошие результаты для моих изображений.

В моем приложении node.js я использую sharp для обработки изображений, использующей libvips в качестве механизма обработки. Я пытался удалить приведение с помощью .normalize(), но эта команда работает на всех каналах вместе, а не отдельно для каждого из каналов RGB. Так что это не работает для меня. Я тоже задавал этот вопрос на странице проекта Sharp. Я протестировал предложение от lovell, чтобы попробовать его с hist_local, но результаты мне непригодны.

Теперь я хотел бы узнать, как это можно сделать с помощью родных libvips. Я играл с графическим интерфейсом nip2 и различными командами, но не мог понять, как этого можно достичь:

  1. Гистограмма > Выровнять гистограмму > Глобальный => Изображение выглядит слишком насыщенным
  2. Изображение> Уровни> Масштабировать до 0–255 => Не все каналы распространяются от 0 до 255 (я не совсем понимаю, что делает эта команда?)

Спасибо за каждую подсказку!

Дополнение Вот пример с картинками из фотошопа, чтобы показать, что я хочу.

Исходное изображение представляет собой изображение кадра с пленочного негатива. Изображение до обработки

Шаг 1 Инвертировать изображение Изображение после инверсии

Шаг 2 с использованием автоматического тона в Photoshop (работает так же, как в моем описании выше о ручном удалении цветового оттенка) Изображение после автоматического тона

Последняя картинка меня устраивает.


person groboter    schedule 09.01.2020    source источник


Ответы (3)


nip2 имеет для этого пункт меню.

Загрузите изображение и отметьте на нем область, содержащую область, которую вы хотите сделать нейтральной. Это может быть любая светлота, не обязательно белая.

  • Используйте File / Open, чтобы открыть диалоговое окно файла, и вы должны увидеть изображение, загруженное в вашу рабочую область, в виде миниатюры.
  • Дважды щелкните миниатюру, чтобы открыть окно просмотра изображения.
  • В окне просмотра увеличьте масштаб и переместитесь в нужное место. В руководстве пользователя (нажмите F1) есть раздел, посвященный навигации по изображениям.
  • Удерживая нажатой клавишу CTRL, щелкните и перетащите вниз и вправо, чтобы отметить прямоугольную область.

окно просмотра изображения с отмеченной областью

Вернувшись в главное окно, нажмите Инструменты/Задачи/Захват/Баланс белого. Вы должны увидеть что-то вроде:

виджет баланса белого

Вы можете изменить размер области, чтобы изменить нейтральную точку. Используйте палитру цветов, чтобы установить, что означает белый цвет. Вы можете сделать другие белые с помощью (например) Color/New/Color от CCT и связать их вместе.

  • Нажмите Цвет / Новый / Цвет из CCT, чтобы сделать палитру цветов из CCT (коррелированная цветовая температура) — температура в Кельвинах этого белого.
  • Установите что-нибудь интересное, например, 4800 для теплого белого.
  • Нажмите на формулу для A5.white, чтобы отредактировать ее, и введите ячейку виджета CCT (в данном случае A7).

Теперь вы можете перетащить область, чтобы настроить пиксели, чтобы установить нейтраль, и перетащить ползунок CCT, чтобы установить температуру.

нестандартный белый

Поиск вещей в меню набора инструментов может раздражать. Есть штука для поиска тулкитов: в главном окне жмем Вид/Браузер тулкитов. Вы можете ввести что-то вроде «белый», и он покажет соответствующие записи инструментария.

person jcupitt    schedule 10.01.2020
comment
Привет jcupitt большое спасибо за это подробное объяснение! Я попробовал это, но я не получаю таких же результатов, как с моими экшенами Photoshop. Я добавил более подробную информацию, а также фотографии, показывающие мои шаги в PS в моем первом вопросе. - person groboter; 11.01.2020
comment
Шаг 1 Invert отлично работает с Sharp или libvips. Но я не знаю, как достичь Step2. Я могу выбрать минимальные и максимальные значения для каждого канала RGB (используя статистику), но я не знаю, как использовать эти значения для распределения гистограммы каждого канала по всему диапазону (0...255). - person groboter; 11.01.2020
comment
Ваш пример PS выглядит так, будто он просто независимо растягивает три канала. Чтобы сделать это в nip2, разделите полосы, масштабируйте их, а затем соедините их. Я сделаю другой ответ. - person jcupitt; 11.01.2020
comment
Я только что попробовал ваши предложения, используя: Image->Band->Extract для каждого канала, а затем Image->Levels->Scale 0...255 и, наконец, Image->Join->Bandwise Join. Это дает хороший результат со светло-голубым оттенком, но PS лучше, потому что синий оттенок светлее. Я подозреваю, что PS сокращает несколько самых низких и самых высоких значений на гистограмме. Можно ли установить такие ограничения в libvips? - person groboter; 11.01.2020
comment
Да, я думаю, что PS игнорирует несколько процентов пикселей на каждом конце при расчете растяжения. Вы можете сделать то же самое в nip2, найдя нормализованную кумулятивную гистограмму, пороговое значение и найдя индекс. - person jcupitt; 11.01.2020
comment
Извините, я пытался реализовать ваши предложения, но я не знаю, как это сделать. Как я могу получить нормализованную кумулятивную гистограмму (интегрировать?) и выполнить пороговое значение, найти индекс и построить окончательное изображение? Извините, что снова беспокою! - person groboter; 12.01.2020

Вот еще один ответ, но с использованием pyvips и ответов на предыдущие комментарии. Я не хотел удалять первый ответ, так как он все еще казался полезным.

Эта версия находит гистограмму изображения, ищет пороговые значения, которые будут выбирать 0,5% и 99,5% пикселей в каждой полосе изображения, а затем масштабирует изображение так, чтобы эти значения пикселей стали равными 0 и 255.

import sys
import pyvips

# trim off this percentage of pixels from the top and bottom
trim_percent = 0.5

def percent(hist, percentage):
    """From a histogram, find the threshold above which lie 
    @percentage of pixels."""
    # normalised cumulative histogram
    norm = hist.hist_cum().hist_norm() 

    # column and row profile over percentage
    c, r = (norm > norm.width * percentage / 100).profile()

    return r.avg()

image = pyvips.Image.new_from_file(sys.argv[1])

# photographic negative
image = image.invert()

# find image histogram, split to set of separate bands
bands = image.hist_find().bandsplit()

# for each band, the low and high thresholds
low = [percent(band, trim_percent) for band in bands]
high = [percent(band, 100 - trim_percent) for band in bands]

# rescale image 
scale = [255.0 / (h - l) for h, l in zip(high, low)]
image = (image - low) * scale

image.write_to_file(sys.argv[2])

Кажется, это дает примерно такие же результаты для кнопки PS. Если я бегу:

$ ./autolevel.py ~/pics/before.jpg x.jpg

Я понимаю:

результат скрипта на примере изображения

person jcupitt    schedule 17.01.2020
comment
Спасибо за это! Теперь пойми лучше. Я также нашел возможное решение, но без libvips, которое, как мне кажется, проще реализовать в node.js. Потому что насколько я понимаю шарп не поддерживает некоторые нужные команды для вашего решения. Я публикую новый ответ с моим решением. - person groboter; 17.01.2020

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

Это точно такое же решение, как Джон описывает в своем втором ответе, но в виде небольшого фрагмента c-кода.

Сейчас я пытаюсь использовать его как аддон C/C++ с N-API под node.js.

person groboter    schedule 17.01.2020