Source Codes









Ich schreibe jetzt mehrere Programme, weil es Spaß macht. Diese werden aber echt fertig. So wie der Funktionsplotter (der allerdings auch verbessert werden kann, keine Grenze nach oben). Aber ich schreibe jetzt Programme:
Das erste Programm wird die Darstellung Bitmap-Dateien (BMP's). Dabei werde ich die Bildpunkte aber nicht farbig auf dem Bildschirm darstellen, sondern in Form von Zahlenwerten.
Weil, wenn ich die Bildpunkte Farbig darstelle, dann brauche ich entweder Qt unter Linux, dann könnte man aber auch so argumentieren, dass man mit Qt, so oder so JPEG's und BMP's usw. bereits darstellen kann. Oder man geht in den VGA-Modus des PC's. Dafür muss man aber aus Linux raus. Und das möchte ich nicht. Dann muss man bei der Boot-Prozedur arbeiten.
Danach arbeite ich mit JPEG's. Ich schreibe ein Programm, was mit JPEG's arbeitet. Dann schreibe ich das aber so, dass es diese auch nicht darstellt, sondern speichert. Ebenso bei den BMP's. Es speichert Bilder in dem Format von JPEG und BMP.
Also:
1. Programm zur Darstellung von BMP's als Zahlenwerte
2. Ein Programm zum Beispiel zum Speichern von BMP's und JPEG's
3. Ich arbeite mit der Webcam. Ich habe die Header-Datei zum ansteuern der Webcam bereits durchgelesen. Dazu gibt es Bibliotheken. Diese sind nicht unübersichtlich. Ich werde sie benutzen um ein Bild in JPEG oder BMP zu speichern.
4. Ich denke darüber nach, wie ich auf dem Webserver einen Stream so hin übertragen kann, dass er von diesem als Film geguckt wird. Nun ist es so: Bei einer öffentlich, sichtbaren IPv4-Adresse ist es kein Problem einen Film zu streamen. Dazu muss man nur die Software öffnen und die Webcam haben. Unter der IP-Adresse des Rechners, läuft dann der Stream. Schwieriger ist es, wenn man einen externen Webserver hat. Dann lässt sich auf diesem von einem PC nicht so einfach ein Film streamen. Vielleicht könnte man darüber nachdenken.


Mit dem BMP darstellen und auslesen, bin ich schon bald fertig.


http://www.talkortell.de/bmpproject/bmpv0.1.c Ich glaube, das letzte müsste schon funktionieren.


http://www.talkortell.de/bmpproject/bmpv0.2.c
http://www.talkortell.de/bmpproject/bmpv0.3.c
Hier das BMP, an dem ich die Sache getestet habe (Vorsicht, muss BMP sein) Und hier ein Teil des Ausgabe von dem Programm
http://www.talkortell.de/bmpproject/bmpv0.4.c
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255
blue: 255 green: 255 red: 255



Jetzt machen wir die Sache anders: Wir ersetzen jeden Roten Punkt durch den Wert 0x01. Und speichern das neue Bild. Das Ergebnis, gleich.


Jetzt können wir folgende Versuche machen: Zunächst ersetzen wir den rot-Wert bei einem ganz weißem Bild. Mal sehen, was raus kommt. Das zweite was man machen kann, man hellt ein Bild auf. Das heißt man addiert zu jedem Rot-Wert oder jedem Blau oder allen einen bestimmten Wert. Das heißt: +2 oder +20. Die nächste Idee wäre, ein Schachbrett zu entwerfen. Und zwar so, dass man ein BMP zeichnet, sich dabei geometrischer Methoden bedient. Dann wäre es interessant das Schachbrett auf ein existierendes BMP an zu bringen. Noch besser ist: Wir hatten es von aufhellen, jetzt wäre es natürlich interessant, ein Schachbrett aufgehellt, also durch Aufhellung auf ein Bild an zu bringen.
Natürlich haben wir bei unseren bisherigen BMP's Dateien gehabt, die mit Gimp gezeichnet wurden. Und Gimp verwendet keine Farbpalette. Kann sie aber sehr wohl öffnen. Jetzt wäre es natürlich interessant ein entsprechendes Bild mit Palette zu erzeugen, und es mit Gimp zu öffnen.


Hier die funktionierende Sache:
http://www.talkortell.de/bmpproject/bmp.c

Hier das Bild:
http://www.talkortell.de/bmpproject/test.bmp



Zum Zeichen, dass die Sache jetzt sicher funktioniert, kopieren wir ein BMP, und zwar nicht Byte für Byte, sondern in dem wir die entsprechenden Werte entsprechend speichern. Also keine Byte zu Byte-Kopie, eine Datei roh kopieren, sondern wirklich die Werte echt einsetzen. Und es funktionier! http://www.talkortell.de/bmpproject/test3.bmp



http://www.talkortell.de/bmpproject/bmp2.c




Ein Fehler war, dass ich mit einer 64-Bit-Architektur arbeite und nicht mit 32 Bit. Long ist somit 64 Bit, muss aber 32 Bit sein, dann werden die Kopfdaten auch richtig ausgelesen. In dieser Version werden die Kopfdaten richtig ausgelesen. Yeapeah! Ich weiß, wo der Fehler lag. Ich arbeite mit einer 64 Bit Rechnermaschine. Das ganze war auf 32 Bit abgestimmt!

http://www.talkortell.de/bmpproject/bmp5a.c




2017-10-09, ab genau hier funktioniert die Sache

2017-10-09, jetzt mit Colortable bis 256 Einträgen

so, jetzt mit Colortable bis 256 Einträgen (nicht Farben, Einträgen in der Colortable(!), mit 32 Bit Farben kommt das ganze so oder so schon klar), noch nicht an Colortable getestet, aber funktioniert sicher... auf jeden Fall so.


Im nächsten Schritt erzeugen wir ein eigenes Bitmap. Wir füllen eine Datei mit eigenen Daten. Danach gucken wir, ob wir das im Bildbearbeitungsprogramm darstellen können.

2017-10-09, und es ist mir gelungen ein BMP zu erzeugen:...

2017-10-09, hier habe ich ein nicht scwarzes BMP erzeugt:...


Das sieht doch auch Sexy aus:

2017-10-09, Bilder übereinanderlegen



+



=








Zum Rauschen, ..., additiver Mischer, multiplikativer Mischer, ...






So, nun zum Auslesen der Webcam.
Das erste, was ich probiert habe, ist das Device (Gerät) unter Linux /dev/video0 mit dd aus zu lesen.
Mit

dd if=/dev/video0 of=/home/david/out.ppm

Das funktioniert nicht. Das Gerät lässt sich nicht öffnen. Aber das Videogerät lässt sich unter Linux, als Datei öffnen.

#include <stdio.h>
#include <stdlib.h>
#define SIZE 307200 // number of pixels (640x480 for my webcam)
int main() {
   FILE *camera, *grab;
   camera=fopen("/dev/video0", "rb");
   grab=fopen("grab2.raw", "wb");
   float data[SIZE];
   fread(data, sizeof(data[0]), SIZE, camera);
   fwrite(data, sizeof(data[0]), SIZE, grab);
   fclose(camera);
   fclose(grab);
   return 0;
}


Allerdings erhalten wir so nur ein schwarzes Bild. Nun installieren wir unter OpenSuSE Tumbleweed das Paket libv4l-devel.

Und nun rufen wir die Seite

https://www.c-plusplus.net/forum/229046-full auf.

Hier steht der Code:

#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <libv4l1.h> #include <libv4l2.h>


#define GES_LAENGE (320*240)

unsigned char bild[GES_LAENGE];

int main()
{
   int fd;
   long laenge;
   struct video_window video_win;
   struct video_picture video_pict;
   FILE *bilddatei;

   if((fd = v4l1_open("/dev/video0", O_RDONLY)) == -1)
   {
     printf("Fehler beim Oeffnen von /dev/video0\r\n");
     return 1;
   }
   if( v4l1_ioctl( fd, VIDIOCGWIN, &video_win) == -1)
   {
     printf("Fehler beim setzen der Einstellungen\r\n");
     return 1;
   }
   laenge = video_win.width * video_win.height;
   if( laenge > GES_LAENGE)
   {
     printf("Bild ist groesser als angegeben\r\n");
     return 1;
   }
   printf("Länge: %d", laenge);

   v4l1_ioctl(fd, VIDIOCGPICT, &video_pict);

   if( v4l1_read( fd, bild, laenge) == -1)
   {
     printf("Auslesen der Kamera nicht möglch\r\n");
     return 1;
   }
   if((bilddatei = fopen( "bild.ppm", "w+b")) == NULL)
   {
     printf("Konnte die datei zum schreiben nicht öffnen\r\n");
     return 1;
   }
   v4l1_close(fd);
   fprintf( bilddatei, "P6\n%d %d\n255\n",video_win.width, video_win.height);
   fwrite( bild, 1,   video_win.width*video_win.height,bilddatei);
   fclose(bilddatei);
   return 0;
}


Übersetzt wir das erste Programm mit
gcc webcam2.c -o capture -lv4l1 -lv4l2


Der Code ist mit dem von oben, quasie identisch. Nur, dass er statt den typischen open und close, zum Beispiel v4l1_open und v4l1_close verwendet.

Dieses Programm speichert die Daten in einem *.ppm-Datenstrom.

Die Hauptarbeit haben wir geleistet. Wir Können ein *.bmp erzeugen. Wir nehmen nun den Roh-Datenstrom mit einfach nur Farbpixeln und bringen ihn in einer *.bmp-Datei unter.
Eine Anmerkung zu dem Code von oben: Da ist scheinbar ein Fehler drin. Denn hier steht für die Länge des Datenstroms 240*320. Dabei wurde vergessen, dass ein Pixel nicht unbedingt 1 Byte groß ist. Ein Pixel kann auch 3 Byte oder 4 Byte groß sein. Das heißt 240*320*3. ...
Wir speichern den Datenstrom als *.bmp. Und wir erhalten auf verschiedenen Bildern, folgendes:

Zunächst die Aufnahmen mit einem bereits funktionierendem Programm für die Aufnahme von Bildern:






Nun die Aufnamen mit unserem Programm:




Man sieht hier eindeutig Kohärenzen. Bei dem letzten Bild sieht man sogar, dass die Türe geschlossen ist und man erkennt den Türknauf.

Mit ein bisschen Spielerei und Formatanpassung (Länge und Breite), sowie der Größe von Pixeln bekommen wir ein echtes Bild.

2017-10-13, so, jetzt hat die Sache funktioniert, ...





















Wie konnte das funktionieren.
Na ja, zunächst war mal raus zu kriegen, wie groß ist ein Bild denn nun wirklich?
Die Antwort ist einfach: 240*320.
Die ist einfach. Denn das selbstgeschriebene Programm "capture", was die Videokamera ausließt und ein Dump erzeugt, zeigt dies selber an. Es zeigt an: 240*320 Pixel, ist das Bild groß.
Die Frage lautet aber viel mehr, wie groß ist die ganze Sache denn nun wirklich? Die Antwort ist einfach: Zunächst mal, wie viel sind 240*320. Dies lässt sich mit dem Taschenrechner ausrechnen. 240*320 = 76800. Jetzt ist die Frage, wie groß ist ein Pixel? Ist ein Pixel 1 Byte, 2 Byte oder 3 Byte groß, wenn wir die Webcam auslesen. Dafür machen wir folgendes: Wir erstellen ein Dump mit 240*320*3 Byte. Wir tun also so, als ob ein Pixel 3 Byte groß wäre. Dabei geben wir jeden Pixel aus, und zwar wirklich jeden Pixel, so, dass wir seinen Wert erkennen können. Desweiteren geben wir aber nicht nur die Pixel selber aus, sondern ihre Position. Das heißt, der wievielte Pixel das ist. Und wir erstellen nun das Dump. Dann gucken wir in das Bild. Wir wissen das Bild ist 240*320 Pixel groß, 240*320 = 76800. Nun gehen wir das Dump durch. Wir gucken, an welcher Stelle weisen die Pixel Werte auf, die nicht in das Bild gehören können, und sich dadurch zeigen, dass jeder Pixel den Wert 0 hat. Dies ist aber Stelle 153600 der Fall. 240*320*2 = 153600. Das heißt, ein Pixel ist zwei Byte groß.
Jetzt haben wir ein Problem, oder doch nicht. Aber: Wir stellen in dem BMP zunächst ein, ein Pixel ist zwei Byte groß und zeigen das Bild an. Aber es funktioniert nicht. Denn das Bildanzeigeprogramm hat nichts von 16 Bit breiten Pixel gehört, sieht so aus. Aber wir machen es jetzt anders. Wir erzeugen ein BMP, das 3 Byte Pixel hat. Wir tun also so, als ob wir Pixel mit 3 Byte haben, nehmen die Informationen aber von den 2 Byte großen Pixeln. Das heißt, wir setzen den dritten Pixel = 0, oder = 50 oder = 90 oder = 255. Wie auch immer. Das Ergebnis lässt sich aber noch deutlicher verbessern, in dem wir das dritte Byte, gleich dem ersten Byte oder dem zweiten Byte setzen. Und das Ergebnis kann sich wie im letzten Bild einigermaßen sehen lassen.

#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <libv4l1.h> #include <libv4l2.h> //#include <linux/videodev.h>

#define GES_LAENGE (320*240)
#define SIZE_OF_PIXEL 2

unsigned char bild[GES_LAENGE*SIZE_OF_PIXEL];

int main()
{
  int fd;
  long laenge;
  struct video_window video_win;
  struct video_picture video_pict;
  FILE *bilddatei;
  long i;

  if((fd = v4l1_open("/dev/video0", O_RDONLY)) == -1)
  {
   printf("Fehler beim Oeffnen von /dev/video0\r\n");
   return 1;
  }
  if( v4l1_ioctl( fd, VIDIOCGWIN, &video_win) == -1)
  {
   printf("Fehler beim setzen der Einstellungen\r\n");
   return 1;
  }
  laenge = video_win.width * video_win.height * SIZE_OF_PIXEL;
  printf("breite: %d, hoehe: %d\n", video_win.width, video_win.height);
  /*if( laenge > GES_LAENGE)
  {
   printf("Bild ist groesser als angegeben\r\n");
   return 1;
  }*/
  printf("Anzahl, Bytes %li\n", laenge);

  v4l1_ioctl(fd, VIDIOCGPICT, &video_pict);

  if( v4l1_read( fd, bild, laenge) == -1)
  {
   printf("Auslesen der Kamera nicht möglch\r\n");
   return 1;
  }
  if((bilddatei = fopen( "bild.ppm", "w+b")) == NULL)
  {
   printf("Konnte die datei zum schreiben nicht öffnen\r\n");
   return 1;
  }
  v4l1_close(fd);
  fwrite( bild, 1, video_win.width*video_win.height*SIZE_OF_PIXEL,bilddatei);
  for(i = 0; i < laenge; i++)
   printf("Byte %li: %i\n", i, bild[i]);
  fclose(bilddatei);
  return 0;
}

Übersetzt wir das erste Programm mit
gcc webcam2.c -o capture -lv4l1 -lv4l2
Und aufgerufen mit:
./a.out bild.ppm ready9.bmp > test2.txt
Es erzeugt dabei eine Datei bild.ppm
Das zweite Programm wird übersetzt mit:
gcc bmp19.c
Und aufgerufen mit
./a.out bild.ppm ready9.bmp > test2.txt
Dabei muss ein Mal Enter gedrückt werden und das zweite Programm wird auf bild.ppm angewendet.

So, jetzt erzeugen wir JPEG's

Der erste wirkliche Schritt ist getan: Kosinus-Transformation: So, jetzt kommen wir zum nächsten Schritt. Dafür gehen wir einen Schritt zurück. Wir teilen zunächst unser BMP in 8x8 Matrizen ein (zumindest im geistigen Sinne) und des Weiteren, folgt die Farbumrechnung. Darauf wenden wir die Kosinus-Transformation an.

2017-10-21, ..., das sinnbildliche Rauschen, ..., motion bekommt einen großen Bruder

Jetzt zu unserem Smiley.
Im ersten Schritt geht man davon aus, es gibt zwei Farben. Welche sind egal. Farbe und Kontrastfarbe. Zum Beispiel Schwarz und Gelb, Schwarz und Rot und so weiter.
Das Problem wird aber mit regulären Ausdrücken gelöst.
Das erste, was wir machen, ist, das Bild absuchen. Die regulären Ausdrücke gelten für die Farbanteile, die geringer sind. Das heißt, existiert schwarz und gelb, dann zählen wir alle gelben Punkte und alle schwarzen Punkte. Sind die schwarzen Punkte in der Minderzahl, dann wird der reguläre Ausdruck für die schwarzen Punkte erstellt.
Das zweite, oder das allererste, was wir machen, ist: Wir lesen das Bitmap in ein zweidimensionales Array ein. Wir haben ein Bitmap, das ist eine Folge von Bytes. Diese liegen quasi linear hintereinander. Wir lesen aber jetzt anhand der Information, wie groß Breite und Länge ist, dieses lineare Array in ein zweidimensionales Array ein.
Der nächste Schritt besteht darin, eine Art "Rauschen" ein zu führen. Da wir nur zwei Farben verwenden, müssen wir das "Rauschen" in dem Falle nicht für die Farben verwenden, sondern für die Richtung. Dieses Rauschen ist aber fest eingerichtet. Nun ist das bei regulären Ausdrücken normal.
Man denke daran. Ein Buchstabe kann zwischen "A" <= "E" sein. Das heißt, auch in einem regulären Ausdruck ist es normal, oder gerade das ist normal, oder eigentlich der Sinn eines regulären Ausdruckes, nicht eben einen festen Buchstaben zu haben, wie A oder B, umgekehrt dafür alleine zum Beispiel eine Wiederholung, die alleine beliebig wäre. Ein regulärer Ausdruck könnte es aber schon sein, indem wir | (ODER) einführen und * (das heißt) eine beliebige Wiederholung. Auch das würde schon zum Ziel eines simplen, kleinen regulären Ausdrucks führen. Umgekehrt muss man sehen, dass man mit der Schreibweise I (ODER) nicht glücklich wird. Das heißt, wir schreiben nicht A|C, dafür, dass wir A oder C haben, und machen dies bei 12 Buchstaben. Sondern wir führen einen Bereich ein, also, das kleiner gleich: "A" <= "E". Dies überlassen wir aber dem Computer, genauso wie den regulären Ausdruck überhaupt. Wir schauen uns den gar nicht an. Sondern: Der Computer soll anhand des Ausdrucks feststellen, ob der Smiley lacht oder traurig ist. Der reguläre Ausdruck interessiert nicht.


Wie, soll das mit dem Smiley funktionieren?

Also

In dem regulären Ausdruck, speichern wir zwei Farben

R: Rot, Geld
S: Schwarz

oder

R: Schwarz
S: Rot, Gelb

oder wie auch immer.

Wenn die eine Farbe kommt, kommt ein R, wenn die andere Farbe kommt, kommt ein S

jetzt speichern wir die Anzahl, der R und S, die kommt

5*S, bedeutet 5 S
6*s, bedeutet 6 S
7*S, bedeutet 7 S

Dann kann der Ausdruck aussehen, wie folgt:
5*S, 6*R, 10*S

Diese 5, 6, 10, ..., wie auch immer, werden ersetzt durch n.
n ist eine Variable. Das heißt, hier können beliebig viele stehen.

Jetzt kommt der zweite Punkt,
der erste ist: Wir haben zwei Informationen gespeichert: R und S, die Farbe
n, die Länge

Jetzt kommt eine weitere Information:
Die Richtung. Die Richtung, gibt an in welcher Richtung der nächste Punkt liegt, der dieselbe Farbe hat.

So zum Beispiel
RRRR
RORR
RROR
RRRR
Das untere O, liegt -1 versetzt nach unten, als -1, -1.

Jetzt haben wir aber eine zweite Information: Nämlich, wir sind in einem Bild.
In einem Bild haben wir nicht automatisch einen Strich, der aus jeweils der Breite von einem Punkt besteht.

Also, haben wir neben der Richtung eine zweite Information.
Diese zweite Information besteht generell aus vier Informationen. Trotzdem ist es eine Information.
Diese eine Information besteht zunächst aus vier Informationen: Aber, die Information besteht aus 8 Informationen:
Norden, Nord-Ost, Ost, Süd-Ost, Süd, Süd-West, West, Nord-West
Aber wir sehen, zunächst mal gedacht, vier Informationen, aber 8 in der Realität.
Das sind 4 oder 8 Informationen, diese 4 oder 8 Informationen sind aber eine.
Diese eine Information gibt 8 Informationen preis. Umgekehrt, ist diese eine Information ein Vektor. Eine Information, die aus 8 Informationen besteht, muss nicht in Wirklichkeit eine Information sein, die 8 Informationen ist, sondern es ist ein Vektor.
Und dieser Vektor enthält 8 Elemente.

Jetzt bringen wir in unserem regulären Ausdruck folgende drei Informationen unter:

Farbe: Rot-Schwarz, Schwarz-Geld, Rot-Geld, Schwarz-Rot, ...

Die Länge n
Dann der Vektor, Vektor mit 8 Elementen, die benachbarten Felder.

Jetzt wie sollen die regulären Ausdrücke aussehen?

Jetzt ist meine Idee:

Zunächst Mal, die Verkettung, Concatenation.

ABC
bedeutet auf A, folgt B, folgt C

C(AC+B)D
bedeutet auf C folgt AC, oder B, folgt D
Also CAC oder CBD

Hüllebildung:

(AB)* = ABABAB...

Jetzt müssen wir wohl bei der Verkettung, Concatenation anfangen.

Wir sind es gewohnt, in einem Text, folgt Buchstabe auf Buchstabe
Das heißt:
ABCDEFG...

Jetzt sind wir im zweidimensionalen Raum.
Und: Wir haben von Vektoren gesprochen. Das heißt von einer Information, die aus 8 Informationen besteht, nämlich der Vektor, der benachbarten Felder.

Jetzt haben wir im Text

ABC

Hier folgt nach dem A, das B

umgekehrt kann man denken

AB1B2 Auf A folgt in der einen Richtung B1 in einer anderen Richtung B2

Nun haben wir 8 Richtungen.

Also
A[a1, a2, a3, a4, a5, a6, a7, a8]

Natürlich können wir nach jeden Buchstaben, so zu sagen, den folgenden speichern.

Dann schreiben wir wie im Text

ABCDEFG

aber wir haben ja Richtungen.
Also, kann man folgendes wie folgt interpretieren

Aa1a2

In die eine Richtung folgt a1, in die andere a2

Aber, warum das nicht so ausdrücken

A[b1, b2, b3, b4, b5, b6, b7, b8]
Das ist nichts als eine andere Ausdrücksweise, auch die Ausdrucksweise von oben, könnte man so interpretieren. Allerdings macht es das Leben leicht. Warum? Wir haben ja gar nicht vor, den regulären Ausdruck später zu lesen. Wir wollen das gar nicht wissen. Das erledigen zwei Programmteile für uns. Das eine ließt einen Smiley ein und erstellt einen Ausdruck, das andere ließt einen Smiley ein und vergleicht ihn mit dem Ausdruck. Was da jetzt in der "Datenbank" des Computer steht, wollen wir nicht wissen. Man kann so denken, der reguläre Ausdruck ist in der "Datenbank" untergebracht. Das interessiert uns nicht. Aber wir entwickeln das Programm und da müssen wir genau wissen, was wo ist.

Wenn die Richtung gleich bleibt, dann schreiben wir n.
Vereinfachen wir die Sache: kommen zwei, sagen wir vollkommen identische Punkte, nacheinander,
dann schreiben wir n = 2. Aber, sobald wir n = 2, schreiben wir n.
Das heißt für jedes n > 1, (2, 3, 4, ...) , schreiben wir autoamtisch n. n > 1, bedeutet, also 2, 3, 4, ... hier können beliebig viele Pixel folgen, die identisch sind. Das ist das Prinzip der Hüllenbildung.

Jetzt noch eine Frage: Wenn wir einen Ausdruck finden, es gibt ja viele Ausdrücke. Man kann aus einem regulären Ausdruck eine Information schließen, mit der man etwas in einer Folge findet. Jetzt ist die Frage, gibt es nicht viele reguläre Ausdrücke, die, dasselbe besagen? Das mag sein. Zum Beispiel ABABAAB kommt (AB)* ziemlich nahe. Nun haben wir aber gesagt, dass wir ab n>1 (AB)* einsetzen. Wenn wir jetzt eine Menge regulärer Ausdrücke finden könnten, dann ist das wahr. Aber ist das interessant? Wenn wir uns den regulären Ausdruck gar nicht anschauen, sondern das dem Programm überlassen, ist das sicher noch weniger interessant. Warum? Weil der Ausdruck kann sogar beschissen aussehen, soll heißen, der Ausdruck ist im Computer, kann uns doch egal sein, wie der aussieht, im schlimmsten Falle ist es eine Verschwendung von Speicherplatz. Und wie unlesbar und häßlich der aussieht kann uns egal sein, der Computer kann ihn interpretieren. Umgekehrt könnte man mehrere reguläre Ausdrücke finden, die dasselbe besagen, auch wenn unser Computer mit unserem Programm, immer nach demselben Schema vorgeht und somit immer auf dieselbe Art und Weise welche findet, dann kann uns das egal sein. Denn wenn mehrere reguläre Ausdrücke gefunden wurden, besagen sie dasselbe. Und somit kann man sie im zweiten Schritt, gleichermaßen anwenden.

Jetzt haben wir folgendes Problem:

Hüllenbildung. Das Entweder/Oder schließe ich aus.

Wir haben zwei Farben: Schwarz und Geld, Rot und Schwarz und so weiter.

Wenn wir aber genau zwei Farben haben, dann brauchen wir den regulären Ausdruck nur für eine Farbe auf zu stellen. Die andere Farbe vernachlässigen wir.
Wenn wir aber Entweder/Oder ausschließen, dann können wir uns die Operation A|B ersparen.
Dann haben wir zwei Operationen: AB, das heißt, auf A folgt B
Oder die Hüllenbildung *A. Das heißt, es folgen beliebig viele A: AAAAAA... Mehr als die drei Operationen gibt es so oder so nicht. Da wir eine ausgeschlossen haben, gibt es nur noch zwei. Diese sind wie gesagt, ABCD und *A Jetzt kann man dieses *A betrachten.
Wir sind bei unserem Vektor.
Da können wir jetzt auf ein Mal, zwei Dinge unterscheiden:
*A[b1, b2, b3, b4, b5, b6, b7, b8]
A[*b1, *b2, b3, b4, b5, *b6, b7, b8]
Das eine gilt dafür, dass der ganze Ausdruck wieder folgt, das heißt, dass der nächste Punkt eindeutig identisch ist. Für alle Punkte, b1 bis b8, und das bedeutet: Jeder dieser Punkte b1 bis b8 hat wiederum dieselben Eigenschaften wie A. Das heißt, jeder hat auch wieder solche Nachbarn.
Umgekehr bedeutet: A[*b1, *b2, b3, b4, b5, *b6, b7, b8], dass die Punkte b1, b2, b6, dieselben Eigenschaften haben, wie A, aber nicht b3, b4, b5, b7, b8

Jetzt kann man die Sache als Baum darstellen:

A[B[c1, c2, c3, c4, c5, c6, c7, c8],b2, b3, b4, b5, b6, b7, b8]
Das Sternchen wiederum bedeutet nur: Hier kann bis zu dem Unterknoten, der im Baum dargestellt ist und ein Unterknoten ist, beliebig oft, der eigentliche Knoten stehen.
Doch, jetzt ist die Sache realtiv klar:


http://www.talkortell.de/smiley01.c


So, ich bin jetzt mit meinem Programm so weit:
Siehe, letzter Beitrag:
Ich benutze nach wie vor BMP's. Windows *.bmp's. Ich benutze keine Rohdaten. Jetzt ist mir aufgefallen: Wenn ich eine Datei unter GIMP zum Beispiel speichere, also einen Smiley und ihn nach BMP konvertiere, dann enthält die Datei mehr als zwei Farben, auch wenn im Bild nur zwei Farben zu sehen sind. Ich habe aber als "Postulat", dass nur zwei Farben enthalten sind. Also habe ich das Problem jetzt so gelöst. Das Programm geht jede einzelne Farbe durch. Es wird unterschieden zwischen der Mehrheit der Farben und der Minderheit der Farben. Ich habe ja zwei Farben. Das war das "Postulat". Ich sage jetzt, die Farbe die in der Mehrheit auftritt ist die eine Farbe, alle anderen Farben in der Minderheit sind die andere Farbe. Dazu zähle ich das Auftauchen der Farben im Bild. Ich gehe jeden Punkt durch, wenn er nicht schon verglichen wird (sonst haben wir es mit extrem langen Programmlaufzeiten zu tun), sondern ich vergleiche jeden Punkt, wenn seine Farbe nicht schon bekannt ist und zähle das Auftreten der Farbe an dem Punkt im weiteren Bild. Wenn ich damit fertig bin, nehme ich die Farbe die am häufigsten auftritt als die eine Farbe.
Im nächsten Schritt ersetze ich jede Farbe, die nicht der Mehrheit angehört, durch eine bestimmte Farbe, die von der Mehrheit verschieden ist.
Bislang öffne ich also eine BMP-Datei. Und ich zähle das Auftreten der Farben und ersetze es.
Am Schluss wird die Sache so aussehen: Ich rufe das Programm auf: "programmname bild1.bmp bild2.bmp". Dann gibt das Programm aus, ob die Bilder das identische aussagen oder nicht.


http://www.talkortell.de/smiley02.c


letzter Beitrag:
In diesem Fall starten wir jetzt in der letzten Schleife, die noch nicht fertig ist, den eigentlichen Algorithmus. Die letzte Schleife ist noch nicht ausgefüllt, hier steht der Algorithmus. Man geht an jeden Punkt, der von der Farbe mit der Minderheit ist und durchläuft hier (das ist ja selber eine Schleife, die zu jedem Punkt geht), eine weitere Schleife, die den Algorithmus darstellt: Hier wird von jedem Punkt ein Mal aus der Algorithmus gestartet, dass nämlich das Suchmuster erstellt wird. Oder eigentlich der Ausdruck vom Suchmuster, der aber ja uns nicht bekannt ist: Den schauen wir nicht an, der steht nur im Programm.


http://www.talkortell.de/smiley03.c


etzt, kann man auch von einem Rauschen sprechen, in einem ganz anderen Sinne.
Jetzt hatten wir es mit analogen Rauschen, digitalen Rauschen zu tun. Beim analogen Rauschen spielen zwei Dinge eine Rolle: Mischer (Mischung bedeutet zwei Signale werden miteinander gemischt, dabei entweder additiv oder multiplikativ), beim additiven Mischen kann man auch von einer generellen Pegelanpasssung reden. Wenn die Impedanz oder der Pegel nicht stimmt, dann gibt es auch ein Rauschen. Das führt nicht automatisch dazu, dass das Bild einfach heller wird, sondern es kann zu Verzerrungen führen. Beim digitalen Rauschen kann man sogar zum selben Ergebnis kommen, aber zunächst hier sind beim Rauschen zwei Sachen zu unterscheiden: Das eine ist das Rauschen im Punkt. Hier kann ein Wert von +2, einen Unterschied machen und ist also ein Rauschen. Dann kann man sagen, bei jedem Punkt, gilt +2. Das ist ein Rauschen, das für jeden Punkt gleich ist für das ganze Bild. Nun kann man einen Prozentsatz einführen, in wie weit für ein Punkt ein Rauschen besteht: wenn Werte von 0 bis 255 zugelassen sind, ein Punkt hat den Wert 100, der andere 98, dann herrscht ein Rauchen für den Punkt von 2%. Umgekehrt kann man alle Punkte zusammensetzen und am Ende hat man einen Durchschnittswert für das gesamte Rauschen. Umgekehrt.
Jetzt haben wir es mit analogen Rauschen, digitalen Rauschen zu tun, jetzt kommt der Smiley. Hier haben wir ein Rauschen, das bezieht sich auf das gesamte Bild. Hier haben wir also ein Rauschen im Ausdruck. Der eine grinst, der andere ist traurig, das ergibt ein Rauschen. Und zwar, was die Aussage des Bildes betrifft. Feststellen kann man das aber nicht darüber, dass man wie bei dem Linux-Programm "motion" vorgeht. Denn dieses stellt zum Beispiel ein farbliches Rauschen fest. Umgekehrt kann man jetzt sagen: In einem Text ist ein typisches Verhalten nach einem Suchmuster zu suchen.
Das eine wäre, wir rufen einen Texteditor auf, zum Beispiel "kate" unter KDE, Linux. Dann suchen wir überall nach dem Wort, "Hallo Welt". Das kann mehrfach auftauchen oder aber es kann auch von uns ersetzt werden, durch "hello world". Wir können es dabei jedes Mal einzeln ersetzen und das nächste suchen, die andere Methode wäre es im gesamten Text zu ersetzen. Jetzt gibt es hier die typischen Algorithmen. Der erste wäre der Brute-Force-Algorithmus. Dann kommen Algorithmen von Knuth-Morris-Pratt und B...
Das wäre, wenn wir ganz konkretes Suchmuster suchen.
Eine andere Methode wäre die Eingabe von regulären Ausdrücken. Hier spezifizieren wir zum Beispiel, dass wir eine Zeichenfolge, AB, AAB, AAAB, AAAAB, AAAAAB haben, aber nicht indem wir jeden Ausdruck eingeben, sondern in dem wir allgemein für alle Ausdrücke *AB schreiben.
Dann kann man das natürlich auf den Zweidimensionalen Raum ausdehnen.
Darauf bezieht sich der letzte Beitrag mit seinem Quelltext, hier sieht man eine Funktion make_pattern.


http://www.talkortell.de/smiley04.c


http://www.talkortell.de/smiley05.c


http://www.talkortell.de/patternmatching.c


http://www.talkortell.de/patternmatching2.c


http://www.talkortell.de/patternmatching3.c


http://www.talkortell.de/patternmatching4.c


Nächster Tag

http://www.talkortell.de/smiley06.c


So, weit bin ich mit dem Code bisher (Smiley) Jetzt mache ich am Besten einen Versuch. Ohne Speicherplatz an zu fordern, mache ich die Funktionsaufrufe, ohne Datenstruktur. Also die Rekursiven zu Erstellung der eigentlichen Datenstruktur, um zu gucken, ob es mit diesen rekursiven Funktionsaufrufen klappt.


http://www.talkortell.de/smiley07.c


Wenn man sich den letzten Beitrag anschaut, scheint es nicht an der Menge und Häufigkeit der rekursiven Funktionsaufrufe zu liegen. Ich habe nämlich jetzt die Menge der rekursiven Funktionsaufrufe stark reduziert, indem, ich MAX_LINE_HEIGHT und MAX_LINE_WIDTH stark verkleiner habe. Der Speicherzugriffsfehler findet trotzdem noch statt.


http://www.talkortell.de/smiley08.c





http://www.talkortell.de/smiley09temp.c


Es zeigt sich an diesem Beispiel eindeutig, dass es sich um einen Speicherzugriffsfehler, wegen "to deeply nested" handelt. Denn ich habe hier die Funktion make_pattern, alleine getestet, lässt man nur 3 IF's steht funktioniert sie bei MAX_LINE_HEIGHT = 3 und MAX_LINE_WIDTH = 3, gerade noch. Ab 4 bis 5 IF's scheitert die Funktion.
Deswegen muss ich mir einen nicht rekursiven Algorithmus ausdenken. Ich muss jetzt eine nicht rekursive alternative Ausdenken.

Ich weiß, schon, wie ich das Problem löse. Ich gehe zu jedem Punkt
for(k = 0; k < biHeight; k++) {
for(l = 0; l < biWidth; l++) {
... Dann gehe ich von jedem der Punkte ein Mal schräg nach, gerade nach oben, schräg links, rechts, ...
Dann zähle ich die Anzahl der Punkte, die ich gehen kann, bei der also die Farbe gleich ist.



Also: An jeden Ort gehen:
for(k = 0; k < biHeight; k++) {
for(l = 0; l < biWidth; l++) {
...
Dann von jedem der Punkte aus:
Nord, Nord-Ost, Ost, Süd-Ost, Süd, Süd-West, West, Nord-Ost
und zähle, die Anzahl der Punkte, bei denen das gleich bleibt.
Dabei zähle ich die Schritte mit. Ist n > 1, dann wird * gesetzt. Ist n = 1. Dann gilt die Regel (A|B): Wir wissen wir haben zwei Farben A und B.
Wir haben die Regeln *A, A|B, A und B. Das heißt, ich für n > 1 setze ich *, da ich eine Art "Rauschen habe" setze ich für n=1 (A|B) und für n = 0, setze ich B oder 0 ein.


http://www.talkortell.de/smiley10.c





http://www.talkortell.de/smiley11.c





http://www.talkortell.de/smiley11.c


So, jetzt ist diese Routine fertig. Jetzt kommt der zweite Schritt. Wir legen das erstellte Muster, auf jede Stelle buffer[k][l], des zweiten Musters.


http://www.talkortell.de/smiley13.c


Was nachher entscheidend ist, aber das kommt erst noch. Wenn wir zwei Punkte NORD_OST haben, und hinter diesen folgt in NORD_OST, beliebig viele Punkte, dann haben beiden N gespeichert. Wenn man dieses nun auf das Vergleichsbild legt, dann ist das Problem: Das zweite Bild kann zwar breiter sein, aber nicht schmaler. Denn wir speichern, wenn es "weit" nach NORD_OST geht für jeden Punkt in NORD_OST ein n bzw. *. Jetzt auch für die beiden benachbarten Punkte. Es wäre notwendig, alle Punkte, bei denen n steht oder * (Sternchen) zu einem zusammen zu fassen. Denn der erste Punkt nach NORD_OST hat n oder *, der zweite n oder *, der dritte, diese Reihe sollte man zu einem zusammenfassen.


So, funktioniert die Sache auch ohne Speicherzugriffsfehler! Achtung! Wenn MAX_LINE_HEIGHT und MAX_LINE_WIDTH zu groß gewählt sind, dann gibt es wieder einen Speicherzugrifffehler! Das liegt aber eindeutig daran. Macht man sie zu groß gibt es einen, macht man sie kleiner gibt es keinen. 320 jeweils gibt keinen. Das liegt aber daran.


So, im nächsten Schritt, legen wir die beiden Bilder aufeinander drauf. Dafür schreiben wir eine Funktion cmp_pattern. Die eine Möglichkeit besteht jetzt darin, das Muster direkt auf das zweite Bild an zu wenden. Oder wir erstellen ein Muster vom ersten Bild und vom zweiten Bild und vergleichen die beiden entstanden Muster.


Wir sind faul! Wir haben zwei Dateien und beide müssen gelesen werden. Dafür haben wir die Dateizeiger fp und fp1. Jetzt ist das Problem, da beide gelesen werden, müssen wir jetzt nicht nur fp und fp1 verdoppeln, sondern: Wir müssen alles verdoppeln: biWidth, biHeight, ... sind wir verrückt? Nein, wir machen das anders: Wir haben ja nun das Muster erstellt: Wir brauchen in fp nichts mehr zu lesen. Also schließen wir fp von der ersten Datei und öffnen die zweite Datei wieder unter fp mit demselben Daten. Das Muster von der ersten Datei ist ja schon da. Die erste Datei wird geschlossen, wir kopieren alles von dem ersten Quelltext zur Behandlung der ersten Datei und nun haben wir wieder einen Buffer, denselben, aber diesmal gefüllt mit dem Inhalt der zweiten Datei. Wir erstellen jetzt auch nicht großartig ein zweites Muster, sondern wenden das erste Muster von der ersten Datei gleich direkt auf die zweite Datei an. Wir behalten uns aber die Erstellung von zwei Mustern vor. Wir schreiben zwei Funktionen pattern_cmp und patter_cmp2. Die erste wendet das Muster von der ersten Datei direkt auf die zweite Datei an, die zweite Funktion benutzt zwei Muster, die miteinander verglichen werden. Der Vorteil von zwei Mustern ist eventuell die automatische Beseitigung, des unten genannten Problems: Gehen wir nach NORD_OST und folgen hier eine Menge Punkte. Dann ist der Punkt 1 nach NORD_OST, n oder *, der zweite nach NORD_OST, n oder * und so weiter. Was ist wenn dieses Prinzip vorliegt, im zweiten Bild aber verkürzt wird? Wenn man zwei Muster hat, löst sich dieses Problem einfach: Man vergleicht in die eine Richtung und in die andere, aber nicht jedes Muster, erst in die eine und dann in die andere, sondern von jedem Punkt aus, erst in von dem einem zum anderen, dann von dem anderen zum ersteren.


Die Geschichte ist relativ einfach: Die Funktion cmp_pattern ist quasi dasselbe wie make_pattern. Nur: Es werden zwei Bilder verglichen. Der Buffer ist diesmal nicht das Muster. Der Buffer ist von der einen Datei, das Muster von der anderen. Das Ergebnis von davor. Nun machen wir folgendes: Anstatt, dass wir jedes Mal, zuweisen: ... NORTH_EAST = n oder wie auch immer, machen wir hier einen Vergleich. Und wir führen zwei Zähler. Diese drücken im Prinzip das Rauschen aus. Wir führen zwei Zähler. Der eine heißt positive_count, der andere negative_count. Jedes Mal, wenn das Muster übereinstimmt, machen wir positive_count++, ansonsten negative_count++. Dieses drückt eine positive Übereinstimmung ein Rauschen dar, also wo etwas nicht übereinstimmte. Ein Zähler für das Rauschen, mit Übereinstimmung und Nicht-Übereinstimmung.


Und wir führen zwei Zähler. Diese drücken im Prinzip das Rauschen aus. Wir führen zwei Zähler. Der eine heißt positive_count, der andere negative_count. Jedes Mal, wenn das Muster übereinstimmt, machen wir positive_count++, ansonsten negative_count++. Dieses drückt eine positive Übereinstimmung ein Rauschen dar, also wo etwas nicht übereinstimmte. Ein Zähler für das Rauschen, mit Übereinstimmung und Nicht-Übereinstimmung.





http://www.talkortell.de/smiley14temp.c





http://www.talkortell.de/smiley15.c


So, jetzt habe ich diesen Programmquelltext und der stürzt auch nicht ab. Ich habe den Negativen Count und den Positiven Count ausgedruckt, leider noch kein befriedigendes Ergebnis:
positive count: -1460781344, negative count: -1461621024
Bei einem anderem Bild kam:
positive count: -405227584, negative count: -406067264
Aber das kann folgende Ursachen haben: Zum Beispiel, die Zahlen die hier stehen sind ja negativ. Ich habe unsigned verwendet, printf druckt aber mit Vorzeichen aus %i und %u. Außerdem sollte ich als Zähler vielleicht long ausdrucken.
Ich probiere es gleich mal aus:

Da kommt raus:
positive count: 816463776, negative count: 815624096
Vielleicht sollte ich es mit long probieren.
Bei long kommt raus:
positive count: 140721560169952, negative count: 140721559330272
Immer noch kein befriedigendes Ergebnis.

Ah ich weiß, was der Fehler war:
Das ist eindeutig so!!!!
printf("positive count: %li, negative count: %li\n");
Da steht
printf("positive count: %li, negative count: %li\n");
Das kann gar nicht funktionieren, weil die Variablen bei printf sind gar nicht angegeben. Das sind irgendwelche Werte, aber nicht die Werte der Variablen, weil bei printf sind die Variablenwerte nicht angegeben.

Da da da da!
Jetzt kommt was befriedigendes Raus!!! Da, da, da, da... Es war printf (printf konnte gar nichts befriedigendes ausgeben!) Und nun schaut man sich das Ergebnis an:
positive count: 605472, negative count: 0

Das Ergebnis, dies Mal ohne den Schnitzer von printf:
positive count: 605472, negative count: 0

Es konnte nicht gehen!!! Es konnte nicht gehen! Selbst, wenn irgendetwas falsch war, es konnte nicht gehen. Selbst wenn, etwas falsch wäre, es ging nicht: Weil, selbst wenn etwas falsch wäre, und selbst wenn etwas nicht stimmte, das Ergebnis, war alles nur nicht das Ergebnis. Printf hätte selbst bei einem falschen Ergebnis irgendetwas nur nicht das Ergebnis ausgegeben. Denn printf war gar nicht an das Ergebnis gebunden.

Ne, da ist noch ein Fehler drin:
Jetzt spuckt es ständig aus:
positive count: 605472, negative count: 0
Aber, ich habe ein Bild Leicht verändert und das Programm hat das nicht erkannt.

Das Programm mit dem sinnbildlichen Rauschen in Anführungsstrichen ist fertig... (2017-11-01)

http://www.talkortell.de/bmpproject/smileyready.html























http://www.talkortell.de/bmpproject/patternmatching.c
http://www.talkortell.de/bmpproject/patternmatching2.c
http://www.talkortell.de/bmpproject/patternmatching3.c
http://www.talkortell.de/bmpproject/patternmatching4.c
http://www.talkortell.de/bmpproject/patternmatching5.c
http://www.talkortell.de/bmpproject/patternmatching6.c
http://www.talkortell.de/bmpproject/patternmatching7.c
http://www.talkortell.de/bmpproject/patternmatching8.c
http://www.talkortell.de/bmpproject/patternmatching9.c
http://www.talkortell.de/bmpproject/patternmatching10.c
http://www.talkortell.de/bmpproject/patternmatching11.c
http://www.talkortell.de/bmpproject/patternmatching12.c
http://www.talkortell.de/bmpproject/patternmatching13.c
http://www.talkortell.de/bmpproject/patternmatching14.c
http://www.talkortell.de/bmpproject/patternmatching15.c

Jetzt posten wir das ganze auf unserer Website. (Ich auf meiner), aber: Im nächsten Schritt kommt, anhand dieser Farbunterschiede, die allerdings die Richtung von gleichen Farben angeben, und nicht einfach Farbdifferenzwerte an einem Punkt, ein BMP zu erstellen, was das anzeigt.

Und, das Ergebnis ist Klasse, vergleichen wir:
Bild 3 mit Bild 1, erhalten wir:
positive count: 898429, negative count: 0
vergleichen wir, Bild 1 mit Bild 2, erhalten wir:
positive count: 779423, negative count: 0
vergleichen wir, Bild 2 mit Bild 3, erhalten wir:
positive count: 119116, negative count: 0

Bei dem letzten mit dem ersten kommt wieder
positive count: 0, negative count: 0
Aber das soll uns nicht erschrecken! Denn: Wir setzen ja jetzt nicht mehr die Farben gleich und sie können invertiert werden.

./smiley.out this2.bmp this.bmp

Bei dem zweiten Bild, mit dem ersten Bild:
positive count: 781290, negative count: 0

positive count: 0, negative count: 0

./smiley.out this.bmp this.bmp

Bei zwei Mal einem gleichen Bild:

0
--> 30
-> 30
--> 60
-> 60
--> 2
-> 2
--> 4
-> 4
--> 2
-> 2
--> 60
-> 60
--> 30
-> 30
positive count: 0, negative count: 0



Der letzten Quelltext, auf den kommt es an. Hier wurde die Gleichsetzung von Farben außer Acht gelassen. Wenn dem so ist und sie nicht außer acht gelassen wurden, dann funktioniert die Sache nicht. Der letzte Quelltext liefert aber, bei folgenden Bilder folgende Ergebnisse.

Geil, ich veröffentliche schon mal folgenden Quelltext.

Also, jetzt lassen wir mal das Geschwätz. Stattdessen zurück zu dem Programm mit den Smileys. Ich meine eine Lösung gefunden zu haben. Ich habe doch gestern gesagt: Wir schaffen die Methode mit NORD-OST, NORD, ... ab. Stattdessen laufen wir einmal auf der X-Achse, also, WEST-OST die y-Achse ab, also NORD-SÜD. Und einmal auf der y-Achse jeweils die x-Achsen. Was sollen wir da tun? Ganz einfach, wir vergleichen jeweils die Nachbarfelder. Wenn wir jeweils auf jeder y-Achse gen Norden gehen, dann vergleichen wir den westlichen und östlichen Nachbarpunkt, wie weit dieser mit NORD und SÜD der gleichen Farbe unterschiedlich ist. Dabei jeweils den Unterschied von NORDbund SÜD des Nachbarpunkts.
Das macht mich aber, bei mir, das Konzept des Pattern Matching Ansatzes, es gibt entweder 0, 1 oder n/'*' Unterschiede zwischen den Punkten, in Frage zu stellen. Wenn der Nachbarpunkt zum Beispiel einen Unterschied von drei hat, speichern wir einfach drei: Wir speichern drei, für den Unterschied drei, vier für den Unterschied vier, zwei für den Unterschied zwei, 1 für den Unterschied 1, 0 für keinen Unterschied in der Höhe und -1, wenn auf dem Nachbarfeld kein zum Beispiel schwarzer Punkt vor einem Kontrast ist.
Sollten wir das nun wiederum mit dem zweiten Bild vergleichen würde zum Beispiel ein Unterschied von 2 im ersten Bild, mit einem Unterschied von 4 im zweiten Bild, sich durch ein Rauschen ausdrücken. Das heißt, wir speichern nicht mehr allgemein 'n' oder '*', sondern die tatsächlichen Unterschiede, sowohl in dem einen, wie im anderen Bild. Beides tatsächliche Unterschiede. Der Unterschied vom einen Bild zum anderen, wäre dann wiederum ein Rauschen. Nebenbei: So könnte man eine ganze Karte anfertigen, an welchen Stellen im Bild, ein besonders starkes Rauschen ist. Das Rauschen könnte man selber interpretieren, als Mensch, oder noch gewagter, ein drittes Bild daraus erstellen, in dem man dieses Rauschen, als Pixel darstellt.
Umgekehrt können wir unter diesem Umstand auch zur alten Methoden zurückkehren. Wir benutzen wieder NORD-WEST, NORD, ..., WEST und gehen bei jedem Pixel in jede Richtung in einer Schleife, ein Mal nach NORD-WEST, solange dieselbe Farbe ist, wie in dem Pixel, ein Mal nach NORD, usw. Jetzt speichern wir den Wert dieser Differenz. Da wir ja nun das Rauschen eingeführt haben, brauchen wir blos die Differenzen von dem einen Bild mit denen des anderen Bild zu vergleichen. Die Unterschiede drücken sich im Rauschen aus. Hier gibt es zunächst Mal, das Rauschen, das lokal für jeden Pixel ist und das Rauschen, was sich auf das ganze Bild bezieht.

Eine andere Möglichkeit wäre doch: Wir hatten bisher: NORD-WEST, NORD, NORD-OST, OST, SÜD-OST, SÜD, SÜD-WEST, WEST. Wir sind jede Richtung für jeden Pixel durchgegangen und haben geprüft wieviele danach kommen. Das sind entweder, keiner, 1er, oder n, '*'. Das Problem liegt auf der Hand. Am Ende ist es immer einer, am Ende einer Kette, von schwarzen Punkten, das zweite ist, was ist n? Wenn wir 3 Punkte übereinander haben, in y-Richtung, ist das Problem: Jetzt könnte aus einem Grinsen ein Trauriges Gesicht sein. Weil die Mittellinie vom Mund beim Grinsen besteht immer aus mehren übergelagerten Punkten in y-Richtung. Nun könnte das beim Grinsen falsch als Traurigkeit interpretiert werden, weil hier auch mehrere Punkte in y-Richtung übereinander liegen. Ob das wirklich nicht funktioniert, weiß ich nicht. Eventuell ist im Programm ein anderer Fehler. Ich habe nämlich ein gelbes mit einem schwarzen verglichen und es zeigt sich noch immer nichts. Darüber kann ich aber nichts sagen.
Eine andere Möglichkeit wäre es, zwei Benachbarte Punkte, die in X-Richtung benachbart sind, in Y-Richtung zu vergleichen. Wenn zum Beispiel in X-Richtung zwei Punkte nebeneinander liegen, dann könnte man ja vergleichen, wie groß die Differenz von den darüber liegenden Punkten in Y-Richtung ist. Wenn zum Beispiel zwei Punkte so nebeneinander liegen:
**
Dann liegen vielleicht Punkte darüber:

*
*
*
**

Hier liegen drei Punkte in positiver Y-Richtung über den ersten versetzt zum zweiten in X-Richtung.
Die eine Möglichkeit wäre nun, für jeden Punkt die Differenz zu vergleichen in alle Richtungen: NORD-WEST, NORD, NORD-OST, OST, SÜD-OST, SÜD, SÜD-WEST, WEST.
Das ist aber in sofern nicht nötig: Vor allem, was ist NORD-WEST. Wir müssten alle Punkte nach NORD-WEST durchgehen und gucken, wie es sich zum Nachbarpunkt in NORD-WEST bezüglich NORD-OST verhält.
Wir können es aber auch anders machen: Zunächst Mal, tun wir einfach so, als vergessen wir NORD-WEST, NORD-OST, SÜD-OST, SÜD-WEST, sondern haben nur NORD, OST, SÜD, WEST. Und zwar die X-Achse und die Y-Achse. Müssen wir nun zu jedem einzelnen Punkt gehen? Nein müssen wir nicht. Wir gehen einfach beim Array in der X-Achse jeden Punkt durch "a[y-Achse][x-Achse]" und vergleichen wie sie sich positiver und negativer Y-Richtung unterscheiden. Die Differenz vom vorherigen zum nächsten. Dasselbe machen wir in Y-Richtung, indem wir jeweils Y inkrementieren.

Ich habe den Fehler entdeckt, ein schwerwiegender Denkfehler, der mich umgetrieben hat. Der Denkfehler, war, dass es keiner war. Ich hatte davon berichtet, dass ich im Code vergessen hatte, nach dem Lesen der Head-Infos der BMP's die Informationen auch zu schreiben. Aber da gibt es nichts zu schreiben, beide Dateien werden lediglich gelesen.
Dieser Gedanke trieb mich um und ich begab mich in eine Pause.
Halten wir noch mal fest, worum ging es:
Wie sie auf meiner Website feststellen können, geht es um das sinnbildliche Rauschen. Wir haben das analoge Rauschen und das Digitale Rauschen, bei den Smileys führen wir das sinnbildliche Rauschen ein.
Das war aber alles etwas überfrachtet auf Facebook, so hat das da nichts zu suchen.
Deswegen: Ich habe alles genauso wie auf Facebook auf meiner Website. Keine Sorge, die Chronik stimmt überein, wer das genau nachlesen will, kann das auf meiner Website tun.
Sie kriegen aber noch eine gute Fassung meines Projekts. Auch auf Facebook - sowohl auf Facebook, als auch auf meiner Website, beides. Das ist dann aber eine gute Fassung.
Des weiteren geht es darum: Ja, das ist das Thema: Wir kennen das Programm motion, das unter anderem ein digitales Rauschen feststellt und das Motto lautet: motion bekommt einen großen Bruder, das sinnbildliche Rauschen.
Ich habe schon einen Rauschwert eingeführt. Wir müssen bedenken, wir suchen wie beim Pattern Matching danach, nicht eine festgelegte Reihenfolge zu suchen, sondern eine Art Muster. Dieses Muster wird von uns bei regulären Ausdrücken so eingeben: *(AB) oder zum Beispiel *(A|B). Das heißt, beim ersteren hätten wir AB, ABAB, ABABAB, ... beim zweiteren A, AA, AAA, ..., B, BB, BBB, ..., AB, ...
Diese Eingabe eines Musters können wir uns ersparen. Denn wir gewinnen das Muster gleich aus dem Bild, ein BMP, was wir ausgelesen haben. Wir brauchen keine regulären Ausdrücke, wir wissen, im Computer wird der reguläre Ausdruck so oder so nicht als regulärer Ausdruck gespeichert. In Robert Sedgewicks Buch "Algorithmen in C" wird der Compiler ja genau mit dem Thema reguläre Ausdrücke eingeführt, genauso wie mit arithmetischen Ausdrücken. Wir müssen aber bedenken, wenn wir arithmetische Ausdrücke wie (A+B)*C eingeben oder reguläre Ausdrücke, wie *(A|B) funktioniert jedes Mal das Prinzip des Compilers bei der Eingabe des Ausdrucks. Hier arbeiten wir aber nicht mit Ausdrücken die eingeben werden, sondern die Informationen stammen gleich aus dem Bild, das mit dem anderen verglichen wird. Wir brauchen als keinen Compiler.
Umgekehrt habe ich auf meiner Website ein Programm geschrieben, was es ermöglicht, quasi graphisch, Sterne, Kreise und Quadrate addiert. Dies ist natürlich über einen Ausdruck möglich an zu geben. Man denke daran, ebenso wie wir speziell für Arithmetische oder Reguläre Ausdrücke Operationen definiert haben, haben wir das für Boole'sche Operationen. Uns hindert nichts daran, das für Graphiken zu tun. Wie wir die Operationen definieren, ist unser Problem. Ich habe jetzt kein Graphisches Frontprogrammiert, was absolut toll wäre. Aber es erfüllt seinen Zweck. Man könnten sich vorstellen, eine Multiplikation mit einem bereits entstanden Bild von einem Stern, heißt, man bringt in jeder Ecke des Sterns das Bild unter. Oder in allen Ecken, des zweiten Bildes. Addition bedeutet, man malt sie einfach nebeneinander. Allerdings, unabhängig wie gut unser graphisches Frontend ist, wir können es auch so definieren: Bei der Multiplikation malen wir das Bild entsprechend der existierenden Kanten so und so oft, vor und hinter, das erste Bild, beim der Addition, malen wir das Bild unabhängig der Kanten, einfach nebeneinander.
Was würde würde uns das in der Praxis nützen? Nutzt das etwas?
Ich würde sagen, ja, jetzt schauen wir uns einen Intel-Prozessor an.
Sagen wir ganz knapp, entwickeln eine neue Programmiersprache mit eigenem graphischen Frontend.
Sagen wir mal ganz verkürzt, nachher führen wir es ein wie in C, dass wir Variablen von einer bestimmten Länge definieren können. Sagen wir {a,b,c,..., z} das sind Bits
{A, B, C, ..., Z} das sind Bytes oder Worte, oder Doppelworte, oder Quadwörter.
Jetzt könnten wir, wenn die Operationen AND und OR schon definiert sind, Variablenzuweisungen wie A=B&C definieren.
In unserem Graphischen Frontend, wird & durch ein entsprechendes Gatter ersetzt. Dies würde den Schaltplan ergeben, der könnte später in ein Platinenlayout übersetzt werden.
Wir können aber nicht nur neue Variablen definieren, sondern neue Operationen: Op1 = (xy & xz)|(ab)
Das wäre dann Op1. So können wir + und - (also ADD und SUB) in der Bibliothek finden, oder es direkt neu Programmieren. Die Variablen {A, B, C, ..., Z} sind einfach Register.
So könnten wir auch Arrays definieren, die einen Arbeitsspeicher darstellen.
Natürlich gibt es auch IF's. So könnte man den Befehl so deuten: Wenn im Befehlsregister (Inhalt, nicht Instruction Pointer, Befehlszähler, ...) irgendein Byte mit irgendeiner Zahl steht, wäre das als ADD zu interpretieren. Der Befehlszähler selber wäre eine Variable, die nach oben gezählt wird, aber das würde normal behandelt, und die in ein Array, einen Arbeitsspeicher zeigt.


Zunächst zu dem Programm mit den Smileys: Es liefert einen positiven Rauschwert und einen negativen. Bisher hatte ich Glück, es hat immer einen großen positiven Rauschwert ausgegeben (also das Gegenteil von Rauschen) und einen Negativwert von 0. Das ist auf jeden Fall positiv. Egal, zurück zum Programm, da scheint ein massiver Fehler im Ansatz drin zu sein: Denn: Wir haben so zu sagen 'n' oder '*' gesetzt, wenn sich eine Folge von schwarzen Farbpixeln wiederholt. Das könnte ja unter anderem für eine Richtung bedeuten: Wenn jetzt ein Smiley eine Wiederholung hat, obwohl diese nicht nach unten geht, weil er nicht traurig ist, wird diese aber auf diese Art und Weise interpretiert. Ebenso finden wir ja an der Äußeren Grenze keinen Wert 'n' oder '*'. Das würde ich aber nicht so schnell so interpretieren. Denn in der Praxis ist das noch mal etwas anderes: Denn wir müssen bedenken wir sind im zwei-demensionalen Raum, außerdem haben wir benachbarten Pixel und was das ganze dann bedeutet und ob das durch ein paar kleine Schritte schnell behoben ist, ist eine andere Frage. Des weiteren ist es ja so: Wir haben das Grundgerüst, das Grundprogramm, der Rest, an dem kann man weiter viel erfinden. Da findet sich bestimmt etwas. Positiv ist es, dass kein Rauschen festgestellt wurde, sowohl beim negativen Wert, als auch beim Positiven, das heißt, der eine ist 0, der andere nicht.






















http://www.talkortell.de/bmpproject/patternmatching.c
http://www.talkortell.de/bmpproject/patternmatching2.c
http://www.talkortell.de/bmpproject/patternmatching3.c
http://www.talkortell.de/bmpproject/patternmatching4.c
http://www.talkortell.de/bmpproject/patternmatching5.c
http://www.talkortell.de/bmpproject/patternmatching6.c
http://www.talkortell.de/bmpproject/patternmatching7.c
http://www.talkortell.de/bmpproject/patternmatching8.c
http://www.talkortell.de/bmpproject/patternmatching9.c
http://www.talkortell.de/bmpproject/patternmatching10.c
http://www.talkortell.de/bmpproject/patternmatching11.c
http://www.talkortell.de/bmpproject/patternmatching12.c
http://www.talkortell.de/bmpproject/patternmatching13.c
http://www.talkortell.de/bmpproject/patternmatching14.c


So, nun habe ich ein zweites Programm geschrieben, was die Differenzen pro Pixel, was ihren "Vektor" betrifft angibt.
http://www.talkortell.de/bmpproject/patternmatching15.c



Hier jetzt, wenn man nur eine Komponente addiert.

In diesem Falle wurden nach NORD-OST beide Bilder auf nur einer Seite (NORD-OST) hin verglichen.


Hier wurden zwei nach Osten verglichen.

Und hier wurden wieder zwei nach Osten verglichen.

Hier das ganze noch mal, zwei verglichen, aber mit einem anderen Faktor.

Hier das ganze noch Mal, mit einem anderen Faktor, wie gerade eben.

Und hier nach Süden, mit einem verstärkenden Faktor.

Hier das ganze noch mal nach Süden.




Wir programmieren komische Schachfelder


























Wir malen einen Kreis und ein Posthorn







Jetzt mache ich Hexagone.













Wichtig bei Hexagonen ist folgendes:
Die Formel leuchtet uns allen ein (sicher auch der Rest): Aber: Die Hypothenuse gibt auch im schrägen Falle, die Breite an. Die Hypothenuse ist an allen Ecken gleich lang. Die Höhe des Rechtecks, in das die Schräge eingeschrieben wird, ist die Länge aller Ecken. Diese Höhe berechnet sich über den Cosinus, denn sie ist die Ankathete. Also hat die Höhe des Vierecks in die, die Schräge eingeschrieben wird, die Höhe des entsprechenden Cosinus bei 30°.
Aber Vorsicht, es genügt nicht diese Höhe als Grenze in der Schleife an zu geben. Natürlich zählen wir y nach oben, das diese Höhe angibt: y++. Aber machen wir gleichzeitig x++? Bis wir die Grenze erreicht haben? Nein, wir machen nicht x++. Denn machen wir im selben Atemzug x++, wenn wir y++ machen, erreichen wir einen 45° Winkel.
Um einen Winkel von 30° zwischen Höhe und Breite zu erreichen, müssen wir den tan von 30° anwenden. Aber Vorsicht! Wenn wir jedes Mal y erhöhen, um 1 und dabei einen tan von 30° auf jeden "1-er" Schritt auf y anwenden, erreichen wir nichts. Denn der tan von 30° ist eine Zahl zwischen 0.5 und 1. Bei den Schritten von x und y arbeiten wir aber mit Ganzzahlschritten. Und wenn wir den Einzelschritt, auf den wir tan anwenden aufrunden, erreichen wir "1". Wir können aber den Tan immer dann, anwenden, wenn y, 2, 3, 4, ..., 10, ... Schritte gegangen ist. Der Tan von so einer größeren Zahl sieht schon besser aus. Wir können dies über den % (Modulo) erreichen. Die Schrittgröße von 2 ist zwar in der einen Richtung Feinkörniger, allerdings ist hier auch wiederum der Nachteil, dass die Rundung von float zu Ganzzahl kein gutes Ergebnis bringt. Deswegen nicht 2 wählen, sondern eine größere Schrittzahl. 4 scheint gut zu sein.

So, meine Damen und Herren, jetzt gibt es GIF

http://www.talkortell.de/bmpproject/gif.html

Vorsatz

Realisierung

LZW-Algorithmus

Ich habe jetzt eine funktionierende Version des LZW-Algorithmus implementiert.

Ich beziehe mich dabei auf folgendes Skript:

ai.toastbrot.ch/lzw.pdf


Meine Ausgabe lautet dabei (beim letzten Code):

AUSGABE: A 1
AUSGABE: B 2
AUSGABE: B 2
AUSGABE: AB 4
AUSGABE: ABA 7
AUSGABE: C 3


Fortschreiten zu den GIF's

Was die GIF's betrifft beziehe ich mich auf:

http://www.kaudel.de/projekte/GIFundPNG.pdf


Ich werde das jetzt gleich implementieren.

Hier eine Menge nicht funktionierende Codes und ihre erzeugten Bilder: Und die nicht-funktionierenden Bilder: So weit ist es mit den GIF's bis heute gediehen. Zunächst habe ich das Beispiel von Kaudel mittels Programm Quelltext zum Laufen gebracht. Dann war ja vorher der Quelltext mit LZW. Diese beiden Sachen habe ich auch schon vermengt. Allerdings scheint's jetzt mit LZW im Original noch nicht zu laufen. Vielleicht auch wegen der Farbtiefe.

Und es funktioniert, ...

http://giflib.sourceforge.net/whatsinagif/lzw_image_data.html


Juhuu, es funktioniert!! Ich habe ein Programm geschrieben, dass einen funktionierenden Byte-Stream für ein GIF-Bild erstellt. Ich möchte auf den letzten Beitrag hinweisen. Hier stehen essentiell wichtige Informationen zum Bytestream. Was nämlich bisher ungesagt war, blieb: Es gibt ein EOI_CODE, einen CLEAR_CODE und es wird die Anzahl der Bit angegeben, mit denen, nicht das Bild Kodiert ist, aber wie groß die Elemente, die im durch LZW Kodierte Bytestream vorkommen, sind. Also (höchster Wert 64, 128, 256, ..., 4, 8, 16, 32, ...). Ich verwende 1 Byte pro Element. Als Anzahl von Farben verwende ich 64. Das hat den Vorteil. Beim LZW Algorithmus verwende ich ja eine Tabelle, die zunächst für jedes einzelne Zeichen einen Eintrag enthält. Bei 64 Zeichen ist diese 64 breit. Wenn ich nun ein Byte im Code verwenden will habe ich immer noch 256-64-3 Zeichen (3 für CLEAR_CODE, EOI_CODE, 0x00). Deshalb verwende ich 64, damit ich danach weiterhin 1 Byte im Code schreiben kann. Den Code zum funktionierenden GIF und dem C-Programm poste ich im nächsten Beitrag. Das Bild ist eigentlich das, was ich erwarte, mal abgesehen von einem merkwürdigen Rand. Der Rand soll uns jetzt mal gar nicht stören. Stattdessen bedenke man: Ich habe ein schwarzes Bild erstellt, das ist schwarz (bzw. Eintönig). Dem aber nicht genug. Ich kann alle erzeugten GIF's also alle durch das C-Programm erzeugten GIF's öffnen. Das ging vorher nicht. Die Versionen von den vorherigen C-Programmen ließen das nicht zu. Also: Es tut!