Démonstration de Noël 2013

Cette catégorie traite de développements récents destinés à nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

Daniel
Messages : 17423
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Démonstration de Noël 2013

Message par Daniel »

La préparation de la video consiste à extraire une image bmp pour chaque trame et un fichier .wav 22050 kHz pour le son. Ensuite un programme sur PC crée le fichier lu par le MO5. Pour la vidéo, j'utilise la même technique que la démo Simon's Cat sur carte SD : un octet "déplacement dans la mémoire vidéo" + un octet "image", pour afficher uniquement les segments de 8 pixels différents par rapport à l'image précédente. Le fichier contient successivement un octet déplacement, un octet son, un octet image, un octet son, et ainsi de suite. Le son est sur 6 bits, stocké dans des octets. J'ai préparé ce fichier il y a longtemps, je ne me souviens plus exactement du temps de génération, mais je ne crois pas que ce soit très long (moins d'une heure).

Avec le système utilisé, le débit maximum théorique d'acquisition des données est 400 Ko/s. Un LDD (3 cycles) + un branchement (2 cycles) permettent de lire 2 octets en 5 cycles. Evidemment il faut faire quelque chose avec les octets lus, ce qui réduit considérablement le débit en pratique. Le plus gros problème est le délai entre deux buffers de 512 octets, car il ne faut pas interrompre la musique ni la vidéo. La nécessité de stocker les données à jouer pendant le "gap" diminue encore un peu le débit.

Dans la démo Olympia, je travaille à 44100 octets/s (22050 pour le son et 22050 pour l'image). Il doit être possible d'aller un peu plus vite. Et aussi d'améliorer l'image avec les techniques de diffusion d'erreur de __sam__. J'ai utilisé Floyd Steinberg, par paresse.

Sur la partie "hard" je ne peux rien vous dire aujourd'hui, mais j'espère que nous en reparlerons l'année prochaine.
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
Dominique
Messages : 831
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Démonstration de Noël 2013

Message par Dominique »

Daniel, tu arrives donc à recodifier par un petit programme une image BMP en une succession de 1 et 0 renvoyés sur l'écran Forme du MO5 ( pas encore les couleurs Fond, si j'ai compris) Ce programme est il disponible ? J'aimerai bien illustrer quelques uns des programmes auquel je pense et si je prenais une image BMP comme modèle, même que ce ne soit que les formes, ce serait sensas.
Daniel
Messages : 17423
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Démonstration de Noël 2013

Message par Daniel »

Rien de plus facile en noir et blanc : avec n'importe quel logiciel de traitement d'image, il faut redimensionner en 320x200, réduire en monochrome et sauver en .bmp. Ensuite, avec un éditeur hexadécimal (ou un programme sur PC) retirer l'en-tête du bmp (62 octets). Chaque ligne est codée sur 40 octets, les lignes sont stockées de la dernière à la première. On peut les garder dans cet ordre pour les afficher de bas en haut sur Thomson, ou les remettre dans l'ordre naturel. Exemple :

Code : Tout sélectionner

  FILE *fbmp;
  char ecran[8000];
  int i , j;

  fbmp = fopen(filenamebmp, "rb");
  if(fbmp == NULL) return;
  fseek(fbmp, 0x3e, SEEK_SET);
  for(i = 199; i >= 0; i--) //de bas en haut
  for(j = 0; j < 40; j++)   //de gauche a droite
  ecran[40 * i + j] = fgetc(fbmp);
  fclose(fbmp);
Pour afficher l'image à l'écran il suffit d'initialiser toute la mémoire vidéo couleurs avec la couleur de fond et la couleur de forme souhaitées, par exemple $07 ou $70. Ensuite on copie les 8000 octets en mémoire vidéo formes.

Image Image
Image Image
Image Image
Image Image

Je sais aussi que le logiciel CC90 du groupe PULS permet de convertir un fichier bitmap pour PC en fichier MAP pour Thomson, c'est peut-être encore mieux car le fichier .MAP est compressé et prend donc moins de place. Je ne sais pas s'il traite les images monochromes, il faudrait lire la documentation et/ou essayer. http://www.pulsdemos.com/cc90/cc90-1.03.zip
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
Dominique
Messages : 831
Inscription : 09 mars 2010 13:37
Localisation : Limoges
Contact :

Re: Démonstration de Noël 2013

Message par Dominique »

Meci ! Je vais m'y mettre tout de suite..
Jusqu'à présent je faisais des calques et un petit VisualBasic qui calculait les bytes. :oops:

http://www.labnol.org/software/spreadsh ... xcel/6074/
__sam__
Messages : 7986
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Démonstration de Noël 2013

Message par __sam__ »

Daniel a écrit :Avec le système utilisé, le débit maximum théorique d'acquisition des données est 400 Ko/s.
Mazette! Pas loin de 80x à 100x la vitesse que tu tires d'une carte SD. Pas mal du tout.
Un LDD (3 cycles) + un branchement (2 cycles) permettent de lire 2 octets en 5 cycles. Evidemment il faut faire quelque chose avec les octets lus, ce qui réduit considérablement le débit en pratique. Le plus gros problème est le délai entre deux buffers de 512 octets, car il ne faut pas interrompre la musique ni la vidéo. La nécessité de stocker les données à jouer pendant le "gap" diminue encore un peu le débit.
Tu veux dire qu'il faut charger ces deux bufers à toute vitesse sans couper le son, c'est ca ? Dans ma routine qui jouait des samples des guignols des infos avec le timer j'avais le même genre de soucis: comme commuter la banque mémoire sur TO9 est trop lente pour chaque échantillon audio (4khz), je copiais 256 octets d'un coup dans une mémoire non commutable, ce qui réduit le temps moyen de commutation à 1/256 du temps réel. Il est théoriquement possible de copier plus (genre 1ko), ce qui réduirait d'autant la charge du temps de commutation, mais hélas, pour le 6809, la recopie de 1ko est lente et le retard entre deux échantillons lors de la recopie s’entend. Ainsi 256 était le compromis que j'avais trouvé pour que la recopie de mémoire + la commutation de banque passe relativement inaperçue à l'oreille (si on copie un buffer plus gros, on entends un glitch). Est-ce le même genres de problèmes que tu as du résoudre qui te font utiliser des buffers de 512 ?
Et aussi d'améliorer l'image avec les techniques de diffusion d'erreur de __sam__. J'ai utilisé Floyd Steinberg, par paresse.
La diffusion d'erreur est pas mal pour la finesse des teintes, mais elle a l'inconvénient de brouiller la répétition de motifs. Cela entraine une perte flagrante de la fluidité quand une grande surface grise, pourtant homogène, doit s'afficher à l'écran. Ca se voit par exemple sur la chanson les "bigotes" de Brel (ainsi que vers la fin du concert): ca clignote un max car le rideau gris du fond doit être redessiné à chaque image alors que rien n'a fondamentalement changé dans sa teinte. C'est juste la diffusion d'erreur qui a fait bouger les pixels éteints, entrainant un ré-affichage d'une zone alors qu'aucune information nouvelle y figure.

Un tramage type matrice de bayer (cf pochette de grand corps malade ou années 80) devrait permettre d’améliorer la redondance entre images et donc améliorer la fluidité, surtout pour ces zones homogènes. Tu n'as pas essayé avec ce tramage plus régulier ?

Nota: la matrice de bayer fait un peu perdre en finesse mais c'est pas forcément gênant si les FPS sont au rendez-vous. Il existe d'autres méthodes régulières (ordered-dither) qui ont un rendu similaire à la diffusion d'erreur tout en restant localisé. La méthode void-and-cluster en fait partie. La génération d'une matrice de tramage correcte n'est pas simple à mettre ne œuvre, mais il doit être possible de réutiliser une matrice pré-définie comme celle ci en 25x25, pour obtenir un rendu très très similaire à du Floyd-Steinberg (absence visible de répétition) tout en gardant la propriété de persistance du motif entre images consécutives.
Sur la partie "hard" je ne peux rien vous dire aujourd'hui, mais j'espère que nous en reparlerons l'année prochaine.
On a jamais été aussi proche... suspens :)
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17423
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Démonstration de Noël 2013

