Раскрашивание чёрно-белых фотографий. Тонирование

  О превращении чёрно-белых фото в цветные я уже рассказывал - http://proza.ru/2021/09/19/1630   
  Нечто подобное я сделал и в новой своей программе. Отличие состоит в том, что если раньше я перекрашивал фото, работая с площадями, то сейчас для этой же цели используется кисть.
  Работать кистью удобнее, поскольку, воздействуя на изображение локально, нетрудно по ходу действия менять цвет тонирования и добиваться естественной цветопередачи.

   Что же такое – «тонирование»?
   Независимо от того, является ли фото чёрно-белым, или цветным, на экране компьютера оно создаётся пикселями трёх цветов – синим, зелёным и красным. В свою очередь, каждая из компонент цвета представляется в форме целого числа длиной 1 байт – от 0 до 255.
   Регулируя эти компоненты можно получить практически любой оттенок цвета, а если компоненты между собой равны, то тогда цвет получается серым – от чёрного (0,0,0) и до белого (255,255,255).
   Взаимное отношение компонент человеческий глаз интерпретирует как цвет, а сумму компонент – как яркость, или как светлоту тона.

   Если фотография цветная, то и цвет и светлота тона изменяется от места к месту. Если фото чёрно-белое или однотонное, то от места к месту меняется только яркость. Точки, составляющие фото, становятся то более яркими, то менее яркими, но свой цвет они не меняют.
   Например (0, 128, 254) – оранжевый и (0, 64, 127) – коричневый, это два одинаковых цвета разной яркости.
   Собственно «тонирование» заключается в том хитром процессе, когда чёрно-белая фотография раскрашивается в разные цвета, но так, чтобы яркости её точек не менялись. Как это сделать, мы сейчас обсудим.

   Заметим, что раскрашенную таким способом фотографию, можно подвергнуть повторному тонированию, перекрасив её, и выбрав для перекраски совсем другие цвета. И вновь в этом процессе будет сохранена яркость всех точек. И так – много, много раз. В этом смысле исходная фотография как бы неубиваема. Если процесс тонирования организован правильно, то фотографию таким способом испортить невозможно. Тогда как простое рисование поверх неё оставит неизгладимые следы. 

   Итак, проникшись сознанием важности процесса тонирования, приступим к математическому его описанию.
   Обозначим цвет, которым производится тонирование, через Co, его компоненты через Bo, Go и Ro, а светлоту тона через Ao. Аналогично, цвет, находящийся на отдельном пикселе фото, обозначим теми же буквами, только без индекса – C и B+G+R=A.

   Для того, чтобы обращаться с компонентами тонирующего цвета было легче, нормируем их, то есть найдём среди трёх компонент максимальную и разделим каждую из компонент на это число. Что касается компонент окрашиваемого пикселя, то просто разделим их на число 255.
   Яркость A, так же, как и яркость Ao после нормировки компонент находятся на сегменте [0,3]. Отношение их обозначим, как Z=A/Ao.

   Если A<=Ao, то компоненты нового цвета вычисляем так –
BB=Bo*Z:  GG=Go*Z:  RR=Ro*Z 
Нетрудно видеть, что BB+GG+RR=A и тогда наша задача будет решена.
Такая тонировка делается проще всего. Назовём её «простой тонировкой».

   Если же окажется, что A>Ao, то тогда нам следует призадуматься.
   Мы не можем просто так, взять и увеличить значения компонент тонирующего цвета, они могут оказаться больше единицы, что недопустимо. И как же нам быть в таком случае?
   В таком случае возможны три решения.

   Первое решение – сложное. Можно было бы подтянуть компоненты тонирующего цвета сколько возможно вверх, то есть до тех пор, пока верхняя из них достигнет уровня 1. Но мы уже сделали это. Следовательно, придётся или снизить уровень A, сохранив тонирующий цвет, или сохранить этот уровень, но изменить цвет. Можно, наконец, предложить некий алгоритм, дающий право такого выбора.

   Второе решение – самое простое. Можно просто отказаться от тонирования наиболее светлых мест. Для их тонирования просто выбрать другой, более светлый тон. И это решение не такое уж плохое – тонируя фотографию по отдельным участкам и постепенно меняя тон от самого светлого к более тёмному, можно достичь желаемого цвета пикселей, сохранив их яркость. Ясно, что этот процесс достаточно кропотливый.

   Третье решение тоже достаточно простое. Если тонирующему цвету не достаёт светлоты, то просто разбавим этот цвет белилами. Обозначим долю добавляемого белого цвета через X и потребуем, чтобы в результате получилась яркость A –

