Окантовка пятна и размытие следа кисти

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

  И это правда. Красоту мазка в форме сопутствующих ему артефактов окантовки, приходится специально программировать - http://proza.ru/2023/05/25/1065
  Мой рассказ как раз об этом программировании и будет. К сожалению, эти и подобные опции компьютерного рисования, хоть изредка применяются, но нигде не описываются. И в самом деле - вот перед вами мазок, сделанный компьютерной кистью, плох он или хорош, дело другое, но стоит задача - создать вокруг мазка контур, или окружить мазок ореолом расплывшейся краски.
  Как это сделать? Какие алгоритмы использовать? Какие вычислительные средства применить? Никто и ничего про это не пишет. Догадывайся, мол, сам.
  Вот потому я про это и рассказываю.

     НЕ ПРАВДА ЛИ, ЭТО ЭФФЕКТНО

  Посмотрите на иллюстрацию - не правда ли, очень красиво и эффектно по ней проложены мазки, а ведь я не делал их специально, а только проверял эффекты окантовки и размытия, пробуя для них различные параметры.
  Кисть №1, с которой я делал эти пробы, и сама по себе достаточно живописна, она имеет более тёмный кант, который можно разворачивать в ту или другую сторону, внутрь, или наружу. Выставив постепенное расширение, можно рисовать узенькие веточки, те самые, размытые туманом.
  Размытые – это образно, а на самом деле - окружённые специально созданным ореолом.
  Некоторые пятна окантованы более тёмным цветом. Для этого использовалась опция Ф2 кнопки «Ф1», которая находится на панели инструментов слева, и, пока находится в состоянии 1, ничего не делает.
  Опция Ф3 этой кнопки организует попеременную окантовку, меняя активный цвет, на тот цвет, который был выставлен как цвет фона, и через некоторое время возвращая его обратно. Подобные пятна с жёлто-чёрной окантовкой вы тоже можете видеть на иллюстрации.

  У опции Ф2 имеются опции рангом ниже – Ф2’, Ф2| и Ф2i. Они выставляются кликами правой кнопки мыши по кнопке Ф2. О них я расскажу позже, а сейчас объясню, как это всё работает.

     КАК ДЕЛАЕТСЯ ОКАНТОВКА

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

  Алгоритм оконтуривания поясняется картинками на иллюстрации справа.
  След кисти там представлен окрашенными квадратиками-пикселями, каждый из которых имеет 111 в нижних своих битах, а окружение следа имеет в нижних битах 000. Это пространство на картинке условно белое.

  Процесс оконтуривания начинается с поисков границы пятна. Начинается поиск с пикселя, на который был опущен стилус – на картинке он помечен значком х. Ищем пиксель с 000 в первых битах, поочерёдно продвигаясь на один пиксель то вправо, то влево.
  Предположим, что первой мы обнаружили границу так, как показано на картинке, то есть справа. Тогда мы отступаем на один пиксель назад, устанавливаем на нём проверяющую «вертушку» и красим этот пиксель в цвет контура.
  «Вертушка» с центром, помеченным о, показана на пояснительном рисунке сверху. Начало проверки устанавливаем на обнаруженный 000 пиксель, то есть в положение 3, а проверяем пиксель следующий по счёту, то есть пиксель под цифрой 4.
  По рисунку видно, что там мы находим пиксель 000, поэтому продвигаемся по вертушке на следующую цифру - 4, а проверяем пиксель под цифрой 5. Там мы находим 111, это то, что мы искали, этот пиксель мы окрашиваем в цвет контура и центр вертушки переносим на него. Новое начало проверки устанавливаем на то место, с которого перенесли вертушку, то есть в положение 1.

  При такой установке некоторые пиксели будут проверены по второму разу, но чтобы закончить проверку, нужно обязательно попасть точно на тот пиксель, который проверили первым, а при другом алгоритме этого, как правило, не получается. Тогда программа зацикливается, и после нахождения сорока тысяч одних и тех же точек процесс принудительно обрывается. И окантовка при этом иногда не получается. В чём тут дело, я как следует не разобрался, Однако, след может содержать дырки, то есть пиксели 000 среди 111, возможно поэтому так и выходит.
  Пишу это для того, чтобы Вы не думали, что труд программиста, это как бы верх предсказуемости и точности. Вовсе нет. Программирование похоже на исследовательскую работу. Многие эффекты не предусматриваются и появляются совершенно неожиданно. Можно годами иметь в программе ошибку и не обнаружить её.
 
  Как бы то ни было, но алгоритм работает хорошо, и оконтуривание получается таким, каким вы видите его на иллюстрации и на последнем пояснительном рисунке справа снизу.
  На самом краю иллюстрации справа показано в увеличенном виде, каким сложным может быть край пятна. Окантовка серого следа сделана чёрным цветом, а фон, по которому делалась окантовка, то есть, пиксели, лишённые первых бит, показаны условно, перекрашенными в зелёный цвет. Видно, что, несмотря на зернистость и сильную разреженность следа, окантовка по описанному алгоритму прошла успешно. Попав на визуально ожидаемый край пятна, но оставив редкие периферические точки снаружи. И я даже не знаю, могла бы так окантовать разреженное пятно какая-нибудь другая программа.

     ДРУГИЕ ОПЦИИ ОКАНТОВКИ

  Опция окантовки Ф2 рисует контур тем цветом, который выставлен как активный, и при этом устанавливает в 111 первые биты этого цвета. При её повторении с другим цветом она в точности повторит эту операцию, получится эта же тонкая линия, только она поменяет свой цвет. Что в общем-то и не плохо – если цвет окантовки не понравился, скажем, она показалась очень яркой, то мы, чтобы не оставлять на рисунке лишних следов, можем заблокировать рисование и, заменив цвет на более подходящий, просто коснуться стилусом точки внутри следа, а потом поднять его. Опять при этом будет найдена ближайшая граница и, в большинстве случаев, сделана всё та же окантовка, но только другим цветом.
  И только если пятно разрежено и первая окантовка не получилась, можно ожидать, что окантовка пойдёт по другому. И это тоже неплохо – если окантовка следа на получается целиком, то кликая по нему в разных местах, можно окантовать след по частям.

  Опция окантовки Ф2’ делает всё то же самое, но не устанавливает 111 в первые биты цвета, а ставит в них 000. Полученную окантовку тут же повторить не удастся, поскольку если на этапе поиска границы будет найден цвет уже сделанной окантовки, то программа закончит свою работу и будет рекомендовано сменить цвет.
  Зато, после смены цвета, даже самой небольшой и незаметной, касанием стилуса окантовку можно нарастить изнутри, сделав её более заметной. Теперь след будет окантован изнутри двумя контурами разного цвета. Такую возможность тоже неплохо иметь.

  Следующая опция окантовки – Ф2| оконтуривает след линией более тёмной, чем найденные его краевые пиксели. Цвет этой окантовки не постоянный, он будет меняться, поддерживая цвет граничных пикселей. Если полученный эффект недостаточен, то его можно усиливать, касаясь следа ещё раз.

  Последняя опция – Ф2i окантовку не делает, пограничные пиксели она оставляет в том же цвете. Зато, используя найденный на границе цвет, она делает снаружи границы ореол, подмешивая найденный цвет к заграничному цвету в пропорции 1/(5R), где R – радиус пятна рисования кисти. Ширина ореола равна этому радиусу.
  Полученные цвета имеют 000 в первых битах, и повторными касаниями следа плотность ореола можно постепенно наращивать. Внутреннюю же часть пятна и его границы в цвете не меняются – Ореол преобразует цвет только тех пикселей, до которых он дотягивается, и которые имеют 000 в первых битах цвета.
  Чтобы ореол выглядел естественно, не каждая точка контура включается в его создание, а избирается случайным образом, в среднем каждая вторая. Кроме того, для размеров пятна рисования большего чем 4, изредка, с вероятностью 50%, пятно ореола уменьшается вдвое. В результате этих специальных усилий, размытие краски в форме ореола вокруг следа получается весьма натуральным.
  На иллюстрации с увеличением в 4 раза показана чёрная окантовка небольшого пятна и размытие вокруг пятна, представляющего собой маленький чёрный квадрат.

  Окантовка пятна происходит очень быстро, и задержки в ней почти не чувствуется, тогда как для размытия, для каждого второго пикселя границы нужно считать и снова записать около 200 пикселей, поэтому если окантовка справляется с границей длинной 40000 пикселей, то для размытия задержка во времени становится заметной уже на границе 200 пикселей. Потому размытие этой длиной и ограничивается.
  Для небольших пятен и пятен среднего размера такая длина вполне подходит, а для протяжённых следов ничто не мешает, получив ореол в начале следа, повторными касаниями создать его в других местах, или усиливать его кое-где по своему усмотрению.

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

  Второй аспект – упомянутые ходы и алгоритмы должны сопровождать работу художника, не требуя от него больших усилий для переключения с одной опции на другую. И это очень важный аспект. Например, в Фотошопе можно сделать любую кисть, рисующую в нужном для Вас режиме, но сколько времени уходит на то, чтобы настроить её?
  Или возьмём такой инструмент, как «пипетка». Нужно взять этот инструмент и нужно кликнуть по рисунку, затем ещё выполнить несколько действий, чтобы как-то изменить взятый цвет.
 
  В моей же программе изменение цвета делается во много раз проще. Никаких «пипеток». Нужно нажать правую кнопку мыши над одним цветом и отпустить над другим, и эти цвета преобразуются в новый цвет, войдя в него в пропорции два к одному.
  Художник не должен отвлекаться на технические настройки, никаких меню, никаких появляющихся или исчезающих диаграмм, и даже «горячих клавиш» по минимуму, только клики по кнопкам, которые всегда видны и всегда расположены на своих знакомых местах.
  Вот поэтому я не работаю в Фотошопе, а рисую в своей программе, и стараюсь её развивать.