Message par Daniel »

__sam__ a écrit :Tu veux dire qu'il faut charger ces deux buffers à toute vitesse sans couper le son, c'est ca ?
En fait non, je n'utilise pas de buffer, je traite chaque octet lu à la volée :
- L'échantillon de son est envoyé au CNA au moment même où il est lu
- L'octet "déplacement dans l'image" permet de calculer l'adresse en mémoire vidéo, stockée dans le registre X
- L'octet "image" est écrit en mémoire vidéo au moment même où il est lu

Le MO5 ne permet pas d'avoir deux écrans en mémoire et de basculer de l'un à l'autre. Le rafraichissement se fait par balayage de haut en bas et de gauche à droite. S'il y a trop de différences d'une trame à l'autre il n'y a pas assez de cycles disponibles pour mettre à jour tout l'écran, les modifications perdues seront rattrapées (ou pas) à la trame suivante, ce qui explique les défauts lors de mouvements rapides ou de changements de plan.

Dans un post précédent, j'ai donné un temps de lecture de 5 cycles par octet, c'est une erreur : en réalité c'est 9 cycles. Le débit théorique maximum est donc inférieur, environ 220 Ko/s. Notez les temporisations dans le code : il y a plus de cycles de temporisation que de cycles utiles. Ceci permet de simplifier considérablement le passage d'un bloc de données au suivant, en supprimant des temporisations pour compenser la durée du changement de bloc.

