Oppure

Loading
26/07/21 13:03
bernie
Io avevo fatto una cosa molto grossolana
Dim originale As New Bitmap("C:\cerchiogreyscale8bpp.bmp")
        Dim clonerettangolo As New Rectangle(0, 0, originale.Width, originale.Height)
        Dim clone4bpp As Bitmap = originale.Clone(clonerettangolo, Imaging.PixelFormat.Format4bppIndexed)
        'creo la palette scala di grigio
        Dim palette As Imaging.ColorPalette = clone4bpp.Palette
        For i = 0 To palette.Entries.Length - 1
            If i > 7 Then
                palette.Entries(i) = Color.White
            Else
                palette.Entries(i) = Color.FromArgb(255 - i * 36.4, 255 - i * 36.4, 255 - i * 36.4)
            End If
        Next i

        'associo la palette creata alla bitmap 4bpp,
        'i valori 0...15 ora corrispondono alla scala dal nero al bianco
        clone4bpp.Palette = palette

        ' blocco i bit della bitmap per poter lavorare direttamente su un vettore di bytes
        Dim area As Rectangle = New Rectangle(0, 0, clone4bpp.Width, clone4bpp.Height)
        Dim bmpData As Imaging.BitmapData = clone4bpp.LockBits(area, Imaging.ImageLockMode.ReadWrite, clone4bpp.PixelFormat)

        ' puntatore all'indirizzo di memoria del primo byte.
        Dim ptr As IntPtr = bmpData.Scan0

        ' un vettore che conterrà tutti i bytes della bitmap.
        Dim bytes As Long = Math.Abs(bmpData.Stride) * clone4bpp.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes - 1) As Byte
        ' nel vettore colorValues metto i dati dalla locazione ptr che rappresentano clone4bpp
        System.Runtime.InteropServices.Marshal.Copy(ptr, colorValues, 0, bytes)


        For ind = 0 To bytes - 1
            Dim primosemibyte As Byte = colorValues(ind) \ 16
            Dim secondosemibyte As Byte = colorValues(ind) - primosemibyte * 16
            'primobyte
            If primosemibyte >= 0 And primosemibyte <= 7 Then
                primosemibyte = 7
            ElseIf primosemibyte >= 8 And primosemibyte <= 53 Then
                primosemibyte = 6
            ElseIf primosemibyte >= 54 And primosemibyte <= 89 Then
                primosemibyte = 5
            ElseIf primosemibyte >= 90 And primosemibyte <= 125 Then
                primosemibyte = 4
            ElseIf primosemibyte >= 126 And primosemibyte <= 161 Then
                primosemibyte = 3
            ElseIf primosemibyte >= 162 And primosemibyte <= 197 Then
                primosemibyte = 2
            ElseIf primosemibyte >= 198 And primosemibyte <= 233 Then
                primosemibyte = 1
            ElseIf primosemibyte >= 234 Then
                primosemibyte = 0
            End If
            'secondobyte
            If secondosemibyte >= 0 And secondosemibyte <= 7 Then
                primosemibyte = 7
            ElseIf secondosemibyte >= 8 And secondosemibyte <= 53 Then
                primosemibyte = 6
            ElseIf secondosemibyte >= 54 And secondosemibyte <= 89 Then
                primosemibyte = 5
            ElseIf secondosemibyte >= 90 And secondosemibyte <= 125 Then
                primosemibyte = 4
            ElseIf secondosemibyte >= 126 And secondosemibyte <= 161 Then
                primosemibyte = 3
            ElseIf secondosemibyte >= 162 And secondosemibyte <= 197 Then
                primosemibyte = 2
            ElseIf secondosemibyte >= 198 And secondosemibyte <= 233 Then
                secondosemibyte = 1
            ElseIf secondosemibyte >= 234 Then
                secondosemibyte = 0
            End If
            colorValues(ind) = primosemibyte * 16 + secondosemibyte ' ricompongo il byte con i due pixel
        Next
        System.Runtime.InteropServices.Marshal.Copy(colorValues, 0, ptr, bytes)
        clone4bpp.UnlockBits(bmpData) ' sblocco bit
        clone4bpp.SetResolution(360, 360)
        clone4bpp.Save("C:\remap8bppa3bpp.bmp", Imaging.ImageFormat.Bmp)
        
        clone4bpp.Dispose()
    End Sub