_________
7.06.2023

  Если, кто-нибудь рисование в этой программе хочет попробовать, то скачать программу можно тут - https://disk.yandex.ru/d/pT6LoBWUGOBfiw программа работает в среде Виндос.


ПРИЛОЖЕНИЕ. Тексты подпрограмм, осуществляющих окантовку и размытие.

Public Sub YooA(M As Integer, Xd As Integer, Yd As Integer, A As Single) ' M=1 <=,M=0 => Окантовка следа
Dim DW As Integer, I As Integer, C1 As Long, CC1 As Long, C2 As Long
Dim Xo As Integer, Yo As Integer, X As Integer, Y As Integer, C As Long
Dim N As Integer, J As Integer, Uo As Single, Fc As Integer, Nt As Integer
Dim X1 As Integer, Y1 As Integer, P As Integer, CC As Long
Dim Xi As Integer, Yi As Integer, Ci As Long, Fb As Integer
 
  If Last > 0 Then Exit Sub '==========
    DW = Form1.Picture1.DrawWidth: Fb = 0: If Form1.Text1 = "п" Then Fb = 1:
    Xo = Xd: Yo = Yd: Xi = Xo: Yi = Yo: N = 0 'число точек Co = Form1.Picture1.Point(Xo, Yo):
    CC = OldC Or C111: If F50p = 1 Then CC = OldC And C254:
    CC1 = -1: If F50 = 3 Then CC1 = cBack Or C111: 'and C254
    N = 0: X = 1: J = 4: If M = 1 Then X = -1: J = 7: 'направление поиска границы
    'If M=2 Then
