PDA

Visualizza la versione completa : [C++] Bitmap e convert


RooccoXXI
18-12-2010, 00:51
Ciao a tutti.
Piano piano mi sto avvicinando alla struttura dei file immagine perché mi piacerebbe capire come sono fatti e come poter disegnare in C++ (anche solamente pixel by pixel). Prima di utilizzare librerie varie preferisco sempre sbattere la testa contro il muro, provando a fare le cose manualmente e partendo da zero; prima di utilizzare la STL ho implementato una lista concatenata e un albero binario di ricerca. Questo per capire a fondo come funzionano le cose, invece di utilizzare librerie senza conoscerne le fondamenta. Mi giudicate pazzo? Sono fatto così.

Comunque ho provato a vedere come è fatta la seguente immagine in .png (quella di Wikipedia, raffigurante tre dadi semitrasparenti, su uno sfondo trasparente!).
http://en.wikipedia.org/wiki/File:PNG_transparency_demonstration_1.png

Il risultato, ottenuto con il comando convert[\B] via terminale (su una versione rimpicciolita a 100x75 pixel), è il seguente file di testo:


# ImageMagick pixel enumeration: 100,75,255,rgba
0,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
1,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
2,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
3,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
4,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
5,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
6,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
7,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
8,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
9,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
10,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
11,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
12,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
13,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
14,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
15,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
16,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
17,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
18,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
19,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
20,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
21,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
22,0: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
[...]
64,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
65,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
66,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
67,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
68,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
69,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
70,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
71,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
72,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
73,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
74,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
75,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
76,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
77,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
78,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
79,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
80,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
81,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
82,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
83,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
84,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
85,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
86,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
87,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
88,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
89,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
90,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
91,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
92,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
93,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
94,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
95,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
96,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
97,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
98,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)
99,74: (255,255,255, 0) #FFFFFF00 rgba(255,255,255,0)


Utilizzando il comando

convert nomefile.txt nomefile.png
su questo file di testo riottengo l'immagine originale.

Dai commenti si capisce che i primi due numeri sono le coordinate di un pixel (partendo in alto a sinistra mi sembra) e gli altri sono i colori (RGBA).

Ho poi allora creato un piccolo programmino in C++, che mi crei un file di testo con la medesima struttura, semplicemente colorando ogni singolo pixel o di bianco o di nero (in maniera casuale).


#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::ios;

#include <fstream>
using std::ofstream;

#include <ctime>
using std::time;

#include <cstdlib>
using std::exit;
using std::rand;
using std::srand;

int main()
{
srand(time(0));

ofstream outPNGFile("casualImage.txt", ios::out);

if (!outPNGFile)
{
cerr << "File could not opened." << endl;
exit(1);
}

int color;
int alpha = 0;
for (int i = 0; i <= 100; i++)
{
for (int j = 0; j <= 100; j++)
{
color = (rand() % 2) * 255;

outPNGFile << j << ", " << i << ": (" << color << ", " << color << ", " << color << ", " << alpha << ")" << endl;
}
}

return 0;
}

Il file ottenuto è il seguente:


0, 0: (0, 0, 0, 0)
1, 0: (0, 0, 0, 0)
2, 0: (0, 0, 0, 0)
3, 0: (0, 0, 0, 0)
4, 0: (255, 255, 255, 0)
5, 0: (0, 0, 0, 0)
6, 0: (0, 0, 0, 0)
7, 0: (255, 255, 255, 0)
8, 0: (255, 255, 255, 0)
9, 0: (255, 255, 255, 0)
10, 0: (255, 255, 255, 0)
11, 0: (0, 0, 0, 0)
12, 0: (255, 255, 255, 0)
13, 0: (0, 0, 0, 0)
14, 0: (255, 255, 255, 0)
15, 0: (0, 0, 0, 0)
16, 0: (255, 255, 255, 0)
17, 0: (0, 0, 0, 0)
18, 0: (0, 0, 0, 0)
19, 0: (255, 255, 255, 0)
20, 0: (255, 255, 255, 0)
21, 0: (255, 255, 255, 0)
22, 0: (0, 0, 0, 0)
23, 0: (255, 255, 255, 0)
24, 0: (0, 0, 0, 0)
25, 0: (255, 255, 255, 0)
26, 0: (0, 0, 0, 0)
27, 0: (255, 255, 255, 0)
28, 0: (0, 0, 0, 0)
29, 0: (255, 255, 255, 0)
30, 0: (255, 255, 255, 0)
31, 0: (255, 255, 255, 0)
32, 0: (0, 0, 0, 0)
33, 0: (255, 255, 255, 0)
34, 0: (0, 0, 0, 0)
35, 0: (255, 255, 255, 0)
36, 0: (255, 255, 255, 0)
37, 0: (255, 255, 255, 0)
38, 0: (255, 255, 255, 0)
39, 0: (0, 0, 0, 0)
40, 0: (255, 255, 255, 0)
41, 0: (0, 0, 0, 0)
42, 0: (255, 255, 255, 0)
43, 0: (255, 255, 255, 0)
44, 0: (0, 0, 0, 0)
45, 0: (0, 0, 0, 0)
46, 0: (0, 0, 0, 0)
47, 0: (0, 0, 0, 0)
48, 0: (0, 0, 0, 0)
49, 0: (0, 0, 0, 0)
[...]
71, 99: (255, 255, 255, 0)
72, 99: (0, 0, 0, 0)
73, 99: (255, 255, 255, 0)
74, 99: (255, 255, 255, 0)
75, 99: (0, 0, 0, 0)
76, 99: (0, 0, 0, 0)
77, 99: (0, 0, 0, 0)
78, 99: (0, 0, 0, 0)
79, 99: (255, 255, 255, 0)
80, 99: (0, 0, 0, 0)
81, 99: (0, 0, 0, 0)
82, 99: (255, 255, 255, 0)
83, 99: (255, 255, 255, 0)
84, 99: (0, 0, 0, 0)
85, 99: (0, 0, 0, 0)
86, 99: (255, 255, 255, 0)
87, 99: (0, 0, 0, 0)
88, 99: (0, 0, 0, 0)
89, 99: (255, 255, 255, 0)
90, 99: (255, 255, 255, 0)
91, 99: (0, 0, 0, 0)
92, 99: (0, 0, 0, 0)
93, 99: (255, 255, 255, 0)
94, 99: (0, 0, 0, 0)
95, 99: (255, 255, 255, 0)
96, 99: (0, 0, 0, 0)
97, 99: (255, 255, 255, 0)
98, 99: (255, 255, 255, 0)
99, 99: (255, 255, 255, 0)
100, 99: (0, 0, 0, 0)
0, 100: (255, 255, 255, 0)
1, 100: (0, 0, 0, 0)
2, 100: (255, 255, 255, 0)
3, 100: (255, 255, 255, 0)
4, 100: (0, 0, 0, 0)
5, 100: (0, 0, 0, 0)
6, 100: (255, 255, 255, 0)
7, 100: (255, 255, 255, 0)
8, 100: (0, 0, 0, 0)
9, 100: (0, 0, 0, 0)
10, 100: (0, 0, 0, 0)
11, 100: (255, 255, 255, 0)
12, 100: (0, 0, 0, 0)
13, 100: (255, 255, 255, 0)
14, 100: (255, 255, 255, 0)
15, 100: (255, 255, 255, 0)
16, 100: (255, 255, 255, 0)
17, 100: (255, 255, 255, 0)
18, 100: (0, 0, 0, 0)
19, 100: (0, 0, 0, 0)
20, 100: (0, 0, 0, 0)
21, 100: (0, 0, 0, 0)
22, 100: (255, 255, 255, 0)
23, 100: (255, 255, 255, 0)
24, 100: (255, 255, 255, 0)
25, 100: (0, 0, 0, 0)
26, 100: (255, 255, 255, 0)
27, 100: (0, 0, 0, 0)
28, 100: (255, 255, 255, 0)
29, 100: (0, 0, 0, 0)
30, 100: (255, 255, 255, 0)
31, 100: (0, 0, 0, 0)
32, 100: (0, 0, 0, 0)
33, 100: (255, 255, 255, 0)
34, 100: (255, 255, 255, 0)
35, 100: (0, 0, 0, 0)
36, 100: (255, 255, 255, 0)
37, 100: (255, 255, 255, 0)
38, 100: (0, 0, 0, 0)
39, 100: (255, 255, 255, 0)
40, 100: (255, 255, 255, 0)
41, 100: (255, 255, 255, 0)
42, 100: (255, 255, 255, 0)
43, 100: (255, 255, 255, 0)
44, 100: (255, 255, 255, 0)
45, 100: (255, 255, 255, 0)
46, 100: (0, 0, 0, 0)
47, 100: (255, 255, 255, 0)
48, 100: (255, 255, 255, 0)
49, 100: (0, 0, 0, 0)
50, 100: (255, 255, 255, 0)
51, 100: (255, 255, 255, 0)
52, 100: (255, 255, 255, 0)
53, 100: (0, 0, 0, 0)
54, 100: (255, 255, 255, 0)
55, 100: (0, 0, 0, 0)
56, 100: (255, 255, 255, 0)
57, 100: (0, 0, 0, 0)
58, 100: (255, 255, 255, 0)
59, 100: (0, 0, 0, 0)
60, 100: (255, 255, 255, 0)
61, 100: (0, 0, 0, 0)
62, 100: (0, 0, 0, 0)
63, 100: (0, 0, 0, 0)
64, 100: (255, 255, 255, 0)
65, 100: (0, 0, 0, 0)
66, 100: (0, 0, 0, 0)
67, 100: (0, 0, 0, 0)
68, 100: (255, 255, 255, 0)
69, 100: (255, 255, 255, 0)
70, 100: (0, 0, 0, 0)
71, 100: (0, 0, 0, 0)
72, 100: (0, 0, 0, 0)
73, 100: (0, 0, 0, 0)
74, 100: (0, 0, 0, 0)
75, 100: (255, 255, 255, 0)
76, 100: (255, 255, 255, 0)
77, 100: (255, 255, 255, 0)
78, 100: (0, 0, 0, 0)
79, 100: (0, 0, 0, 0)
80, 100: (0, 0, 0, 0)
81, 100: (0, 0, 0, 0)
82, 100: (0, 0, 0, 0)
83, 100: (0, 0, 0, 0)
84, 100: (0, 0, 0, 0)
85, 100: (0, 0, 0, 0)
86, 100: (0, 0, 0, 0)
87, 100: (255, 255, 255, 0)
88, 100: (255, 255, 255, 0)
89, 100: (255, 255, 255, 0)
90, 100: (0, 0, 0, 0)
91, 100: (255, 255, 255, 0)
92, 100: (0, 0, 0, 0)
93, 100: (255, 255, 255, 0)
94, 100: (255, 255, 255, 0)
95, 100: (255, 255, 255, 0)
96, 100: (0, 0, 0, 0)
97, 100: (255, 255, 255, 0)
98, 100: (255, 255, 255, 0)
99, 100: (0, 0, 0, 0)
100, 100: (255, 255, 255, 0)