On pourrait aller plus vite dans la boucle principale, mais alors il faudrait stocker les octets de son et d'image à jouer entre chaque bloc. Je le fais dans la démo Simon's Cat, en mettant l'information dans un bit inutilisé de l'échantillon son (le son 6 bits laisse 2 bits inutilisés dans chaque octet). En utilisant cette méthode, l'affichage d'une image en 16 couleurs doit être possible.

Code : Tout sélectionner

PLAY3
* lecture déplacement ecran + echantillon : 45 cycles
  LDD   EDT2       lecture 2 octets                 (6)
  STB   <$CD       joue l'octet musique             (4)
  INCB             test octet de fin $FF            (2)
  BEQ   RETOUR     fin du fichier                   (3)
  TSTA                                              (2)
  BMI   PLAY5      increment negatif                (3)
  BEQ   PLAY4      nouvelle image                   (3)
  NOP              temporisation 2 cycles           (2)
  BRA   PLAY6      incrementation                   (3)
PLAY4
  LDX   #$0000     debut nouvelle image             (3)
  BSR   WAIT16     temporisation 16 cycles         (16)
  BRA   PLAY7      lecture suivante                 (3)
PLAY5
  LEAX  256,X      increment negatif: ajout 256     (8)
PLAY6
  LEAX  A,X        incrementation index ecran       (5)
  BSR   WAIT12     temporisation 12 cycles         (12)

* lecture octet image + echantillon : 45 cycles
PLAY7
  LDD   EDT2       lecture 2 octets                 (6)
  STB   <$CD       joue l'octet musique             (4)
  STA   ,X         affiche l'octet image            (4)
  LEAY  -1,Y       decrementation compteur d'octets (5)
  BEQ   PLAY9      lire nouveau secteur             (3)
  BSR   WAIT20     temporisation 20 cycles         (20)  
  BRA   PLAY3      octet suivant dans le secteur    (3)

* detection des changements de blocs 
PLAY9
  LDA   SECT       nombre de secteurs restants      (5)
  BNE   PLAY1      il reste des secteurs a lire     (3)
  LEAU  1,U        nouveau bloc de 256 secteurs     (5)
  TFR   U,D        numero de cylindre               (6)
  STA   LBA2       registre cylinder high           (5)
  STB   LBA1       registre cylinder low            (5)
  BRA   PLAY0      lire nouveau bloc de secteurs    (3)