In questa maniera posso decidere io che range di livelli originali associo al nuovo livello .
Quello che non ho capito è perchè nei toni medi , mi colora un pixel si e uno no .
aaa
26/07/21 13:06
Carlo
allega: cerchiogreyscale8bpp.bmp
in programmazione tutto è permesso
26/07/21 13:08
bernie
Ecco , niente di speciale
aaa
26/07/21 15:49
Carlo
L'esempio che hai postato ha una falla logica, sempre che io abbia bene interpretato cosa vuoi fare.
Il problema sta nel fatto che l'immagine: cerchiogreyscale8bpp.bmp con palette a 256 livelli di grigio la converti subito a 4bpp, facendo questo perdi i valori originali dei livelli che poi vorresti convertire a 4bpp.
L'esempio che segue corregge il problema, e ti fa impostare una palette come desideri senza fare una sequenza di iff.
Le righette che vedi ci sono perché non hai calcolato i valori correttamente.
' da 8bpp a 4bpp con palette a 3bit
       Dim bmp8bpp As New Bitmap("C:\cerchiogreyscale8bpp.bmp")
        ' blocco i bit della bitmap     
        Dim area8 As Rectangle = New Rectangle(0, 0, bmp8bpp.Width, bmp8bpp.Height)
        Dim bmpData8 As System.Drawing.Imaging.BitmapData = bmp8bpp.LockBits(area8, Drawing.Imaging.ImageLockMode.ReadWrite, bmp8bpp.PixelFormat)
        Dim ptr8 As IntPtr = bmpData8.Scan0 ' puntatore all'indirizzo di memoria del primo byte.
        Dim bytes8 As Integer = Math.Abs(bmpData8.Stride) * bmp8bpp.Height ' calcolo dei bytes necessari
        Dim colorValues(bytes8 - 1) As Byte ' un array che conterrà tutti i bytes della bitmap.
        ' nel vettore colorValues metto i dati dalla locazione ptr che rappresentano bmp8bpp 
        System.Runtime.InteropServices.Marshal.Copy(ptr8, colorValues, 0, bytes8)
     

        ' dichiaro bmp4bpp
        Dim bmp4bpp As New Bitmap(bmp8bpp.Width, bmp8bpp.Height, Imaging.PixelFormat.Format4bppIndexed)
        ' blocco i bit della bitmap     
        Dim area4 As Rectangle = New Rectangle(0, 0, bmp4bpp.Width, bmp4bpp.Height)
        Dim bmpData4 As System.Drawing.Imaging.BitmapData = bmp4bpp.LockBits(area4, Drawing.Imaging.ImageLockMode.ReadWrite, bmp4bpp.PixelFormat)
        'creo una palette con 8 livelli di grigio a piacere, qui scegli l'aspetto dell'immagine con i colori scalati
        Dim palette8 As Imaging.ColorPalette = bmp4bpp.Palette
        palette8.Entries(0) = Color.FromArgb(200, 200, 200)
        palette8.Entries(1) = Color.FromArgb(10, 10, 10)
        palette8.Entries(2) = Color.FromArgb(20, 20, 20)
        palette8.Entries(3) = Color.FromArgb(30, 30, 30)
        palette8.Entries(4) = Color.FromArgb(100, 100, 100)
        palette8.Entries(5) = Color.FromArgb(101, 101, 101)
        palette8.Entries(6) = Color.FromArgb(200, 200, 200)
        palette8.Entries(7) = Color.FromArgb(130, 130, 130)
        ' associo la palette creata alla bitmap 4bpp,
        ' i valori 0...7 ora corrispondono alla scala arbitraria creata
        bmp4bpp.Palette = palette8
        Dim ptr4 As IntPtr = bmpData4.Scan0
        Dim bytes4 As Long = Math.Abs(bmpData4.Stride) * bmp4bpp.Height ' calcolo dei bytes necessari
        Dim levelValues(bytes4 - 1) As Byte

        ' nel vettore che rappresenta bmp4bpp ci copio i dati dal vettore che rappresenta bmp8bpp, scalati
        ' scorro i vettori per riga e colonna

        For riga = 0 To bmp8bpp.Height
            For colonna = 0 To bmpData8.Stride
                Dim ind8 As UInt32 = colonna + riga * (bmpData8.Stride - 2)  'calcolo l'indice per il vettore colorValues
                Dim ind4 As UInt32 = colonna / 2 + riga * (bmpData4.Stride - 1)   'calcolo l'indice per il vettore levelValues
                levelValues(ind4) = (colorValues(ind8) \ 31.8) + (colorValues(ind8) \ 31.8) * 16
            Next
        Next
   
        ' ripristino vettore su immagine
        System.Runtime.InteropServices.Marshal.Copy(levelValues, 0, ptr4, bytes4)
        bmp4bpp.UnlockBits(bmpData4) ' sblocco bit
        bmp4bpp.SetResolution(360, 360)
        bmp4bpp.Save("C:\remap8bppa3bpp.bmp", Imaging.ImageFormat.Bmp)


