Transformation : image => ascii art

Soyez le premier à donner votre avis sur cette source.

Vue 21 809 fois - Téléchargée 745 fois

Description

Ce code transforme l'image "img.jpg" en asciiart, la couleur de fond sur chaque caractère est la couleur moyenne du carré encodé, et le caractère est celui qui présente le plus fort contraste...

Source / Exemple :


<?php
function decompose($a){
	$b=(int)$a/256/256;
	$v=(int)$a/256%256;
	$r=(int)$a%256;
	return array($r, $v, $b);
}
function recompose($r, $v, $b){
	return (($b*256+$v)*256+$r);
}
function colorfor($a, $x, $y, $nx, $ny, $alphabet){
	$alphabetcouleursN=array();
	$alphabetcouleursR=array();
	$alphabetcouleursV=array();
	$alphabetcouleursB=array();
	$rm=0;
	$vm=0;
	$bm=0;
	$n=0;
	foreach($alphabet as $k=>$img){
		$alphabetcouleursR[$k]=0;
		$alphabetcouleursV[$k]=0;
		$alphabetcouleursB[$k]=0;
		$alphabetcouleursN[$k]=0;
	}
	for ($i=$x*$nx;$i<($x+1)*$nx;$i++){
		for ($j=$y*$ny;$j<($y+1)*$ny;$j++){
			list($r, $v, $b)=decompose(imagecolorat($a, $i,$j));
			$rm+=$r;
			$vm+=$v;
			$bm+=$b;
			$n++;
			$px=$i-$x*$nx;
			$py=$j-$y*$ny;
			foreach($alphabet as $k=>$img){
				if (!imagecolorat($img, $px, $py)){
					$alphabetcouleursR[$k]+=$r;
					$alphabetcouleursV[$k]+=$v;
					$alphabetcouleursB[$k]+=$b;
					$alphabetcouleursN[$k]++;
				}
			}
		}
	}
	$rm=intval($rm/$n);
	$vm=intval($vm/$n);
	$bm=intval($bm/$n);
	$car=-1;
	$diff=0;
	for($k=0;$k<sizeof($alphabet);$k++){
		$alphabetcouleursR[$k]=intval($alphabetcouleursR[$k]/$alphabetcouleursN[$k]);
		$alphabetcouleursV[$k]=intval($alphabetcouleursV[$k]/$alphabetcouleursN[$k]);
		$alphabetcouleursB[$k]=intval($alphabetcouleursB[$k]/$alphabetcouleursN[$k]);
		$d=abs($alphabetcouleursR[$k]-$rm)+
			abs($alphabetcouleursV[$k]-$vm)+
			abs($alphabetcouleursB[$k]-$bm);
		if ($d>=$diff){
			$diff=$d;
			$car=$k;
		}
	}
	$c1=recompose($rm, $vm, $bm);
	$c2=recompose($alphabetcouleursR[$car], $alphabetcouleursV[$car], $alphabetcouleursB[$car]);
	return array($c1, $c2, $car);
}

function tohex($a){
	$hex='0123456789ABCDEF';
	$C=$a%16;
	$B=($a-$C)/16;
	return ($hex{$B}.$hex{$C});
}

function color($a){
	list($r, $v, $b)=decompose($a);
	return '#'.tohex($b).tohex($v).tohex($r);
}

set_time_limit(0);

$npx=8;
$npy=15;

$alphabet=array();
//ici, si vous voulez plus de caractères possibles, il faut augmenter le nombre de caractères...
$alphabetstr='abcdefABCDEF0123456789-|`\_#"~@?,.;/:§!%*$&';
for ($i=0;$i<strlen($alphabetstr);$i++){
	$alphabet[$i]=ImageCreateTrueColor($npx,$npy);
	$back = ImageColorAllocate ($alphabet[$i], 200, 200, 200);
	$for = ImageColorAllocate ($alphabet[$i], 0, 0, 0);
	ImageFilledRectangle($alphabet[$i],0, 0,$npx, $npy,$back);
	imagechar($alphabet[$i], 12, 0,0, $alphabetstr[$i],$for);
}