(1-X)*Bo+X + (1-X)*Go+X + (1-X)*Ro+X = A

откуда находим  X = (A-Ao)/(3-Ao)

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

   Теперь обсудим результаты. Они представлены на иллюстрации.
Крайняя левая картинка – исходная. После простой тонировки бледным цветом лица и руки, получается следующая картинка. Обратите внимание, более темные места после тонировки имеют не очень естественный, сероватый цвет. Оно и понятно – к исходному цвету была как бы добавлена чёрная краска. Тем не менее, основное условие – сохранение яркости, было выполнено. Теперь мы можем сделать тонирующий цвет более насыщенным, и уже используя этот цвет, прокрасить тени.

   Полученный второй рисунок инвертируем по цвету. Вновь установим бледный цвет, дополнительный к тому, какой мы хотим получить на тёмных местах оригинала. Тонируем этим цветом платье, закрепляем результат и делаем обратную инверсию цвета. Получаем платье с зелёным узором на светлом фоне.

   Следующий рисунок иллюстрирует работу алгоритма двухцветного тонирования. В этом алгоритме цвет тонирования связывается с яркостью окрашиваемого пикселя. Для тонирования белых пикселей берётся активный цвет, а очень тёмные пиксели тонируются цветом фона. Для промежуточных яркостей берутся промежуточные значения тонирующего цвета. Поскольку белых мест на рисунке нет, то активный цвет подбирается методом проб и получается несколько утрированным – это светлый тон, дополнительный к цвету фона. И тогда, смешиваясь с цветом фона на светлых местах, он создаёт правильную их окраску.
   На рисунке видно, что тонирование светлых и тёмных мест лица и руки получается куда более естественным.

   Поговорим теперь о причёске. Причёска у дамы на первый взгляд совершенно чёрная, поэтому зачем её тонировать? Однако если перейти на время от режима тонирования к режиму светления, и поводить кистью по волосам, то они осветлятся, и тогда обнаружится, что они вовсе не такие однородно чёрные. В них обнаружатся более светлые и слегка вьющиеся пряди.
   Осветляющая кисть оставляет не вполне равномерный след. Если водить ею вдоль прядей, то выявляются именно пряди, а если водить поперёк, то выявляются локоны. Таким способом мы можем весьма оживить причёску.
   На рисунке причёска тонировна той же парой цветов, что и лицо, но можно было выбрать и другую пару. Результаты получаются разнообразные и интересные.

   Следующий рисунок, чуть меньшего размера, показывает результат тонирования того же образца, сделанного онлайн программой в интернете. Программа управляется искусственным интеллектом и делает свою работу качественно. Правда, женщина у неё получилась цвета морковки. Если Вам такие женщины нравятся, то пожалуйста.
   Самый правый рисунок тонирован в моей программе, и он показывает, что такая же женщина, цвета морковки, может быть сделана и в ней.
))
________
2.2.2022

ДОПОЛНЕНИЕ
В программе имеется возможность считывать тон и тонировать только те места, которые отличаются от считанного тона не более чем на 15%, 10% и 5%. На иллюстрации такие зоны показаны. Красная 15% зона самая широкая.


