Visualizzazione dei risultati da 1 a 8 su 8
  1. #1
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308

    [C#] Costruttore Bitmap da file e memoria

    Ciao a tutti.
    Vorrei capire bene cosa succede in sottofondo quando costruiamo una bitmap leggendola da un file.
    Es.:
    Bitmap b = new Bitmap("C:\ciao.bmp");

    Immagino che b finisca in memoria e ciao.bmp rimanga li dov'era sul disco C. E fin qui (spero) va bene.
    Che succede se voglio copiare in una bitmap b2 solo una porzione 100 x 100 di una bitmap b1 1000 x 1000 contenuta su C nel file C:\b1.bmp?

    Bitmap b2 = new Bitmap(100, 100) ----> memoria occupata M 100x100
    Graphics g = Graphics.FromImage(b2) ----> memoria x graphics
    g.DrawImage(b1, 0, 0, new Rectangle(0,0,100,100)) ---> dati da b1 a M
    g.Dispose() ---> liberata memoria per graphics

    Quando avviene il trasferimento dei dati da b1 a M, b1 resta sul disco C no? Quindi tutta la memoria che ho usato è M?

    Ah scusate ho detto una fesseria, b1 è pure in memoria!
    Il fatto è che io ho una bitmap di 10000x10000 su disco ma un mio programma ne deve usare una porzione piccolissima per volta. Come posso fare? La Marshal.Copy fa al caso mio?
    Ultima modifica di escocat; 13-02-2015 a 15:37

  2. #2
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    E scusate pure per quest'altra domanda: io creo una bitmap b e la trasformo in Png. Eseguo

    System.Drawing.Imaging.BitmapData bdata = b.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
    ImageLockMode.ReadOnly, bmp.PixelFormat);

    Leggo lo Stride di bdata e mi da 3 byte per pixel: perchè non 4? Il canale alfa che fine ha fatto?
    Ultima modifica di escocat; 13-02-2015 a 16:49

  3. #3
    Quote Originariamente inviata da escocat Visualizza il messaggio
    Quando avviene il trasferimento dei dati da b1 a M, b1 resta sul disco C no? Quindi tutta la memoria che ho usato è M?
    No. Quando carichi un'immagine va tutta in memoria - il processore non sa lavorare direttamente con dati che stanno su disco, e in generale quando GDI+ carica un'immagine la tiene tutta in memoria in un formato indipendente dal formato di file specifico (che è l'unica cosa sensata da fare per molti formati compressi).
    Ah scusate ho detto una fesseria, b1 è pure in memoria!

    Il fatto è che io ho una bitmap di 10000x10000 su disco ma un mio programma ne deve usare una porzione piccolissima per volta. Come posso fare? La Marshal.Copy fa al caso mio?
    Marshal.Copy serve a copiare dati da memoria a memoria, perché dovrebbe ridurti l'utilizzo di memoria?

    Una soluzione semplice al tuo problema può essere dividere manualmente la tua immagine in 100 tiles quadrate (diciamo 1000x1000) e caricare solo quelle necessarie per ricostruire il pezzo di immagine che ti interessa.
    Leggo lo Stride di bdata e mi da 3 byte per pixel: perchè non 4? Il canale alfa che fine ha fatto?
    Se il tutto deriva da un .BMP probabilmente hai salvato il PNG senza canale alpha...
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #4
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308

    Una soluzione semplice al tuo problema può essere dividere manualmente la tua immagine in 100 tiles quadrate (diciamo 1000x1000) e caricare solo quelle necessarie per ricostruire il pezzo di immagine che ti interessa


    Non è così semplice, la porzione che mi interessa varia in continuazione e l'origine del rectangle può essere un punto qualsiasi della mappa hires. Comunque credo di aver risolto in questo modo:
    1) Partendo dalla mia mappa hires (la bitmap 10000x10000 o 30000x30000 per intenderci) leggo tutti i pixel e i tre byte R,G,B.
    2) Mi creo un files di byte che contiene tutti i valori RGB dei pixel: ogni pixel occupa 3 byte.
    3) E' nota la relazione tra pixel (x,y) e puntatore Ptr del primo byte di ogni gruppo di 3 byte nel file: Ptr = 3*(x + Dim1*y)
    4) In base alla parte che devo estrarre (sottoinsieme di valori x, y della mappa hires) vado a prelevare nel file i byte che mi interessano e leggendo i valori contenuti nei byte ricostruisco la bitmap (partizione) corrente. In questo modo in memoria, ad ogni istante, ho solo la piccola bitmap estratta. Sto facendo fare tutto questo lavoro ad una classe Pxl (pixel) che ho scritto per ottimizzare il codice. Se a qualcuno interessa posso allegare il codice Pxl.

  5. #5
    Quote Originariamente inviata da escocat Visualizza il messaggio
    Non è così semplice, la porzione che mi interessa varia in continuazione e l'origine del rectangle può essere un punto qualsiasi della mappa hires.
    Appunto per quello dicevo di caricare le tiles (=plurale) necessarie.
    ...
    Puoi anche evitare il passaggio per un file separato, se è un normale .bmp i byte sono già scritti senza compressione.
    Comunque, se l'immagine è non compressa e più piccola dello spazio di indirizzi puoi guadagnare molto mappando il file in memoria e lasciando che sia il sistema operativo a smazzarsi le menate di caching.

    In ogni caso, l'approccio a tiles (magari gestito in maniera un po' meno naif) diventa essenziale lavorando con immagini molto grosse, per cui mantieni cache locality operando su pixel vicini (a differenza del tenere il file non compresso, per cui comunque devi saltare qua e là passando da una riga all'altra).
    Amaro C++, il gusto pieno dell'undefined behavior.

  6. #6
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Puoi anche evitare il passaggio per un file separato, se è un normale .bmp i byte sono già scritti senza compressione.
    Comunque, se l'immagine è non compressa e più piccola dello spazio di indirizzi puoi guadagnare molto mappando il file in memoria e lasciando che sia il sistema operativo a smazzarsi le menate di caching.
    A dire il vero io lavoro con i Png.... ho cercato di capire come è fatto il loro formato e dove comincia lo spazio dei dati sul file ma mi sono perso, e comunque i png non sono così chiari e limpidi come i bmp.
    Per quanto riguarda la mappatura in memoria, con Xna io e il mio portatilino soffriamo abbastanza non appena carichiamo una png 1000x1000. C'è un modo per usare una memoria DIVERSA da quella che serve a Xna? Per farti capire, io ho mondi sferici e mondi "cubici" con 6 facce modellate - a bassa risoluzione (cioè se sono abbastanza lontano da quel mondo) con png di 500x500 o 1000x1000. Ma quando mi avvicino la porzione di mondo che sto sorvolando deve mostrare i particolari più "fini" e così quella porzione di faccia inquadrata devo sostituirla con una map prelevata da una png di 5000x5000 ad esempio, perchè non posso utilizzare tutta la nuova mappa hires altrimenti il portatile va a fuoco (o meglio si addormenta). Avvicinandomi ancora il discorso si ripete, ecco perchè alla fine mi serve una base alla risoluzione massima di 10000 o 30000 pixel. E pensa tu che i miei mondi cubici hanno 6 facce e nel mio sistema gravitazionale ci sono almeno una decina di mondi. Poi ci sono quelli sferici che avendo "una sola faccia" (anzi tre per essere precisi) figurati che dimensioni devono avere..... dunque o faccio quel discorso che ti dicevo, o trovo qualche memoria a disposizione che non invade quella di Xna, o rubo qualche PC alla NASA.

  7. #7
    Quote Originariamente inviata da escocat Visualizza il messaggio
    A dire il vero io lavoro con i Png.... ho cercato di capire come è fatto il loro formato e dove comincia lo spazio dei dati sul file ma mi sono perso, e comunque i png non sono così chiari e limpidi come i bmp.
    Se parliamo di PNG è tutto un altro discorso, per avere accesso casuale in O(1) a qualunque pixel dell'immagine devi necessariamente scompattarlo (fai conto che un PNG concettualmente è come se fosse un .BMP zippato).
    Per quanto riguarda la mappatura in memoria, con Xna io e il mio portatilino soffriamo abbastanza non appena carichiamo una png 1000x1000. C'è un modo per usare una memoria DIVERSA da quella che serve a Xna?
    Al di là del fatto che per il memory mapping devi usare immagini non compresse (per il motivo detto sopra), se tutto va lento significa che hai finito la memoria fisica (lo spazio di indirizzi virtuale ha ancora spazio, ma il sistema operativo è costretto a fare swapping, per cui deve passare al disco e tutto diventa ordini di grandezza più lento).

    Again: ti conviene ragionare per tile, caricando solo quelle che ti servono e buttandole via quando non ti servono più (eventualmente tieni una cache di dimensioni limitate), invece di decomprimere e caricare completamente in memoria (=il sistema operativo deve allocare effettivamente spazio per tutto in memoria fisica) PNG enormi.
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #8
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Dunque, se non ti annoio troppo, io attualmente sto usando due strategie di hiring (alias due "modelli World": un tipo P (Partition) e un tipo R (Rectangle). Il tipo P effettivamente usa una Hires Map già inizializzata come suddivisa in più "parti" ed io effettivamente prelevo ora una parte ora un'altra. Ho dovuto "inventarmi" la seconda strategia perchè se il centro del campo puntato P capita sul bordo della sua partizione mi ritrovo il campo in dettaglio spostato rispetto alla linea visuale (è antipatico e inevitabile). Volendo mantenere il campo in dettaglio centrato sulla retta View della mia Camera devo "spostare" la partizione di quel tanto che basta, ma con partizioni "fisse" questo non posso farlo e allora devo ricorrere a partizioni "variabili" e cioè appunto a Rectangle prelevate con Graphics.Draw dalla HiresMap. Questo mi permette di prelevare, sempre e comunque, il Rectangle centrato su P ma come ben tu capisci non ho più partizioni fisse costruite all'inizio una volta e per sempre. Questo metodo va molto bene, non ha praticamente difetti se non quello (ahime) che per evocare graphics.Draw devo avere in memoria la HiresMap... allora sto prendendo la terza via: lascio la Hires su disco ed eseguo un graphics.Draw sul suo file di bytes (che io chiamo raw), tanto funziona lo stesso. Al modello non interessa tanto l'immagine quanto i dati numerici di colore che poi modulano le altezze delle montagne e dei crateri di quel mondo. Se voglio che il mio portatilino funzioni come se fossi alla NASA devo fare così... e come premio non ho limiti sulle dimensioni delle png se non eccedono il mio HD, e posso lavorare anche senza immagini tanto partendo da piccoli dati byte le immagini le creo io. Unica seccatura: per creare il raw di una 10000x10000 il portatile ci mette una notte intera, ma tanto io dormo....a meno che non decido di usare bmp per le heightmap e mi riservo le png per le textures (che spesso devono essere trasparenti) e le bmp sono già in raw....
    Ultima modifica di escocat; 15-02-2015 a 00:37

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.