Merci à __sam__ pour ses conseils d'expert sur la réduction en monochrome. J'ai essayé un tramage ordonné "basique", mais le résultat étais mauvais. La méthode void-and-cluster doit être une bonne solution, je vais l'essayer. Même si elle n'apporte pas de grosses améliorations de l'image par rapport à Floyd-Steinberg, elle aura un impact important sur la fluidité de la vidéo en diminuant considérablement le nombre de différences d'une image à l'autre. Existe-t-il un logiciel de traitement d'image utilisant cette méthode, ou faut-il programmer soi-même l'algorithme ?
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7986
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Démonstration de Noël 2013

Message par __sam__ »

Daniel a écrit :Existe-t-il un logiciel de traitement d'image utilisant cette méthode, ou faut-il programmer soi-même l'algorithme ?
L'utilisation de cette méthode est identique à la matrice de bayer classique (M): si le pixel p(x,y) est au dessus du seuil M(x % w, y % h) on l'allume, sinon on l'éteint. La matrice de seuillage est simplement organisée différemment (pour reproduire un bruit bleu, plus proche de ce que font les algo à diffusion d'erreur je crois). La génération de cette matrice est décrite dans un PDF mais je n'ai pas trouvé d'implémentation concrète prête à être réutilisée. Des gens disent l'avoir fait en quelque lignes de C, mais ne fournissent pas le source. L'idéal est d'avoir une matrice assez large pour ne pas se rendre compte de la répétition de motif. Du 32x32 ou 64x64 devrait être bon, mais au final je n'ai trouvé que les matrices 14x14 et 25x25 précalculées par l'équipe de la libcaca.

Cependant avec un OCR j'ai réussi à récupérer les coefs correspondant et créer un fichier
thresholds.zip
(3.59 Kio) Téléchargé 148 fois
utilisable par image-magick. Il suffit de le dezipper et de le placer dans son $HOME/.magick/thresholds.xml pour obtenir de nouveaux modes de tramage:

Code : Tout sélectionner

$ identify -list threshold

   Threshold Maps for Ordered Dither Operations

PATH: /etc/ImageMagick/thresholds.xml

Map              Alias        Description
----------------------------------------------------
threshold        1x1          Threshold 1x1 (non-dither)
checks           2x1          Checkerboard 2x1 (dither)
o2x2             2x2          Ordered 2x2 (dispersed)
(...)

PATH: /home/Samuel/.magick/thresholds.xml

Map              Alias        Description
----------------------------------------------------
diag5x5          diag         Simple Diagonal Line Dither
vac-14x14                     14x14 void and cluster matrix
vac-25x25                     25x25 void and cluster matrix
Cela s'utilise simplement:

Code : Tout sélectionner

$ convert <fichier_source> -gamma 0.454545 -colorspace gray -resize 320x200 -ordered-dither <carto> <fichier_destination>
avec carto = vac-14x14 ou vac-25x25.
Le gamma est important pour ne pas avoir une image trop claire (cf ici).

Le truc sympa avec image-magick est que la source peut être un gif animé situé sur le WEB. Voici par exemple ce que donne:

Code : Tout sélectionner

$ convert http://www3.picturepush.com/photo/a/11279546/img/Gifs-Animados-de-Animes/13109---animated-gif-moe-nekomimi-sanada-ufo-ultra.gif -gamma 0.454545 -resize 320x200 -colorspace gray  -ordered-dither vac-14x14 ./anim-14x14.gif
Image
anim-14x14.gif
anim-14x14.gif (64.4 Kio) Consulté 6363 fois
Même chose en 25x25:
anim-25x25.gif
anim-25x25.gif (64.44 Kio) Consulté 6363 fois
Le résultat ressemble fichtrement à du Floyd-Steinberg mais 1) il est beaucoup plus rapide à produire et 2) les images sont hyper redondantes, réduisant de beaucoup la taille du gif animé par rapport à une animation à base de Floyd-Steinberg.

