ASCII Art - сортировка массива символов ASCII по уровням яркости (C/C++)
Я работаю над программой (на C/C++), где пользователь должен взять выбранное пользователем изображение и преобразовать его в искусство ASCII (используя SQL). До сих пор я был в состоянии для пользователя выбрать изображение и отобразить это изображение в оттенках серого в окне.
Однако в настоящее время у меня возникают трудности с сортировкой символов ASCII в виде массива уровней яркости и последующим сопоставлением одного символа с областью пикселей.
Я знаю, что мне нужно будет использовать циклы for, но я пока не могу найти ничего полезного в Интернете. Спасибо:D
4 ответа
$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'.
Вот стандартная градация серого от темного к светлому (или наоборот, в зависимости от вашего предпочтительного цвета дисплея).
`.-':_,^=;><+!rc*/z?sLTv)J7(|Fi{C}fI31tlu[neoZ5Yxjya]2ESwqkP6h9d4VpOGbUAKXHm8RD#$Bg0MNWQ%&@
Я обнаружил, что ответ Ахсена Хана не совсем точен для шрифта моей консоли Windows (consolas), что дало несколько неверные результаты. Я написал программу для анализа и упорядочивания символов путем суммирования значений оттенков серого каждого пикселя, что и дало это. Не забудьте поставить пробел в начале.
Кроме того, темнота распределяет символы неравномерно (хотя я обнаружил, что результаты предположения о равномерном распределении были удовлетворительными). Тьма для каждого персонажа:
[0, 0.0751, 0.0829, 0.0848, 0.1227, 0.1403, 0.1559, 0.185, 0.2183, 0.2417, 0.2571, 0.2852, 0.2902, 0.2919, 0.3099, 0.3192, 0.3232, 0.3294, 0.3384, 0.3609, 0.3619, 0.3667, 0.3737, 0.3747, 0.3838, 0.3921, 0.396, 0.3984, 0.3993, 0.4075, 0.4091, 0.4101, 0.42, 0.423, 0.4247, 0.4274, 0.4293, 0.4328, 0.4382, 0.4385, 0.442, 0.4473, 0.4477, 0.4503, 0.4562, 0.458, 0.461, 0.4638, 0.4667, 0.4686, 0.4693, 0.4703, 0.4833, 0.4881, 0.4944, 0.4953, 0.4992, 0.5509, 0.5567, 0.5569, 0.5591, 0.5602, 0.5602, 0.565, 0.5776, 0.5777, 0.5818, 0.587, 0.5972, 0.5999, 0.6043, 0.6049, 0.6093, 0.6099, 0.6465, 0.6561, 0.6595, 0.6631, 0.6714, 0.6759, 0.6809, 0.6816, 0.6925, 0.7039, 0.7086, 0.7235, 0.7302, 0.7332, 0.7602, 0.7834, 0.8037, 0.9999]
Эти значения масштабируются таким образом, что 0 означает все черные пиксели (т. е. символ пробела), а 0,9999 — самые яркие («@»).
Символы ASCII не имеют собственной серости, потому что это зависит только от того, как они нарисованы на вашем экране - каким шрифтом, размером, горизонтальным и вертикальным интервалом и какими цветами.
Тем не менее: можно сделать обоснованное предположение. Для большинства шрифтов пробел "полностью белый", точка останова будет маленькой точкой в большинстве шрифтов, запятая немного больше, и так далее. Все, что вам нужно, - это соотношение чёрно-белых пикселей для каждого отображаемого символа.
Найдите (или создайте) растровую версию шрифта, который вы собираетесь использовать, или близкий к нему. Поскольку большинство шрифтов ASCII на самом деле очень близки по своему дизайну, вы даже можете использовать простой растровый шрифт 8x8 (не многие шрифты будут иметь
!
это "тяжелее", чемW
- если вы найдете то, что делает, найдите другое). Поскольку вы собираетесь использовать его для ASCII-искусства, вам, вероятно, нужны только моноширинные шрифты. Рисование ASCII-изображений с помощью пропорциональных шрифтов возможно, но гораздо сложнее.Зацикливайтесь на каждом символе и считайте черные пиксели. Как правило, пространство будет иметь
0
, полная остановка1
и что-то вроде#
будет 16 или около того. (Эй, смотрите! Здесь вы можете использоватьfor
цикл!)Точная серость каждого символа может быть представлена
value/area
гдеarea
это полный размер растрового изображения. Но вы не заинтересованы в абсолютной стоимости! Обычный диапазон ASCII не содержит символа, который должен быть "полностью черным". Чтобы узнать относительную серость, разделите значение для каждого символа на максимальное значение, которое вы нашли для всего шрифта. Таким образом, пространство будет0
, символ "максимальное значение" будет1
и все остальные символы будут иметь значение между ними. (На самом деле, если ваш символ "Пробел" содержит черные пиксели, вычтите их также из начальных значений. Просто, чтобы обрисовать общую идею; лучше не использовать такой странный шрифт.)В итоге вы получите 95 значений - по одному для каждого от пробела (#32) до тильды (#126). Если вы хотите использовать все символы в выводе, вы готовы к работе. Сортировка символов по уровню серого. Для каждого серого входного пикселя (уровень от 0 до 255) разделите его на 255, чтобы получить его в том же диапазоне, что и значение карты вашего персонажа. Затем напечатайте символ с уровнем ближе всего к нему. (Это самый простой метод, но его можно оптимизировать различными способами.)
Если вы хотите ограничить оттенки серого меньшим диапазоном значений / символов, создайте меньший массив со значениями, ближайшими к нужным уровням. Например, если вы хотите 16 уровней серого, найдите символы, наиболее близкие к 0, 1/15, 2/15 ... 15/15.
Смотрите также шаги 5 и 6 моего ответа на связанный вопрос.
Нет никакого разумного способа сделать это, и существующие программы ASCII-art просто используют предопределенный порядок символов. Т.е. char myASCII[] = " .,:ilwW";