Генерация изображения из произвольных строк

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

Я немного погуглил, но даже не знаю, как структурировать свой запрос? Существует ли что-нибудь подобное? И бонус, если он не будет использовать дубликаты при создании изображений.


person Caranicas    schedule 13.10.2014    source источник


Ответы (1)


Не совсем подходит для Stack Overflow, но тем не менее интересный проект. Так что я решил немного развлечься и посмотреть, как далеко я смогу зайти.

Я думаю, что это сводится к этому:

  1. вычислить значение серого для набора символов ASCII;
  2. рассчитать «наилучшее соответствие» для каждой строки;
  3. повторять 2. пока не закончите.

Я не думаю, что «без дубликатов» возможно, если у вас нет очень маленьких изображений и большого количества строк-кандидатов. Вот что я придумал, используя свой аватар и мои текущие значки в качестве списка строк. (Я исключил свой значок «c»; каким-то образом моя программа решила, что он «лучше всего подходит» для больших исправлений, что было не очень привлекательно. Примечание для ума: не включать односимвольные строки.)

QuorumQuorumAutobiographerQuorumQuorumQuorumJongwareQuorumQuorumQuorumQuorumQuor
umQuorumQuorumAutobiographerQuorumQuorumSupporterQuorumQuorumProofreaderQuorumQu
orumQuorumAutobiographerQuorumQuorumQuorumQuorumQuorumQuorumAutobiographerQuorum
QuorumQuorumAutobiographerQuorumQuorumQuorumQuorumQuorumQuorumAutobiographerQuor
umQuorumQuorumAutobiographerQuorumQuorumQuorumAutobiographerQuorumMortarboardQuo
rumQuorumAutobiographerQuorumQuorumQuorumQuorumAutobiographerQuorumMortarboardQu
orumQuorumAutobiographerQuorumQuorumQuorumQuorumJongwareQuorumQuorumCommentatorQ
uorumQuorumAutobiographerQuorumQuorumQuorumQuorumQuorumQuorumQuorumAutobiographe
rQuorumQuorumAutobiographerQuorumQuorumProofreaderJongwareQuorumQuorumQuorumQuor
umQuorumQuorumMortarboardJongwareQuorumProofreaderCommentatorSuffrageQuorumQuoru
mQuorumQuorumJongwareQuorumAutobiographerSuffrageCommentatorCaucusCriticCleanupQ
uorumQuorumMortarboardAutobiographerCommentatorQuorumConstituentCriticCriticQuor
umQuorumQuorumQuorumAutobiographerJongwareCleanupSupporterInvestorCriticCleanupQ
uorumQuorumQuorumQuorumAutobiographerFanaticCleanupFanaticInvestorCriticCleanupQ
uorumQuorumQuorumQuorumAutobiographerCriticInformedSupporterCriticCriticInformed
QuorumQuorumQuorumQuorumAutobiographerCriticQuorumSupporterInvestorFanaticQuorum
QuorumQuorumQuorumQuorumAutobiographerCriticCleanupCommentatorQuorumDeputyQuorum
QuorumQuorumQuorumQuorumAutobiographerCriticInvestorCaucusInformedDeputyQuorumQu
orumQuorumQuorumQuorumQuorumCommentatorCriticCriticCitizen PatrolQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumAutobiographerCriticCriticCitizen PatrolQuorumQuorumQ
uorumQuorumQuorumQuorumQuorumAutobiographerCriticCriticCitizen PatrolStewardQuor
umQuorumQuorumQuorumQuorumAutobiographerConstituentCitizen PatrolCaucusQuorumQuo
rumQuorumQuorumQuorumQuorumAutobiographerInvestorCriticConstituentQuorumQuorumQu
orumQuorumQuorumQuorumQuorumCommentatorConstituentCleanupCaucusCleanupQuorumQuor
umQuorumQuorumQuorumQuorumAutobiographerInvestorCleanupSupporterInformedQuorumQu
orumQuorumQuorumAutobiographerCommentatorCriticInformedJongwareJongwareQuorumQuo
rumQuorumQuorumAutobiographerCommentatorCriticInvestorJongwareJongwareQuorumQuor
umQuorumQuorumAutobiographerFanaticInvestorCriticInformedCleanupQuorumQuorumQuor
umQuorumQuorumQuorumDeputySupporterInvestorConstituentCaucusQuorumQuorumQuorumQu
orumQuorumQuorumAutobiographerCriticInvestorCriticSupporterQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumAutobiographerInvestorInvestorCleanupQuorumQuorumQuorumQuor
umQuorumQuorumQuorumQuorumCommentatorInvestorInvestorQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumCommentatorInvestorInvestorQuorumQuorumQuorumQuorumQu
orumQuorumQuorumQuorumQuorumCommentatorInvestorCleanupStewardQuorumQuorumQuorumQ
uorumQuorumQuorumQuorumQuorumCommentatorInvestorJongwareQuorumQuorumQuorumQuorum
QuorumQuorumQuorumQuorumQuorumAutobiographerCleanupQuorumQuorumQuorumQuorumQuoru
mQuorumQuorumQuorumQuorumQuorumAutobiographerSuffrageQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumQuorumAutobiographerDeputyQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumQuorumQuorumAutobiographerQuorumQuorumQuorumQuorumQuo
rumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuorumQuoru

Вы должны немного щуриться; в маленьком размере это выглядит так:

textvatar(tm)

Вот как я его создал.

Шаг 1: Найдите подходящее изображение;

Шаг 2: преобразовать в оттенки серого;

Шаг 3: преобразуйте серый цвет в крайности. Этот шаг должен гарантировать, что входной диапазон (значения серого) использует полный диапазон от 0 до 255.

Шаг 4: измените размер изображения для наилучшего соответствия. Я выбрал 80x40 и намеренно сжал изображение вдвое. Это потому, что «текст» обычно выше, чем в ширину. Для разных шрифтов нужны разные пропорции! 80 будет количеством символов в строке, 40 — общим количеством строк.

Я использовал Photoshop для описанных выше шагов только потому, что не хотел писать для него код. Это не сложно или что-то в этом роде, если у вас есть доступ к необработанным данным изображения, но это много работы и не интересно.

Промежуточный шаг, увеличенный на 400%, чтобы вы могли видеть пиксели:

деформированное изображение в градациях серого

Шаг 5: Найдите себе моноширинный растровый шрифт. Я нашел хороший 8x8 где-то в Интернете. Возможно, больший размер может работать лучше, но только очень незначительно, потому что ограничивающим фактором являются ваши строки, а не шрифт.

Шаг 6: Рассчитайте «серые» значения для каждого из символов ASCII. Это количество черных пикселей, деленное на общее количество пикселей. Для лучшего разброса я разделил результат для каждого символа на найденный максимум, поэтому наименьшее значение — 0 (для пробела), а наибольшее — 1 (что оказалось для M, но это зависит от шрифта). Затем я умножил значения на 255, чтобы они имитировали оттенки серого. Наконец, поскольку эти значения были обратными значениям в изображении в градациях серого, я заменил их на 255-value.

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