[Edit] hum je vois quelques pixels trop rapprochés dans le 14x14.. je vais revérifier... bingo, j'ai mal recopié.. je modifie les attachements... fait. J'espère qu'il ne reste pas d'erreur, mais vu le nombre de coefs, ca n'est pas garanti :P
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17423
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Démonstration de Noël 2013

Message par Daniel »

Merci à sam d'avoir fait tout le travail :D
Le résultat paraît bon, je ne sais pas dire quel est le meilleur entre 25x25 et 14x14. Il faudra essayer d'autres réglages de gamma et/ou de luminosité et contraste, et tester sur une séquence vidéo pour voir le résultat. Ce sera pour ma prochaine démo...

Autre possibilité, créez votre propre démo :
- fichiers .bmp monochromes 320x200 nommés 00001.bmp, 00002.bmp, ..., nnnnn.bmp dans un sous-dossier nomme "video"
- fichier .raw pcm 22050 échantillons par seconde 6 bits (complétés à 8 bits par b6 et b7 à zéro) dans un sous-dossier nomme "audio"
Il faut exactement 882 échantillons de son pour une image .bmp
Lancez le programme MOANIM ci-dessous (pensez à modifier les chemins des sous-dossiers), et envoyez-moi le fichier .mo :

Code : Tout sélectionner

//=============================================================================
// MOANIM.C - Conversion fichiers bmp et raw en sequence video pour MO5
//            Daniel Coulom - Novembre 2013
//=============================================================================

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define YDEB 0          //premier octet de l'image dans l'ecran MO5
#define YFIN 8000       //dernier octet de l'image dans l'ecran MO5
#define BUFFERSIZE 1764 //4*441 pour 882 echantillons par image

FILE *fmo;
FILE *fbmp;
FILE *fraw;
char buffer[BUFFERSIZE]; //taille du buffer pour une image
char ecran[8000];        //image telle qu'affichée a l'ecran
char cible[8000];        //image reelle lue dans le fichier
int y;                   //pointeur dans l'image

/*
PRINCIPE:
Dans chaque bloc de BUFFERSIZE octets du fichier .mo on stocke les differences
entre l'image actuelle et l'image precedente, en intercalant un echantillon
audio entre chaque octet de la video. Chaque difference est codee sur deux
octets: deplacement par rapport a la difference precedente (1-255) et nouvel
octet remplacant celui de l'image precedente. S'il y a plus de 255 octets
entre deux differences, de fausses differences intermediaires sont generees.
S'il y a plus de BUFFERSIZE / 4 differences les suivantes sont ignorees. Le
rattrapage sera effectue dans les images suivantes. Pour cela, il faut stocker
a chaque etape l'image obtenue, car elle peut être differente de l'image reelle.
ASTUCES:
Pour gagner du temps:
- on commence a la premiere ligne affichee (Y = YDEB)
- on termine a la derniere ligne affichee (Y < YFIN)
La debut d'image est indiquee par un increment 0 et le premier octet de l'image
La fin du film est indiquee par un octet audio a $FF
*/

//Affichage d'un nouvel ecran ////////////////////////////////////////////////
void Ecran(int i)
{
 y = YDEB;
 buffer[i] = 0;
 ecran[y] = cible[y];
 buffer[i + 2] = cible[y];
 y++;
}