Purtroppo utilizzando di nuovo il comando
convert per convertire il mio file di testo in un immagine .png viene visualizzato il seguente messaggio d'errore:

convert: delegate library support not built-in `(null)' (Freetype) @ annotate.c/RenderFreetype/1417.


Che significa? Cosa c'è che non va? Come mai il mio file non viene compilato mentre l'altro si? Cosa manca nel mio file? Il problema potrebbe essere nel comando [B]convert?

Grazie a tutti per eventuali risposte.
Rocco.

GliderKite
18-12-2010, 10:49
:malol:

Allora, dici che vuoi partire da zero giusto per poter disegnare un immagine anche solo pixel per pixel ? Dovresti chiederti quindi come si fa. Il trucco sta nel chiedersi: qual'è la differenza tra un immagine bmp, o png, o gif o ancora jpg, etc... Be, essenzialmente la differenza sta nel formato.

Non conosco il comando convert, ma tu stesso hai detto di voler realizzare un programma in C++ che ti permetta di ricreare un immagine, ed utilizzare un comando da terminale (tra l'altro non ho capito che sistema operativo utilizzi) non è proprio roba da sbatterci la testa.

Vuoi un consiglio? Scegliti un formato (possibilmente non troppo complicato per iniziare e possibilmente dovresti essere in grado di riuscire a trovare un bel po' di informazioni su questo: internet, libri, fai te...) e, in base a questo, trova una soluzione per implementare un programmino che scriva un file seguendo le regole di quel formato per generare l'immagine che desideri. Oltretutto evita di andare a scrivere a caso pixel per pixel, sarebbe una grande perdita di tempo e non ne otterresti niente. In sostanza se non hai qualcosa da disegnare soffermati sul formato.

Spero di essere stato chiaro :ciauz:

MItaly
18-12-2010, 11:02
Scrivere un file immagine in formato "testuale" per poi farlo convertire da ImageMagick non ha gran senso... a quel punto tanto vale usare una libreria per la gestione delle immagini (ad esempio FreeImage con i binding per C++) e usare quella per scrivere i file in questione. In alternativa, se vuoi partire "dalla gavetta", dovresti scegliere un formato di immagine facile (bmp o pnm, ad esempio, e in generale non formati compressi che sono un casino) e provare a lavorare con esso, magari scrivere una classe che consente di scrivere i singoli pixel, scrivere il tutto su file e così via.

RooccoXXI
18-12-2010, 13:14
Ho capito le vostre perplessità.
Però il mio obbiettivo è arrivare a disegnare dei frattali in C++. E per questo basterebbe manipolare un'immagine pixel per pixel (es: nell'insieme di Mandelbrot basta colorare di nero i pixel che rappresentano i punti della successione che non divergono!).

Anche in questo caso secondo voi non avrebbe senso creare un'immagine in formato testuale e poi convertirla con il comando convert? (Utilizzo Mac OS X 10.6).

Pensavo di concentrarmi sul formato .png, perché mi sembra uno dei migliori? Voi che ne pensate?
La mia idea era quella appunto di creare una classe che mi permetta di manipolare pixel per pixel un'immagine .png (rappresentata da una tabella di vector) per poi salvarla in un file testuale. Per il processo di conversione pensavo appunto di utilizzare convert. Però se voi mi dite che ricreare una versione semplificata del comando convert è qualcosa di abbordabile anche per chi ha studiato da autodidatta (sul manuale della Deitel, C++ - How to program) mi metto subito al lavoro! =P.

Comunque potete consigliarmi qualche libro o qualche sito dove si affrontano discorsi relativi a C++ e immagini/grafica? (Non libri su OpenGL o simili però!xD).

MItaly
18-12-2010, 13:52
Originariamente inviato da RooccoXXI
Ho capito le vostre perplessità.
Però il mio obbiettivo è arrivare a disegnare dei frattali in C++. E per questo basterebbe manipolare un'immagine pixel per pixel (es: nell'insieme di Mandelbrot basta colorare di nero i pixel che rappresentano i punti della successione che non divergono!).
E proprio per questo ti conviene lavorare su formati come DIB o PNM (i vari PNM sono i più semplici in assoluto).


Anche in questo caso secondo voi non avrebbe senso creare un'immagine in formato testuale e poi convertirla con il comando convert? (Utilizzo Mac OS X 10.6).
Secondo me non ha senso perché è una menata da gestire in memoria, mentre con i formati che ti ho detto dai in output già un formato "vero" (e binario), anche se non compresso, e passare dalla rappresentazione in memoria a quella su file è rapidissimo.


Pensavo di concentrarmi sul formato .png, perché mi sembra uno dei migliori? Voi che ne pensate?
La mia idea era quella appunto di creare una classe che mi permetta di manipolare pixel per pixel un'immagine .png (rappresentata da una tabella di vector) per poi salvarla in un file testuale.
Resto dell'idea che non è una buona idea. Usa in memoria la normale rappresentazione binaria DIB o PNM (che altro non è che un semplice vettore di pixel) e poi scrivila su file invece di passare per un formato testuale non riconosciuto da altri programmi.

Però se voi mi dite che ricreare una versione semplificata del comando convert è qualcosa di abbordabile anche per chi ha studiato da autodidatta (sul manuale della Deitel, C++ - How to program) mi metto subito al lavoro! =P.
Piuttosto usa una libreria come la già citata FreeImage.

RooccoXXI
18-12-2010, 14:06
E proprio per questo ti conviene lavorare su formati come DIB o PNM (i vari PNM sono i più semplici in assoluto).


I formati che hai indicato ho già provato ad utilizzarli: sono semplici, comodi e funzionano bene.

Il seguente programma in C++ crea un immagine .ppm con pixel bianchi o neri colorati in maniera casuale:

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::ios;

#include <fstream>
using std::ofstream;

#include <ctime>
using std::time;

#include <cstdlib>
using std::exit;
using std::rand;
using std::srand;

int main()
{
srand(time(0));

ofstream outPPMFile("casualImage.ppm", ios::out);

if (!outPPMFile)
{
cerr << "File could not opened." << endl;
exit(1);
}


outPPMFile << "P1" << endl;
outPPMFile << "100 100" << endl;
int color;
for (int i = 0; i <= 100; i++)
{
for (int j = 0; j <= 100; j++)
{
color = rand() % 2;

outPPMFile << color << " ";
}

cout << endl;
}

return 0;
}

Quello che mi da un po' fastido è però che posso leggerli sono tramite Gimp (cioè tramite programmi di computer grafica). Antemprima (Mac OS X) non riesce a leggere questi formati ed è per questo che mi piacerebbe riuscire a creare file .png.

GliderKite
18-12-2010, 14:12
Vuoi creare frattali tramite un programma scritto in C++?

Usa Windows:
Fracty - The Fractal Generator (http://fracty.altervista.org/) :D


Come vedi ho già avuto esperienza sul campo, fidati quando ti dico che la base è conoscere perfettamente il formato su cui vuoi lavorare, poi viene il resto. Una volta che deciderai quale formato utilizzare (ti ripeto parti con uno semplice) potremmo tranquillamente discuterne.

E quoto MItaly...

MItaly
18-12-2010, 14:14
Originariamente inviato da RooccoXXI
I formati che hai indicato ho già provato ad utilizzarli: sono semplici, comodi e funzionano bene.

Provato con i BMP? Sono sicuro che l'anteprima di Mac OS te lo legge... E poi ti fai un po' le ossa su un formato completamente binario e dotato di qualche stranezza (una per tutte: le righe sono indicizzate al contrario :ecco: ).
Se poi vuoi generare formati più complessi, come già detto, ti consiglio di affidarti a FreeImage.

RooccoXXI
18-12-2010, 14:35
Vuoi creare frattali tramite un programma scritto in C++?


Quello che mi piacerebbe fare non è creare frattali tramite un programma scritto in C++, ma scrivere un programma in C++ che crei dei frattali. Partendo da quelli semplici semplici (triangolo di Sierpinski) per passare a quelli un po' più complessi (quelli turtle, tipo il fiocco di Koch) per arrivare a quelli complessi (Mandelbrot).

È chiaro che bisogna conoscere a fondo il formato. Ma è per questo che sto scrivendo sul forum. Non avendo mai lavorato con immagini e avendo solo trasformato qualche immagine in testo per vedere come veniva descritta non so proprio niente. E per questo mi interessava conoscere le opinioni di qualcuno che ne sa molto di più e che può darmi consigli, come voi!

GliderKite
18-12-2010, 14:45
Personalmente ti propongo il formato BMP, piuttosto semplice (l'unico problema è che utilizzano il formato di compressione RLE alquanto scarso, ne deriva un immagine molto appesantita come dimensioni). Qui (http://en.wikipedia.org/wiki/BMP_file_format) trovi un po' di informazioni sufficienti a scrivere una classe in grado soddisfare le tue esigenze.

Questa è la mia opinione.

Una volta scritta se hai problemi non esitare a postare e chiedere chiarimenti.

PS: Mandelbrot è un frattale relativamente semplice da generare. :ciauz:

Loading