ПРИЛОЖЕНИЕ
Текст подпрограммы, осуществляющей тонирование.
Опции CV = 7,8,9 задают режим:
7 – двухцветное тонирование
8 – тонирование без интенсивной покраски светлых тонов
9 – тонирование с добавлением белил в интенсивный цвет
СС = OldC – активный цвет    С – цвет пикселя
cBack – цвет фона
cRGB(C)- подпрограмма, извлекающая из цвета его компоненты BB GG RR
RGB(RR, GG, BB)- стандартная подпрограмма, собирающая цвет из его компонент.
ccRGB(OldC, cBack, A / 3) – подпрограмма, складывающая цвета в заданной пропорции

Public Function cCnew(CC As Long, C As Long) As Long 'п/п -Тонирование
Dim A As Single, Z As Single, B As Single, G As Single, R As Single, X As Single
Dim A1 As Single, B1 As Single, G1 As Single, R1 As Single, C1 As Long, Am As Single
Static Ao As Single, CCo As Long, Bo As Single, Go As Single, Ro As Single

  Call cRGB(C): B = BB / 255: G = GG / 255: R = RR / 255: A = B + G + R:
  If CV = 7 Then 'опция двойного тонирования
    C1 = ccRGB(OldC, cBack, A / 3): Call cRGB(C1):
    B1 = BB / 255: G1 = GG / 255: R1 = RR / 255: Am = B1: If G1 > Am Then Am = G1:
     If R1 > Am Then Am = R1:
     If Am > 0 Then Z = 1 / Am: B1 = B1 * Z: G1 = G1 * Z: R1 = R1 * Z:
    A1 = B1 + G1 + R1: If A1 = 0 Then cCnew = C1: Exit Function:
    Z = A / A1:
    If Z <= 1 Then Z = Z * 255: BB = B1 * Z: GG = G1 * Z: RR = R1 * Z: cCnew = RGB(RR, GG, BB): Exit Function
    If A1 >= 3 Then cCnew = vbWhite: Exit Function:
    X = (A - A1) / (3 - A1): B = (1 - X) * B1 + X: G = (1 - X) * G1 + X: R = (1 - X) * R1 + X:
  GoTo 7: End If '===========
  If CC = CCo Then
     Else: CCo = CC: Call cRGB(CC): Bo = BB / 255: Go = GG / 255: Ro = RR / 255:
     Am = Bo: If Go > Am Then Am = Go:
     If Ro > Am Then Am = Ro:
     If Am > 0 Then Z = 1 / Am: Bo = Bo * Z: Go = Go * Z: Ro = Ro * Z:
     Ao = Bo + Go + Ro:
  End If:
  If Ao = 0 Then cCnew = C: Exit Function:
  Z = A / Ao:
  If Z <= 1 Then Z = Z * 255: BB = Bo * Z: GG = Go * Z: RR = Ro * Z: cCnew = RGB(RR, GG, BB): Exit Function
  If CV = 8 Then cCnew = C: Exit Function
  If Ao >= 3 Then cCnew = vbWhite: Exit Function:
  X = (A - Ao) / (3 - Ao): B = (1 - X) * Bo + X: G = (1 - X) * Go + X: R = (1 - X) * Ro + X:
7  BB = B * 255: GG = G * 255: RR = R * 255:
  cCnew = RGB(RR, GG, BB):
End Function


Рецензии
Приветствую. Случайно не подскажете, как мне растянуть в спираль фотографию? Хочу обложку для книги сделать. И что-то не найду в инете описание процесса. Сам я в этих делах дилетант, только Paint на компе.

Взз   18.02.2023 17:56     Заявить о нарушении
Вы хотите нечто подобное сделать? - http://proza.ru/2022/05/30/756
Это довольно просто - находите в интернете чёрную спираль на белом фоне. Ослабляете яркость настолько, чтобы фон был совершенно белым (есть программы онлайн, которые делают это), и накладываете в Паинте спираль, установив прозрачный белый фон, на своё обесцвеченное фото.
Если нужно это или что иное, напишите подробнее, и опубликуйте фото, и я Вам помогу.

Дмитрий Маштаков   19.02.2023 12:40   Заявить о нарушении
На это произведение написаны 4 рецензии, здесь отображается последняя, остальные - в полном списке.