$a=ImageCreateFromJpeg('img.jpg');
$x=imagesX($a);
$y=imagesY($a);

$ncx=60;
$ncy=(int)$y*$ncx/$x*$npx/$npy;

$ny=$ncy*$npy;
$nx=$ncx*$npx;
$b=ImageCreateTrueColor($nx,$ny);
ImageCopyResized($b,$a,0,0,0,0,$nx,$ny,$x,$y);
imagedestroy($a);

echo '<table>';
for ($y=0;$y<$ncy-1;$y++){
	echo '<tr>';
	for ($x=0;$x<$ncx-1;$x++){
		list($c1, $c2, $c3)=colorfor($b, $x, $y, $npx, $npy, $alphabet);
		echo '<td style="background-color:'.color($c1).';color:'.color($c2).'">'.$alphabetstr{$c3}.'</td>';
		flush();
	}
	echo '</tr>';
}
echo '</table>';
imagedestroy($b);
?>

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
147
Date d'inscription
lundi 16 août 2004
Statut
Membre
Dernière intervention
14 novembre 2009

Salut coucou747,
sprintf() est certes lent, mais toujours plus rapide (à peu près 3 fois plus rapide) que ta combinaison color()=decompose()+tohex(), c'est le résultat d'un "bench" des plus basique que j'ai effectué sur 100000 itérations.
Amicalement.
Messages postés
12303
Date d'inscription
mardi 10 février 2004
Statut
Modérateur
Dernière intervention
30 juillet 2012
39
sprintf est lent... en C du moins... pour le redimentionnement, c'est aussi lent... bref, j'aime bien ma méthode, et si elle est lente, c'est que le calcul l'est :)
Messages postés
147
Date d'inscription
lundi 16 août 2004
Statut
Membre
Dernière intervention
14 novembre 2009

Salut coucou747
90 secondes pour afficher une image de 60x60 pixels et de 1,6 KB (il s'agit en fait ton "avatar")!
Mon pc n'est pas de première jeunesse, mais quand même!
Bien que je ne sois pas sûr que ton script s'exécute correctement chez moi (par exemple certains caractères de l'"alphabet" ne s'affichent pas d'une couleur qui permette de les différencier du fond : est-ce normal?), ce qui est certain, c'est qu'il gagnerait à être optimisé.

Sur la forme,
passons vite fait sur les divisions et les multiplications par des puissances de 2 que l'on peut optimiser par des décalages avec >> et <<,
l'appel à ta fonction color() (qui fait elle appel aux fonctions decompose() et tohex()!) peut être remplacé
sans état d'âme par celui de la fonction sprintf(), certainement plus optimisée (un grand merci en passant
aux inventeurs du langage C).
ex :
color($c1)
est équivalent à :
sprintf('#%06X',$c1)

Sur le fond,
la fonction colorfor($a,$x,$y,$nx,$ny,$alphabet), qui calcule, en faisant des moyennes, la couleur pour chaque cellule de ton tableau html, est-ce qu'on obtiendrait pas la même chose en réduisant l'image, avec imagecopyresized(), directement aux dimensions $ncx et $ncy ? (et après on prendrait la couleur de chacun de ses pixels pour la reporter dans le tableau?).
Amicalement.
Messages postés
4030
Date d'inscription
mardi 13 mai 2003
Statut
Modérateur
Dernière intervention
23 décembre 2008
22
Salut,
Un petit peu long à l'exécution sur mon poste (image de 12Ko). Mais le résultat vaut bien d'attendre 4 secondes.
Sympa également pour la pixelisation d'images.
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
23
Hello Coucou,

très amusant et sympa :-)
Pour coller plus à l'esprit ascii art, je proposerais même une version en dégradés de gris, si j'étais toi.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.