//Affichage d'une image //////////////////////////////////////////////////////
void Image()
{
 int i; //index sur un groupe de 4 octets (deplacement, audio, image, audio)
 int k; //distance a la difference precedente, de 0 a 127

 for(i = 0; i < BUFFERSIZE; i += 4)
 {
  //affichage d'un nouvel ecran
  if(y >= YFIN) {Ecran(i); continue;}
  //recherche de la premiere difference
  //k varie de 1 a 254 pour les differences reelles
  //a defaut de difference reelle, k vaut 255 pour une difference fictive
  for(k = 1; k < 255; k++)
  {
   if(cible[y] != ecran[y]) break; //difference detectee
   y++;
   if(y >= YFIN) break; //fin d'une image
  }
  //affichage d'un nouvel ecran
  if(y >= YFIN) {Ecran(i); continue;}
  //stockage de la difference dans le buffer
  buffer[i] = k;                       //deplacement dans l'image
  buffer[i + 2] = ecran[y] = cible[y]; //nouvel octet dans l'image
  y++;
 }
 //ajout de l'audio (un octet sur deux)
 for(i = 1; i < BUFFERSIZE; i += 2)
 {
  k = fgetc(fraw);
  if(k == EOF) {buffer[i] = 0xff; continue;}
  if(k > 0x3f) {buffer[i] = 0x3f; continue;}
  buffer[i] = k;
 }
 //ecriture du buffer
 fwrite(buffer, BUFFERSIZE, 1, fmo);
}

//Generation d'un fichier video //////////////////////////////////////////////
void Video(char *filename, int filenamelength)
{
 int i , j;
 int filenumber;
 char filenameraw[256];
 char filenamebmp[256];
 char filenamemo[256];
 char string[256];
 //nom des fichiers
 sprintf(filenameraw, "..\\%s\\audio\\%s.raw", filename, filename);
 sprintf(filenamemo, "..\\%s\\%s.mo", filename, filename);
 //initialisation de l'image
 for(i = 0; i < 8000; i++) ecran[i] = 0;
 //ouverture des fichiers
 fraw = fopen(filenameraw, "rb");
 fmo = fopen(filenamemo, "wb");
 filenumber = 0;
 y = YDEB;
 //boucle de conversion
 while(1)
 {
  //ouverture du fichier bmp
  strcpy(string, "..\\%s\\video\\");
  switch(filenamelength)
  {
   case 1 : strcat(string, "%01i"); break;
   case 2 : strcat(string, "%02i"); break;
   case 3 : strcat(string, "%03i"); break;
   case 4 : strcat(string, "%04i"); break;
   case 5 : strcat(string, "%05i"); break;
   case 6 : strcat(string, "%06i"); break;
   case 7 : strcat(string, "%07i"); break;
   default: strcat(string, "%08i"); break;
  }
  strcat(string, ".bmp");
  sprintf(filenamebmp, string, filename,filenumber++);
  printf("Image: %s\n", filenamebmp);
  fbmp = fopen(filenamebmp, "rb");
  if(fbmp == NULL) break;
  //lecture de l'image cible
  fseek(fbmp, 0x3e, SEEK_SET);
  for(i = 199; i >= 0; i--) //de bas en haut
  for(j = 0; j < 40; j++)   //de gauche a droite
  cible[40 * i + j] = fgetc(fbmp);
  fread(cible, 8000, 1, fbmp);
  fclose(fbmp);
  //traitement de l'image
  Image();
 }
 //fin du programme
 for(i = 0; i < BUFFERSIZE; i += 2) {buffer[i] = 0x00; buffer[i + 1] = 0xff;}
 fwrite(buffer, BUFFERSIZE, 1, fmo);
 fclose(fmo);
}

//Programme principal ////////////////////////////////////////////////////////
int main()
{
 //Video(nom du repertoire, nombre de chiffres du nom de fichier .bmp)
 //Video("brassens", 4);        //882 echant/trame, BUFFERSIZE 1764
 //Video("joanbaez", 4);        //882 echant/trame, BUFFERSIZE 1764
 //Video("brel_amsterdam", 4);  //880 echant/trame, BUFFERSIZE 1760
 Video("brel_olympia", 5);    //882 echant/trame, BUFFERSIZE 1764
 system("pause");
 return 0;
}
original.png
original.png (31.7 Kio) Consulté 6342 fois
vac-14x14.png
vac-14x14.png (2.25 Kio) Consulté 6342 fois
vac-25x25.png
vac-25x25.png (2.31 Kio) Consulté 6342 fois
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7986
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: Démonstration de Noël 2013

