ASCII-арты на python

Здравствуйте уважаемые читатели, в этой статье я расскажу Вам как делать ASCII-арты при помощи языка python.

7ba2b7d69c8038811d62e4fefdd48893.jpg

Примерно такие картинки мы научимся делать, когда дочитаем статью

Для начала необходимо установить библиотеку компьютерного зрения OpenC, для этого в консоль прописываем данную строчку (заранее убедившись, что в системе уже есть pip, иначе устанавливаем его):

pip install opencv-python

После установки библиотеки можно приступить к написанию кода! Я не буду разбивать код на строчки и попутно объяснять их, а сначала расскажу о том, как работает весь алгоритм и только после этого приложу код.

И так, сначала разберемся с тем, как нам надо обрабатывать картинку и преобразовывать ее в символы ASCII. Логичнее всего делать это по яркости, но как нам определить яркость пикселя, если у нас картинка в формате RGB? Эту проблему я решил очень простым способом: я преобразовал из формата BGR (да-да именно BGR, потому что в библиотеке OpenCV цвета идут наоборот) в серую палитру, ну и тут уже понятно, обращаемся к пикселю как к элементу массива, указывая его координаты через запятую. И теперь, когда у нас уже есть картинка, в которой каждый ее элемент имеет определенную яркость от 0 до 255, то уже становится понятно, как именно сделать пиксель символом ASCII:

  1. Нам нужен отфильтрованный по яркости элементов список символов ASCII (его можно либо составить на глаз, либо взять из интернета, благо люди уже давно придумали ASCII-арты и составили программы, которые выставили все символы по возрастающей)

  2. Нам нужно создать особый коэффициент, на который мы будем делить яркость пикселя картинки и определять индекс строки ASCII символов

Чтобы сделать перевод можно использовать 2 цикла (способ идентичный перебору двумерного массива), перевести каждый пиксель в ASCII символ и вывести все элементы, но не все так просто, чтобы Вы поняли проблему я приложу картинку:

131d5b6f32d6c2dad440efc28a30177e.jpg

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

Когда картинка обработана и готова к выводу, можно задуматься о том, как это сделать, потому что просто принтить каждую строчку в консоль — это плохая идея, потому что в том же пайчарме она не позволяет масштабировать себя удерживая ctrl и вращая колесиком мыши, что в свою очередь может делать блокнот, значит с ним и надо работать.

Еще я столкнулся с проблемой ошибок, которые вылетали во время обработки разных картинок, ее я решил использованием конструкции try-except.

И теперь, когда Вы все уже прочитали алгоритм моего кода, я готов показать его:

import cv2

string = " `.,-':<>;+!*/?%&98#"
coef = 255 / (len(string) - 1)
image = cv2.imread('img/img_18.png')
height, width, channels = image.shape
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# gray_image = cv2.resize(gray_image, (30, 12))
with open("output\ASCII_Art.txt", "w") as file:
    for x in range(0, width - 1, 8):
        s = ""
        for y in range(0, height - 1, 4):
            try:
                s += string[len(string) - int(gray_image[x, y] / coef) - 1]
                continue
            except IndexError:
                pass
        if len(s) != 0:
            file.write(s + "\n")

Ну вот и все, теперь можно обрабатывать картинки и получать подобные результаты:

8e5022bc4a1dff9fbedc53affba27167.jpg555bb11797f77112a459010cf4e18f03.jpg

Большое спасибо, что прочитали мою статью, буду рад любым комментариям)

(Еще я хочу написать статью о том, как я повторил легендарный клип Bad apple используя ASCII-арты, если будет интересно, то ставьте лайки)

© Habrahabr.ru