0MMMMMM00000000000RDRRDDDDDDDDDDDDDDR#@RRRRR#00000RRR@RRRRR@RR@RRRRD&44&#00#0000
MMMMMM000000000000RDRDDDDDDDDDDDDDDDR0####0R&&&&&&DR@RRR@#########RRDDD4@0000000
MMM000#00000000000RDRRDDDDDDDDDDD&&&R00#000@&DR@####RR@#0000000##0#RD4PP&R@00000
M000#0000000000000RDDDDDDDDDDD&D&&D&R###0000@#0000#@@##@@@@@##000000R&2FPP4R#000
00###0000000000000RDDDDDDDDDDDDDD&&&D0000#@##@##00##@RDD&DRRRR#00000@R4FFP4PD@00
00#000000000000000RDDDDDDDDDD&D&D&&&DRRRRDR@@@##00#R&4&44DDDRRR#0000##R&FPP4PRR@
00##00#00000000000RDDDDDDDDDDD&&&&&&RDRRRRRRRR##@@RR&F4&RDDRR@@#0000000#&44&&4FD
000000000000000000DDDDDDD&&&DD&&&D&&R##@RRRRRRRRRRRRD&DRD&44DD&RR@#00000RDDRR4F4
000000000000000000RDDDDDDDRRDRDDD&DR@###@R&4&4444PP4DRRR&P22FF2FP&DRRRRRRRR@R4FD
000000000000000000RRRRRRR@00@@R&&DRRRRRR@&P2$33*33*4RRRDP23$*33$$**333*$$2D#@4DR
000000000000000000RRRRRRR@0000#DDRRRRRD&D4*$$%%ff3F&DRRR2$1%$$%11ff%ll1l;'IRDF&R
000000000000000000RRR@#0#00000R4444DRRRR&3llf33$32PDRR&3Ii(i%fIlI1Il!ii/' .FF4DR
0000000#0000000000#@@#0MM0M00#RP22*24DR4$l!!!I%*P4DDP31i===/lf1Illi((ii=;..*F4RR
000000000000000000#@@##0M00000@F*$%*2PFflilllI1f3*2PF3fIi/=(lf$fIi/======;iF&P4R
000000000000000000##@##00000000&3f$2F2*1i!ll1$2P4RD&4P*$$%!ii!I!ii/=/=;;;(*&R4FR
000000000000000000#####00000000D%I3$$fflil!l1$3%3&RD2PP*$%1ll!lI1%f$3fI="1RRRRDR
000000000000000000#####00000000Rf1f%II1IIl!l!!1%ff$*FFFF*%((lf**F4&D&PPFf2RRRRRR
00000000000000000M#####0000000003!i11II11l!!!(ilIIl1f$f%I="=1FP4&@#R&DP22&RRR@#@
0000000000000000000###0000000000#$i/iIIIl!!i=;"";===;""""";i12FFP4&4*4&*FRRRR@@R
000000000000000000M000000000000000R4FF1l!i(=;"''"""""'...';/i$3$f$$33$$$4DRRRRRR
000000000000000000000000000M00000000@21l(/ii/=;;=ilI;"'...'=;I%11f$$$ffP@@RR@R#0
000000000000000000000000000M00000000&11!=/li(i!I%%Ii;... .";"!I!!I1ff$*R0#@#0000
000000000000000000000000M0000M000000$lli=//=/i!lIi/l%I/""=//'=Iiiil%f$PR@#@00000
000000000000000000000000M0M0M00000MRl!!!/=;;/l%fl!lI%3233$ff%11II%%f*2PP@##00000
00000000000000000M000000M0MM00000003=illl!!iI%11%%f%f$32FF22$1%ff$f2DD4PR0000000
00000000000000000M00M0#RRRRRRRRRRRPi/(lllI1I(=;=iI$2222FPFFP*$fff%FRR2322&R00000
00000000000000000MM00#RRD&&&&&444*l/(i!ll!i!==/(il%$33*2FFF23$ff*4DDDF33*22&0000
0000000000000000000000@R@@@@@#&f!((/i!!!lI!i=;;/!l1f32*3$$$ff$2&RR@###@##00##000
0000000000000000#RRRR@@4F4R0R3!////(iii!!l%Ii=;"=l%f$333$ff%$4############00000#
0000000000000000000000#@@@#0Di/ii(=/(i!!!lI%%1!(iI%$**$$fffF@0000000000000000000
00000000000000000000000000000R3l((/((ii!lll!I%$3$f$$$$$3$f20M0000000000000000000
000000000000000000000000000000#2l///((!!l!!i!!1%f%f$3$f%%fR000000000000000000000
00000000000000#00000000000000000&l//(i!llllII1%%%1I1ff1I1&000000000000000000#00#
M00000000000000000000000000000000R3l!!llII111%%%%%%f$$f%2000000000000000000RR00#
0000#000000000000000000000000000000R*%1II111%%ffff$33fffR000000000000000000##00#
0####000000000000000000000000000000M0RF3ff$$$fff$$33$ff&00000000000#000000##000R
#00000000#00000000000000000000000000000R4FFFF22*****3fF00000000000000000000000@&
00###000000000000000000000000000000000000@RRDD&&&4P*34#00000000000000000000000#R
00000####000000000000000000000000000000000000##@RRDDR00000000000000M0000000000##
00000000#000000000000000000000000000000000000000000000000000000000000000000000##

Это похоже на то, что выводит среднее изображение в художественный конвертер ASCII.

Шаг 7: найдите себе список строк для использования.

Шаг 8: начиная с верхнего левого угла, проверьте покрытие каждой из ваших строк на изображении. Распечатайте наилучшее соответствие, увеличьте положение на длину этой строки, повторяйте, пока не закончите. (Если вы не хотите дубликатов, на этом этапе вы удаляете строку из своего пула.)

Шаг 9: прибыль!


Для теста покрытия я использовал сумму (source - dest)² для каждого символа/пикселя, деленную на длину строки: меньше = лучше — наименьшая разница между строкой и пунктом назначения.

Я не рассматривал здесь красивые окончания строк. Я экспериментировал с отрицательным бонусом, если слово точно заполняло строку, но разница в выводе была незначительной. Он все еще может работать с большим набором строк.

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

person Jongware    schedule 25.12.2014
comment
Спасибо за ваш ответ. К сожалению, проект, над которым я работал, был отменен. Это было отличное чтение, и я собираюсь сохранить его в своих банках памяти, и, надеюсь, мне удастся попробовать это где-нибудь в будущем. - person Caranicas; 16.03.2015