levelValues(ind4) = entrambi i pixel uguali, se li vuoi divisi sai come fare.
Ultima modifica effettuata da Carlo 26/07/21 15:58
in programmazione tutto è permesso
26/07/21 17:07
bernie
Giustissimo , prendo l'immagine a 8bpp e la converto subito a 4bpp, così facendo perdo tutti i livelli di grigio.
Quindi , prendo l'immagine ,blocco i bit nel vettore ( e sono ancora 255 livelli )
Creo un bmp delle stesse dimensioni(pixel) a 4bpp, il numero dei byte sarà la metà visto che 1 byte fa due pixel.
A questo punto tutti i pixel che hanno valore compreso tra (0,0,0) a (10,10,10) nel bmp 8bpp dovranno diventare tutti 0 nel bmp a 3bpp.
Per quello mi servivano tutti gli if , perchè non devo cambiare solo un valore , ma tutti i pixel che cadono dentro un certo intervallo di colore , devono diventare tutti uguali .
Se un pixel ha valore (255,255,255) e il successivo (253,253,253) entrambi con la nuova palette diventano 7 mentre se il seguente è (240,240,240) diventa 6 . Devo raggruppare tutti i valori della palette a 256 livelli in 8 livelli .
Da (255,255,255) a (223,223,223) diventano 7
Da(222,222,222) a (190,190,190) diventano 6
e via cosi . Ovviamente il range lo devo impostare.
aaa
26/07/21 17:56
Carlo
questa riga
levelValues(ind4) = (colorValues(ind8) \ 31.8) + (colorValues(ind8) \ 31.8) * 16

fa quello che dici tu senza if

Hai provato l'esempio?
in programmazione tutto è permesso
26/07/21 18:50
bernie
Si, ho provato l'esempio ma non posso passarlo al sistema per adesso.
Nel tuo esempio la rimappatura è lineare, a me non serve lineare.
aaa
27/07/21 13:23
Carlo
Postato originariamente da bernie:

Si, ho provato l'esempio ma non posso passarlo al sistema per adesso.
Nel tuo esempio la rimappatura è lineare, a me non serve lineare.

Avevo capito che non ti serve lineare :asd:, ma ho fatto questo ragionamento:
L'immagine in input è a 8bpp e ha una scala di 256 grigi lineare.
Nell'immagine di output a 4bpp dove solo 3bit della palette vengono usati, ci copio i dati scalati linearmente dall'immagine 8bpp.
Ora agendo sulla palette a 3bit, posso scegliere arbitrariamente il livello RGB di ogni valore 0...7 che mi occorre, senza dover per forza restare lineare.
:rotfl:
Ultima modifica effettuata da Carlo 27/07/21 19:45
in programmazione tutto è permesso