1   C = Form1.Picture1.Point(Xo - 1, Yo): If C < 0 Then Form1.Text2 = " граница не найдена": Exit Sub
    If F50p = 1 And C = CC Then Form1.Text2 = " смените цвет": Exit Sub
    C1 = C And C111: If C1 = C111 Then Xo = Xo - 1 Else J = 6: X1 = Xo: Y1 = Yo: GoTo 9:
    C = Form1.Picture1.Point(Xi + 1, Yo): If C < 0 Then Form1.Text2 = " граница не найдена": Exit Sub
    If F50p = 1 And C = CC Then Form1.Text2 = " смените цвет": Exit Sub
    C1 = C And C111: If C1 = C111 Then Xi = Xi + 1: GoTo 1 Else J = 2: X1 = Xi: Y1 = Yi:
   
9   Form1.Picture1.DrawWidth = 1:
    Xo = X1: Yo = Y1:
2  Fc = 0: If F50p < 2 Then Form1.Picture1.PSet (Xo, Yo), CC: 'OldC
   If F50p = 2 Then
     If M = 0 Then Call cRGB(C): Call d3RGB(0): C = RGB(RR, GG, BB) Or C111:
     If M = 4 Then C = ccRGB(CC, C, A) Or C111:
     Form1.Picture1.PSet (Xo, Yo), C:
   End If:
      If F50 = 3 Then If Rnd(1) < 0.3 Then C2 = CC: CC = CC1: CC1 = C2 'смена цвета окантовки
      N = N + 1: If F50p = 3 And N > 200 Then Form1.Text2 = " число точек N=" + Str(N): GoTo 51 'ограничение числа размытий
      If N > 4000 Then Form1.Text2 = " число точек N=" + Str(N): GoTo 51
      If N = 3 Then X1 = Xo: Y1 = Yo:
