Создадим свой Painter. Часть 3

Начало здесь

И веселье только начинается. Давайте порисуем птицами. Ну или любыми другими животными и предметами. Вот простой код.

global img

def setup():        
    global img
    size(1000,200)
    background(0)
    imageMode(CENTER)
    img = loadImage('bird.png')    
    
def draw():
    global img        
    if mousePressed:
        image(img,mouseX, mouseY,100,100)

Картинку птички (или любую другую) предварительно сохраните в папке data. А папку data положите туда же, где находится ваш скетч. Тогда программа ее увидит. Теперь вы знаете как нарисовать что-то подобное или лучше, если у вас нет под рукой планшета и программы procreate.

Целый город одной кисточкой 

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

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

oldX=0
oldY=0

def setup():
    # объявляем глобальные переменные, где будем хранить
    # все наши картинки
    global im1,im2,im3,im4
        
    size(1000,200)
    background(0,0,0)
    
    # загружаем все картинки
    im1 = loadImage('img-01.png')
    im2 = loadImage('img-02.png')
    im3 = loadImage('img-03.png')
    im4 = loadImage('img-04.png')

# Чтобы код выполнялся постоянно, а не один раз
# нам нужно оставить эту функцию, хоть мы ей и 
# пользуемся в этот раз  
def draw():
    pass
    
# рисуем картинку один раз, если нажали мышкой    
def mousePressed():    
    draw_pict(mouseX,mouseY,30)

# рисуем картинку каждый раз, когда нажали мышкой и тащим    
def mouseDragged():        
    draw_pict(mouseX,mouseY,30)

# главная наша функция рисования, которая на вход
# принимает позицию (x,y) и размер картинки в писелях
def draw_pict(x,y,s):    
    global oldX,oldY
    global im1,im2,im3,im4  
    # создаем рандомную (случайную) 
    # переменную от 0 до 3 (по числу наших изображений)    
    r = int(random(4))    
    # сохраняем все изображения в список,
    # чтобы можно было их вызывать по номеру (индексу)
    ims = [im1,im2,im3,im4]
    # вычисляем расстояние, как далеко мы сдвинулись мышкой
    d = calc_distance(x,y,oldX,oldY)
    # если расстояние больше, чем 60% от ширины картинки
    # это чтобы они друг на друга немного заходили    
    if(d>s*.9):        
        # рисуем случайную картинку из списка
        image(ims[r],x-s/2,y-s/2,s,s)
        filter(GRAY)
        oldX = x
        oldY = y
    
def calc_distance(x1,y1,x2,y2):
    dist = sqrt((x2 - x1)**2 + (y2 - y1)**2)
    return dist

Новое в этом коде то, что мы впервые рисуем не в функции draw(), а в функции mouseDragged(). Это немного увеличило сам код, ведь мы еще раз вызываем функцию рисования в mousePressed(). Зато теперь, когда мы останавливаем движение мыши, программа также перестает рисовать. В прошлом коде, программа продолжала рисовать все время, пока нажата левая клавиша мыши. Также, мы написали и использовали простую функцию для определения расстояния между двумя точками. А именно между текущем положением курсора (mouseX и mouseY) и предыдущим положением (oldX и oldY). Формула здесь простая – расстояние это гипотенуза прямоугольного треугольника. А она вычисляется по известной вам теореме – квадрат гипотенузы равен сумме квадратов катетов. 

Меняем размер кисточки от скорости рисования

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

oldX=0
oldY=0
startDraw = True

def setup():
    # объявляем глобальные переменные, где будем хранить
    # все наши картинки
    global im1,im2,im3,im4
        
    size(1000,200)
    background(0,0,0)
    
    # загружаем все картинки
    im1 = loadImage('img-01.png')
    im2 = loadImage('img-02.png')
    im3 = loadImage('img-03.png')
    im4 = loadImage('img-04.png')

# Чтобы код выполнялся постоянно, а не один раз
# нам нужно оставить эту функцию, хоть мы ей и 
# пользуемся в этот раз  
def draw():
    pass
    
# рисуем картинку один раз, если нажали мышкой    
def mousePressed():    
    draw_pict(mouseX,mouseY,10)

# рисуем картинку каждый раз, когда нажали мышкой и тащим    
def mouseDragged():        
    draw_pict(mouseX,mouseY,10)

# главная наша функция рисования, которая на вход
# принимает позицию (x,y) и размер картинки в писелях
def draw_pict(x,y,s):    
    global oldX,oldY
    global im1,im2,im3,im4
    global startDraw
      
    # создаем рандомную (случайную) 
    # переменную от 0 до 3 (по числу наших изображений)    
    r = int(random(4))    
    # сохраняем все изображения в список,
    # чтобы можно было их вызывать по номеру (индексу)
    ims = [im1,im2,im3,im4]
        
    # если мы только начали рисовать
    # возьмем минимальный размер кисти    
    if(startDraw == True):
        d = .4
    else:        
        # иначе, вычислим расстояние по теореме Пифагора
        d = calc_distance(x,y,oldX,oldY)/3
        
                    
    # рисуем случайную картинку из списка
    image(ims[r],x-s/2*d,y-s/2*d,s*d,s*d)
    filter(GRAY)
    startDraw = False
    oldX = x
    oldY = y
    
def calc_distance(x1,y1,x2,y2):
    dist = sqrt((x2 - x1)**2 + (y2 - y1)**2)
    return dist

def mouseReleased():
    global startDraw
    startDraw = True

И мы получим возможность рисовать что-то вроде этого (рисунок ниже).

Поворот туда-сюда

Если вы в предыдущем разделе «Целый город одной кисточкой» замените одну строчку на несколько новых, то ваша кисточка будет вращаться в зависимости от нахождения мыши на холсте. Возьмем координаты мыши по X и подставим их в функцию, которая нам вернет меньшее, но прямо-пропорциональное число. Мы используем его для поворота нашей картинки. Но прежде, чем мы это сделаем, нам нужно «обезопасить» весь холст от поворота. Для этого существуют две функции pushMatrix() и popMatrix(). Еще нужно помнить, что поворот идет относительно начала координат, поэтому нужно его перенести на время в центр нашего изображения. Для этого есть функция translate().

Итак, вот код, который нужно вставить. Обратите внимание на x и y – они заменяются нулями.

# вместо 
# image(ims[r],x-s/2,y-s/2,s,s) 
# вставьте этот код:

ang = map(mouseX,0,width,0,100)
pushMatrix()
translate(x, y)
rotate(PI*ang)
image(ims[r],0-s/2,0-s/2,s,s)        
popMatrix()

Теперь кисточка поворачивается тем сильнее, чем правее курсор

Творческое задание

Придумайте абстрактную тематическую композицию используя фотографии в качестве кисточки. Что это будет зависит от вас. Тема свободная. Море, чайки, камни. Рыба, сети, рыбаки. Что угодно. Размер 1080х600px (горизонтальный), jpg

 

Дальше Image Processing