Message par __sam__ »

Ca rend pas mal. Bien mieux que le dither en 8x8
original2.png
original2.png (1.08 Kio) Consulté 6336 fois
Cependant on peut y voir des pseudo alignements dans le gris-sombre de la veste. Je pense que je dois avoir un ou 2 coefs mal placé c'est suffisant pour que l'oeil :-/ Par exemple en 25x25, les coefs 0, 1 et 2 sont sur une même ligne ce qui provoque un alignement pour les intensités <= 2 (elle est masquée pour les intensités plus hautes). Je suppose que les coefs ne sont pas forcément idéaux. Il faudrait régénérer d'autres matrices.

A ce propos j'ai trouvé le code source de génération de matrice de la libcaca ici: (code python)

Code : Tout sélectionner

# Create matrices
def Matrix(w, h, val = 0):
    return [[val] * w for n in range(h)]

# Iterate in 2D space
def rangexy(w, h):
    for y in range(h):
        for x in range(w):
            yield (x, y)
# (...)
# Output 2.7.1: void and cluster matrix generation
def makegauss(n):
    c = (-1. + n) / 2
    mat = Matrix(n, n)
    for x, y in rangexy(n, n):
        mat[y][x] = math.exp(- ((c - x) * (c - x) + (c - y) * (c - y)) / (0.05 * n * n))
    return mat

def countones(mat):
    total = 0
    for l in mat:
        for x in l:
            if x:
                total += 1
    return total

GAUSS77 = makegauss(7)
GAUSS99 = makegauss(9)

def getminmax(mat, c):
    min = 9999.
    max = 0.
    h = len(mat)
    w = len(mat[0])
    for x, y in rangexy(w, h):
        if mat[y][x] != c:
            continue
        total = 0.
        for i, j in rangexy(7, 7):
            total += mat[(y + j - 3 + h) % h][(x + i - 3 + w) % w] \
                      * GAUSS77[j][i]
        if total > max:
            (max, max_x, max_y) = (total, x, y)
        if total < min:
            (min, min_x, min_y) = (total, x, y)
    return (min_x, min_y, max_x, max_y)

def makeuniform(n):
    random.seed(0)
    mat = Matrix(n, n)
    for t in range(n * n / 10):
        x = (int)(random.random() * n)
        y = (int)(random.random() * n)
        mat[y][x] = 1
    while True:
        (dummy0, dummy1, x, y) = getminmax(mat, 1.)
        mat[y][x] = 0.
        (x2, y2, dummy0, dummy1) = getminmax(mat, 0.)
        mat[y2][x2] = 1.
        if x2 == x and y2 == y:
            break
    return mat

def makevoidandcluster(n):
    vnc = Matrix(n, n)
    # Step 1: step down to zero
    mat = makeuniform(n)
    rank = countones(mat)
    while rank > 0:
        rank -= 1
        (dummy0, dummy1, x, y) = getminmax(mat, 1.)
        mat[y][x] = 0.
        vnc[y][x] = rank
    # Step 2: step up to n * n
    mat = makeuniform(n)
    rank = countones(mat)
    while rank < n * n:
        (x, y, dummy0, dummy1) = getminmax(mat, 0.)
        mat[y][x] = 1.
        vnc[y][x] = rank
        rank += 1
    return vnc

def vnccol(n):
    return lambda val : ['#fff', '#ddd'][val < n * n / 10]

if chapter(2):
    tmp = makevoidandcluster(14)
    Svg(tmp, vnccol(14)).save("out/fig2-7-1.png", 25)
    ordereddither(grad256bw, tmp).save("out/grad2-7-1.png")
    ordereddither(lena256bw, tmp).save("out/lena2-7-1.png")
    tmp = makevoidandcluster(25)
    Svg(tmp, vnccol(25)).save("out/fig2-7-2.png", 20)
    ordereddither(grad256bw, tmp).save("out/grad2-7-2.png")
    ordereddither(lena256bw, tmp).save("out/lena2-7-2.png")