5  For I = 1 To 9: J = J + 1: If J > 8 Then J = 1 'вертушка
     Select Case J:
     Case 1: X = Xo: Y = Yo + 1: Case 2: X = Xo + 1: Y = Yo + 1:
     Case 3: X = Xo + 1: Y = Yo: Case 4: X = Xo + 1: Y = Yo - 1:
     Case 5: X = Xo: Y = Yo - 1: Case 6: X = Xo - 1: Y = Yo - 1:
     Case 7: X = Xo - 1: Y = Yo: Case 8: X = Xo - 1: Y = Yo + 1:
     End Select
       C = Form1.Picture1.Point(X, Y):
       If C < 0 Then Fc = 1: GoTo 3
     C1 = C And C111:    If C1 = 0 Then Xi = X: Yi = Y:
     If C1 = C111 Or C = CC Or C = CC1 Then   'переход на силуэт Or C = OldC
          If F50p = 3 And Rnd(1) < 0.5 Then Call YooAi(C, Xi, Yi, Fb)
       If Fc = 0 Then GoTo 3 Else GoTo 4
     End If: Fc = 1
3   Next I:
    Form1.Text2 = " готово частично N=" + Str(N): GoTo 51 'на случай сбоя
4   Xo = X: Yo = Y: J = J + 4: If J > 8 Then J = J - 8:
    If Xo = X1 And Yo = Y1 Then Form1.Text2 = " число точек N=" + Str(N): GoTo 51
    GoTo 2:
51   Form1.Picture1.DrawWidth = DW: Exit Sub '===============
End Sub
'===============

Public Sub YooAi(CC As Long, XX As Integer, YY As Integer, F As Integer) 'размытие
Dim X As Integer, Y As Integer, Xo As Integer, Yo As Integer, C As Long
Dim R As Integer, A As Single, I As Integer, C1 As Long, A1 As Single

  Xo = XX: Yo = YY: R = Form1.Command16.Caption:
  A = (F51 - 0.5) * 0.8: If F51 = 0 Then A = 5:
  A = (10 - A) * R: A = 1 / A: If A > 1 Then A = 1
  If R > 4 And Rnd(1) < 0.5 Then R = R / 2:
  'If R > 4 Then R = R + R - 4
  Im = R20(R): A1 = A:
  For I = 1 To Im:
    X = Xo + RXY(I, 1): Y = Yo + RXY(I, 2):
    C = Form1.Picture1.Point(X, Y): If C < 0 Then GoTo 5:
    If Fb = 1 Then If C = cBack Then GoTo 5:
    C1 = C And C111: If C1 = 0 Then Else GoTo 5:
    A1 = A * (1 - I / Im)
    C = ccRGB(CC, C, A1): Form1.Picture1.PSet (X, Y), C And C254:
5 Next I
End Sub
'============


Рецензии