Pagina 2 di 3 primaprima 1 2 3 ultimoultimo
Visualizzazione dei risultati da 11 a 20 su 27
  1. #11
    Esattamente. Comunque tecnicamente quello che leggi va in memoria, diciamo che puoi ritagliarti per il caricamento solo quello che ti serve. Tieni comunque conto che così facendo rischi di far diventare il disco (=ordini di grandezza più lento della RAM) il bottleneck dell'applicazione, quello che ti salva sono le cache di IO del sistema operativo che, guardacaso, stanno in memoria.
    Amaro C++, il gusto pieno dell'undefined behavior.

  2. #12
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Ecco il codice definitivo, testato su ogni tipo di bitmap: funziona sempre, sempre e sempre. L'ho racchiuso in un metodo statico (tanto per farmi il bello...


    codice:
           //Preleva una porzione da una bitmap su disco definita da un rectangle di origine (x0,y0)
            //e dimensioni (dimx,dimy) che restituisce in una bitmap in memoria.
     
            public static Bitmap GetBmp(string path, int x0, int y0, int dimx, int dimy)
            {
                Vector4 Data = GetData(path);
                int Dim1 = (int)Data.X;
                int Dim2 = (int)Data.Y;
                int Bits = (int)Data.Z;
                int Ofs = (int)Data.W;
    
                byte[] a = GetAll(path);
    
                int truewidth = (int)((Bits * Dim1 + 31) / 32) * 4;
    
                Bitmap b2 = new Bitmap(dimx, dimy);
                int Ptr = 0, R, G, B;
                for (int y = y0; y < y0 + dimy; y++)
                    for (int x = x0; x < x0 + dimx; x++)
                    {
                        Ptr = Ofs +  (Bits/8)*x + truewidth * (Dim2 - y - 1);
                        B = Convert.ToInt32(a[Ptr]);
                        G = Convert.ToInt32(a[Ptr + 1]);
                        R = Convert.ToInt32(a[Ptr + 2]);
                        b2.SetPixel(x - x0, y - y0, System.Drawing.Color.FromArgb(R, G, B));
                    }
                return b2;
            }
    Ma no, a me serve per esempio una regione di 500x500 pixel per volta, da prelevare però da una mappa immensa (tipo 10000 o 20000 px lato, ma ora chi mi ferma più? Anche 50000 px lato, tanto ci mette sempre lo stesso tempo (questo è il bello) e in memoria ci sta solo la Region....

  3. #13
    None! Stai sempre e comunque caricando tutti i byte del file in memoria! Inoltre, la setPixel è lentissima, e anche quei cast lì non li vedo bene... Il sistema giusto è accedere ai pixel della bitmap target e leggerci dentro direttamente le scanline dal file (o comunque, accedere direttamente ai byte, usando un blocco unsafe e i puntatori. Domani se ho un momento provo a mettere insieme un esempio.
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #14
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    URKA è vero! Quella riga

    byte[] a = GetAll(path);

    mi frega di brutto. E io sai che faccio? Butto tutto il codice di GetBmp dentro GetAll e gli faccio caricare di volta in volta solo il byte puntato.... (torno subito)

    codice:
          //Preleva una porzione da una bitmap su disco in base ai dati di origine x0,y0
            //e le dimensioni dimx,dimy e restituisce una bitmap in memoria.
            public static Bitmap GetBmp(string path, int x0, int y0, int dimx, int dimy)
            {
                Vector4 Data = GetData(path);
                int Dim1 = (int)Data.X;
                int Dim2 = (int)Data.Y;
                int Bits = (int)Data.Z;
                int Ofs = (int)Data.W;
                int truewidth = (int)((Bits * Dim1 + 31) / 32) * 4;
                Bitmap b2 = new Bitmap(dimx, dimy);
                FileStream f = File.Open(path, FileMode.OpenOrCreate);
                byte[] a = new byte[3];//i tre byte di colore pixel
                int Ptr = 0, R, G, B;
                for (int y = y0; y < y0 + dimy; y++)
                    for (int x = x0; x < x0 + dimx; x++)
                    {
                        Ptr = Ofs + (Bits / 8) * x + truewidth * (Dim2 - y - 1);
                        f.Seek(Ptr, SeekOrigin.Begin);
                        f.Read(a, 0, 3);
                        B = Convert.ToInt32(a[0]);
                        G = Convert.ToInt32(a[1]);
                        R = Convert.ToInt32(a[2]);
                        b2.SetPixel(x - x0, y - y0, System.Drawing.Color.FromArgb(R, G, B));
                    }
                f.Close();
                return b2;
            }
    Ultima modifica di escocat; 17-02-2015 a 13:30

  5. #15
    Siamo ancora lenti... lascia stare la SetPixel, tutte quelle Seek/letturine da 12 byte, leggi righe intere e copiale direttamente nella bitmap di destinazione (ad esempio con Marshal.Copy come qui).
    Amaro C++, il gusto pieno dell'undefined behavior.

  6. #16
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Si è vero. Ho fatto tutto questo macello per evitare una costipazione al mio portatilino e ora ho lo stesso problemi di lentezza dovuti alle letture dei byte, ma almeno non ho più limiti di memoria e questo credimi è un sogno. Mentre navigo ho veramente l'impressione di essere sulla Luna. Sono emozioni difficili da trasferire, ma il gioco vale la candela e dunque sotto al lavoro con i nuovi compiti per casa che mi hai lasciato (AMMAZZALA QUANTO 6 DURO!). Buona l'idea di leggere le righe (in fondo che sono 100000x3 bytes rispetto a 100000x100000x3?) e finalmente uso la Marshal che fa tanto di snob.....

  7. #17
    Allora appena ottieni qualcosa di funzionante forniscicene un assaggio
    Amaro C++, il gusto pieno dell'undefined behavior.

  8. #18
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Niente, mi sono perso nei geroglifici della Marshal. Eppure ho controllato byte su byte con mini bitmap e ogni valore è al posto giusto, ma il risultato è disastroso.

    codice:
           public static Bitmap MarshalGetBmp(string path, int x0, int y0, int dimx, int dimy)
            {
                //Legge le grandezze fondamentali della bitmap origine
                Vector4 Data = GetData(path);
                int Dim1 = (int)Data.X;
                int Dim2 = (int)Data.Y;
                int Bits = (int)Data.Z;
                int Ofs = (int)Data.W;
    
                //effettivo Width della bitmap di origine
                int truewidth1 = (int)((Bits * Dim1 + 31) / 32) * 4;
    
                //effettivo Width della bitmap di destinazione
                int truewidth2 = (int)((Bits * dimx + 31) / 32) * 4;
    
                //Costruisce la bitmap di destinazione in memoria
                Bitmap b = new Bitmap(dimx, dimy);
    
                //numero di byte da leggere per costruire una riga di b
                int bytes = Bits * dimx / 8;
    
                //array di valori byte di riga
                byte[] a = new byte[bytes];
    
                //Costruzione BitmapData associata a b
                System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, dimx, dimy);
                System.Drawing.Imaging.BitmapData bmdata = b.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, b.PixelFormat);
    
                //puntatore ad inizio memoria della bitmap b
                IntPtr Ptr = bmdata.Scan0;
    
                //apre lo stream della bitmap origine
                FileStream f = File.Open(path, FileMode.OpenOrCreate);
    
                int sp;//puntatore allo stream
                for (int y = y0; y < y0 + dimy; y++)
                {
                    //pt impostato ad ogni inizio riga nello stream
                    sp = Ofs + (Bits / 8) * x0 + truewidth1 * (Dim2 - y - 1);
                    f.Seek(sp, SeekOrigin.Begin);
    
                    //legge la riga di byte e scrive nell'array
                    f.Read(a, 0, bytes);
    
                    //Copia Marshal dell'array nell'area di memoria di b puntata
                    System.Runtime.InteropServices.Marshal.Copy(a, 0, Ptr, bytes);
    
                    //sposta il puntatore in memoria b di un offset pari al truewidth di b
                    Ptr = new IntPtr((int)IntPtr.Add(Ptr, truewidth2));
                }
    
                //Chiude lo stream e libera b
                f.Close();
                b.UnlockBits(bmdata);
    
                return b;//CIAO
            }
    Ultima modifica di escocat; 18-02-2015 a 02:42

  9. #19
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Mi sono immerso in questo campo affascinante ed ho scoperto che:

    1) Intanto ho sbagliato a scrivere questa formula

    codice:
    int truewidth = (int)((Bits * Dim1 + 31) / 32) * 4;
    perchè nella formula che mi ha regalato MItaly (vedi allegato, prima formula) ci sono parentesi quadre che indicano una funzione soffitto e non la semplice parte intera, dunque più che un cast a Int si tratta di un Math.Ceiling.

    2) Ci sono bitmap orientate dal basso in alto e bitmap messe "al contrario", ma non c'è traccia nell'head del file bmp di questa disposizione;

    3) Wikipedia italiana mi dà un'altra formula per il rowsize (vedi allegato) con tanto di funzione di Heavside....

    4) Nell'Head del file bmp le dimensioni Width e Height sono indicate in 2 byte ma talvolta il primo byte indica il valore 'basso' altre volte il valore 'alto'. Anche qui non c'è traccia nell'Head di un indicatore per leggere correttamente questi dati.

    5) il valore rowsize che si deduce dalle formule su citate non sempre è in sintonia col valore bitmapdata.Stride .

    Detto questo non mi arrendo devo solo studiare meglio quello che sto facendo, ma se qualcuno è in grado di risolvere questi nodi mi farebbe risparmiare un sacco di tempo.....
    Immagini allegate Immagini allegate
    Ultima modifica di escocat; 18-02-2015 a 13:16

  10. #20
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Che bello. La storia è molto più affascinante di quanto pensassi.

    1) Intanto ho sbagliato a scrivere questa formula

    int truewidth = (int)((Bits * Dim1 + 31) / 32) * 4; (1)
    perchè nella formula che mi ha regalato MItaly (vedi allegato, prima formula) ci sono parentesi
    quadre che indicano una funzione soffitto e non la semplice parte intera, dunque più che un cast a
    Int si tratta di un Math.Ceiling.
    3) Wikipedia italiana mi dà un'altra formula per il rowsize (vedi allegato) con tanto di funzione di
    Heavside....
    Sembra che io non abbia sbagliato, a mia insaputa. D'altra parte il metodo GetBmp che usa i SetPixel
    funziona in tutti i casi ed usa proprio questa formula.
    Esistono due versioni per il termine da "arrotondare" nel calcolo della reale dimensione fisica di
    una riga della nostra bitmap, ed a questo fatto è dovuta la presenza di due formule nelle Wikipedie
    En e It. In parole povere questo vuol dire che
    1) o prendiamo la parte intera di (Bits * Dim1 + 31) / 32 che sarebbe il numero intero che precede e
    non eccede quel valore float,
    2) o prendiamo la funzione soffitto ovvero il Math.Ceiling di Bits * Dim1 / 32 dunque
    il numero intero che segue quel valore float. Le due versioni forniscono gli stessi valori.

    2) Ci sono bitmap orientate dal basso in alto e bitmap messe "al contrario", ma non c'è traccia
    nell'head del file bmp di questa disposizione;
    4) Nell'Head del file bmp le dimensioni Width e Height sono indicate in 2 byte ma talvolta il primo
    byte indica il valore 'basso' altre volte il valore 'alto'. Anche qui non c'è traccia nell'Head di
    un indicatore per leggere correttamente questi dati.
    Qui sono ancora al buio.

    5) il valore rowsize che si deduce dalle formule su citate non sempre è in sintonia col valore
    bitmapdata.Stride .
    Questa è la parte "affascinante" e credo di aver capito quanto segue:

    Quando si crea una bitmap vengono costruiti due spazi, uno "fisico" e grande ed uno "logico" più
    piccolo compreso al suo interno. Questo è dovuto al fatto che una bitmap lavora con 3 byte per pixel
    (24 bit) con valori RGB ma ci si riserva sempre la possibilità di "espanderlo" in modo che ad ogni
    pixel si possa aggiungere il canale alfa e dunque essere trattato a quattro byte ARGB (es.
    conversione bmp -> png, 32 bit) senza dover spostare il file o peggio ancora invadere lo spazio
    delle informazioni confinanti.

    Lo spazio logico è molto importante perchè è lì che effettivamente si trovano i dati immagine, e la
    sua larghezza (byte x riga) dovrebbe essere 3*Width byte senonchè questo valore si arrotonda ad un
    prossimo valore multiplo di 4 se non lo è già, ed è qui che entra in gioco il famigerato termine di
    cui sopra. L'importanza di questo "truewidth" viene a galla nella formula di associazione tra le
    coordinate pixel ed il puntatore nel filestream

    sp = Ofs + (Bits / 8) * x + truewidth * (Dim2 - y - 1);

    e come si vede non viene usato il valore Dim1 al suo posto.

    Lo spazio fisico è quello che potete osservare in risorse del computer dalle dimensioni in byte del
    file ed è sempre costituito dai 54 byte dell'intestazione + una matrice di Dim2 righe ognuna larga
    4*Dim1 byte ed è questo ultimo valore che rappresenta il famoso Stride.

    Invece non riesco a trovare nell'intestazione i byte di riferimento per la grandezza del truewidth,
    almeno io non li vedo da nessuna parte, esiste l'indicazione dei byte totali per il file ma non è un
    valore affidabile, a meno che non ci siano dei byte aggiunti e riservati oltre lo spazio immagine e
    lo spazio dell'intestazione. Dobbiamo pregare che il valore di truewidth coincida con quello
    calcolato con la formula (1).....

    Ecco di seguito alcuni valori ottenuti costruendo mini-bitmap tutte con 3 righe a larghezza
    variabile di pixel:

    Dim1 truewidth BitmapData.Stride

    5 16 20
    6 20 24
    7 24 28
    8 24 32
    9 28 ... ecc. ecc. = 4*Dim1
    10 32
    11 36
    12 36
    13 40
    14 44
    15 48
    16 48 .... ecc. ecc.
    ...
    996 2988 3984
    997 2992 3988
    998 2996 3992
    999 3000 3996
    1000 3000 4000
    Ultima modifica di escocat; 18-02-2015 a 19:55

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.