Effectivement l'algo n'a pas l'air si compliqué que ca. Le point sensible semble être le makeuniform(n) qui peuple la matrice n*n avec 10% de pixels allumés choisis au hasard repartis de façon homogène. C'est là dedans qu'on retrouve les 0 1 2 mal placés. Le soucis doit probablement résider dans la taille de la fenêtre gaussienne 7x7 qui est peut-être trop petite pour détecter les rapprochements à 4 pixels près comme entre 1 et 2. Le code prévois une fenêtre gaussienne 9x9, mais elle n'est pas utilisée. La génération est peut-être trop lente avec une fenêtre aussi large.

Au fait comment extrais-tu les BMP et l'audio ? Avec virtual-dub ?
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17423
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Démonstration de Noël 2013

Message par Daniel »

Oui, j'utilise VirtualDub pour créer les images .bmp et le son .wav
Pour l'audio il faut régler les paramètres Preload et Delay pour obtenir une bonne synchronisation avec l'image.
J'ai noté toutes les opérations effectuées quand j'ai préparé un fichier de test à jouer sur MO5 (Amsterdam) :

Code : Tout sélectionner

-----------------------------------
Extraction avec VirtualDub
-----------------------------------
1) Audio full processing mode
2) Audio interleaving : Preload 0, Delay -400
3) Exporter audio -> wav     3509131 echantillons 
4) Exporter images -> bmp       3986 images
Il y a 880 echantillons par image --> taille buffer 1760 

-----------------------------------
Son avec CoolEdit 2000
-----------------------------------
1) Convert Sample Type 
   Sample Rate : 22050 Hz
   High Quality : 999
   Mono Left Mix 50%, Right Mix 50%
   Dither Depth 1
   p.d.f. Gaussian
   Noise Shaping B
   Resolution 8 bits
2) Amplify
   25%
   DC Bias Adjust Absolute -75%
3) Save As...
   PCM Raw Data
   Option 8 bits unsigned

-----------------------------------
Images avec Xnview
-----------------------------------
1) Redimensionner 320x200 Lanczos (ne pas conserver les proportions)
2) Ajuster les niveaux : 12-192
4) Convertir en binaire Floyd-Steinberg
 
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
petitjd
Messages : 2007
Inscription : 23 oct. 2007 11:50

Re: Démonstration de Noël 2013

Message par petitjd »

C'est impressionnant!
J'ai une petite idée sur l'interface utilisée, elle a donc tenue toute ses promesses!
Félicitations! Avec ca, je suppose qu'il est possible de lire l'audio en qualité cd mono et qu'il sera possible de faire une nouvelle version du controleur de disquette qui chargera chaque jeu en 1 seconde!
PetitJD
Tortue Jeulin: www.tortue-jeulin.com
Nanoreseau: www.nanoreseau.net
Proteus III: www.proteus-international.fr
Daniel
Messages : 17423
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: Démonstration de Noël 2013

Message par Daniel »

Tu devines bien, mais il faut garder le secret. Le projet sera annoncé par son concepteur. Aujourd'hui il n'est pas finalisé, il est au stade du prototype.

Le son sera en 44100 Hz (comme les CD) ou 96000 Hz (comme les professionnels), mais seulement en 6 bits mono, c'est une contrainte Thomson. Le temps de chargement d'un petit jeu MO5 ne sera pas de l'ordre de la seconde, mais du dixième de seconde. Les opérations sur disquettes seront au moins 20 fois plus rapides qu'avec un lecteur Thomson. Je n'ai pas encore écrit le soft, mais ce n'est pas difficile car il sera très voisin de celui du CS91-280. Le contrôleur sera aussi un contrôleur nanoréseau avec une autre eprom.
Daniel
L'obstacle augmente mon ardeur.
Répondre