Salve a tutti. Ho questo problema: devo estrarre una matrice dei dati relativi ai livelli di colore di immagini di tipo bitmap al fine di effettuare su questi analisi successive. Ho preparato le macro per l'estrazione dati da matrice e per l'analisi degli stessi perchè ho esperienza di programmazione Fortran. Purtroppo, sulla gestione delle immagini e sul VBA sono neofita. Dopo aver studiato il problema (Loadimage con LR-CreateDIBSection+GetObject dal DIBSection) anche su questo sito ed altrove, senza riuscire, ho trovato il cosice allegato che funziona ma non riesce a gestire le mie immagini BMP che hanno più di 100 livelli di grigio: qualcuno può aiutarmi?
Grazie
Gaetano
codice:
Option Explicit
'###################################################################
' Full Credit to Gary Simmons for this BMP loader code
' Demonstration/tutorial of reading and manually drawing an
' uncompressed (most) bitmap Free for any use:
' see included file (BMP.TXT) for Bitmap file info reference.
'
' Please email me at gary.simmons@optushome.com.au if you find this
' useful
'
' 21st December 2001 Gary Simmons
'###################################################################
Private Type BitMapFile 'bitmap file header structure
bfType As String * 2
bfSize As String * 4
bfReserved1 As String * 2
bfreserved2 As String * 2
bfOffset As String * 4
End Type
Private Type BitMapInfo 'bitmap info header structure
biSize As String * 4
biWidth As String * 4
biHeight As String * 4
biPlanes As String * 2
biBitCount As String * 2
biCompression As String * 4
biSizeImage As String * 4
biXPelsPerMeter As String * 4
biYPelsPerMeter As String * 4
biClrUsed As String * 4
biClrImportant As String * 4
End Type
Private Type RGBQuads 'RGBQuad structure (temporary)
cBlue As String * 1
cGreen As String * 1
cRed As String * 1
cReserved As String * 1
End Type
Private Type RGBQuad 'RGBQuad (used in index)
Blue As Byte
Green As Byte
Red As Byte
End Type
Public Sub GetBmpValues(Filename As String, BMPData() As Long, Progress As MSForms.Label)
' show information about the bitmap and
' manually draw it in another Picturebox
Dim bmf As BitMapFile
Dim bmi As BitMapInfo
Dim rgbqs As RGBQuads
Dim rgbq(255) As RGBQuad
Dim s1 As String * 1
Dim Dword As String * 4
Dim lngCol As Long
Dim lngRow As Long
Dim IWidth As Long
Dim IBitCount As Integer
Dim Pointer As Long
Dim i As Integer
Dim ClrInd As Integer
Dim aMask As Long
Dim z As Integer
Dim ByteNum As Integer
Dim ThisByte As Byte
Dim ColoursFound As Integer
Dim ThisRed As Byte
Dim ThisGreen As Byte
Dim ThisBlue As Byte
Const MAX_WIDTH = 256
Const MAX_HEIGHT = 65536
Progress.Caption = "Reading BMP " & Filename
DoEvents
Open Filename For Binary As #1
Get #1, , bmf 'load the file header
Get #1, , bmi 'info header follows
If lVal(bmi.biSize) <> 40 Or bmf.bfType <> "BM" Then
MsgBox "Not a compatible bitmap."
Close #1
Exit Sub
End If
'load the relevant colour tables
If lVal(bmi.biBitCount) = 1 Then
For i = 0 To 1
Get #1, , rgbqs
rgbq(i).Red = lVal(rgbqs.cRed)
rgbq(i).Green = lVal(rgbqs.cGreen)
rgbq(i).Blue = lVal(rgbqs.cBlue)
Next i
ElseIf lVal(bmi.biBitCount) = 4 Then
For i = 0 To 15
Get #1, , rgbqs
rgbq(i).Red = lVal(rgbqs.cRed)
rgbq(i).Green = lVal(rgbqs.cGreen)
rgbq(i).Blue = lVal(rgbqs.cBlue)
Next i
ElseIf lVal(bmi.biBitCount) = 8 Then
For i = 0 To 255
Get #1, , rgbqs
rgbq(i).Red = lVal(rgbqs.cRed)
rgbq(i).Green = lVal(rgbqs.cGreen)
rgbq(i).Blue = lVal(rgbqs.cBlue)
Next i
End If
' show the properties of the bitmap
' some don't seem to be used
' MsgBox "Actual File Size:" & (Str(LOF(1))) & " bytes" & vbCrLf & _
' "Bitmap File Size: " & lVal(bmf.bfSize) & " bytes" & vbCrLf & _
' "Bitmap Width: " & lVal(bmi.biWidth) & " pixels" & vbCrLf & _
' "Bitmap Height: " & lVal(bmi.biHeight) & " pixels" & vbCrLf & _
' "Bitmap Offset: " & lVal(bmf.bfOffset) & vbCrLf & _
' "Bitmap BitPlanes: " & lVal(bmi.biPlanes) & vbCrLf & _
' "Bitmap BitCount: " & lVal(bmi.biBitCount) & " bit/pixel" & vbCrLf & _
' "Bitmap Size: " & lVal(bmi.biSizeImage) & " bytes" & vbCrLf & _
' "Bitmap ClrUsed: " & lVal(bmi.biClrUsed) & vbCrLf & _
' "Bitmap ClrsImportant: " & lVal(bmi.biClrImportant) & vbCrLf & _
' "Bitmap Compression: " & lVal(bmi.biCompression)
If lVal(bmi.biCompression) <> 0 Then
MsgBox "Its a compressed bitmap."
Close #1
Exit Sub
End If
Close #1
If lVal(bmi.biBitCount) <= 8 Then
' the file is either:
' mono (1-bit/pixel)
' 16-color (4-bit/pixel)
' 256-color (8-bit/pixel)
Open Filename For Binary As #1
lngCol = 0 'holds X position of pixel to draw
lngRow = lVal(bmi.biHeight) '- 1 'holds Y position (Note: bitmap stored from lowest line to highest)
IWidth = lVal(bmi.biWidth) 'width of bitmap
ReDim BMPData(lngRow, IWidth) As Long
IBitCount = lVal(bmi.biBitCount) ' bits/pixel (1,4,8)
Get #1, lVal(bmf.bfOffset), s1 'move binary pointer to start of bitmap
Do While Not EOF(1)
Get #1, , Dword ' read 4-bytes at a time
ByteNum = 1 ' start with first byte in double word
Do While lngCol < IWidth And ByteNum < 5 'stop drawing if edge of bitmap encountered or processed every byte in dword
ThisByte = lVal(Mid(Dword, ByteNum, 1)) 'get relevant byte
Pointer = 8 ' start bit pointer
Do
If lngCol < IWidth Then 'only bother if edge of bitmap not reached
aMask = 0 'reset bit-mask
For z = Pointer To Pointer - IBitCount + 1 Step -1 'the best algorithm
aMask = aMask + 2 ^ (z - 1) 'I could come up with to build a bit-mask
Next z
ClrInd = (ThisByte And (aMask)) / (2 ^ (Pointer - IBitCount)) ' mask of relevant bits and reduce to an appropriate index
BMPData(lngRow, lngCol + 1) = RGB(rgbq(ClrInd).Red, rgbq(ClrInd).Green, rgbq(ClrInd).Blue) 'set the pixel the colour
End If
Pointer = Pointer - IBitCount 'move to the next appropriate bits
lngCol = lngCol + 1 'move the X-position
Loop Until Pointer = 0 'not more bits to process - exit
ByteNum = ByteNum + 1 'point to the next byte in the dword
Loop
If lngCol >= IWidth Then 'if, after processing this dword, we have
Progress.Caption = "Lines remaining " & lngRow
DoEvents
lngRow = lngRow - 1 'reached the end of a line then
If lngRow = 0 Then Exit Do
lngCol = 0 'get the next line and reset the X-position
End If
Loop
Close #1
ElseIf lVal(bmi.biBitCount) = 24 Then
' 16Million-color (24-bit/pixel)
Open Filename For Binary As #1
lngCol = 0
lngRow = lVal(bmi.biHeight) ' - 1
IWidth = lVal(bmi.biWidth)
ReDim BMPData(lngRow, IWidth) As Long
IBitCount = lVal(bmi.biBitCount)
Get #1, lVal(bmf.bfOffset), s1
ColoursFound = 0 'need 3-colours to form a pixel
Do While Not EOF(1)
Get #1, , Dword 'get 4-bytes
ByteNum = 1
Do While lngCol < IWidth And ByteNum < 5
ThisByte = lVal(Mid(Dword, ByteNum, 1))
If lngCol < IWidth Then
ColoursFound = ColoursFound + 1
Select Case ColoursFound
Case Is = 1 'first byte in three is blue (contradicts BMP.TXT)
ThisBlue = ThisByte
Case Is = 2 'second byte is green
ThisGreen = ThisByte
Case Is = 3 'third byte is red
ThisRed = ThisByte
'got the colours we need
'draw the pixel and move on to next pixel
BMPData(lngRow, lngCol + 1) = RGB(ThisRed, ThisGreen, ThisBlue)
ColoursFound = 0
lngCol = lngCol + 1
End Select
End If
ByteNum = ByteNum + 1
Loop
If lngCol >= IWidth Then
Progress.Caption = "Lines remaining " & lngRow
DoEvents
lngRow = lngRow - 1
If lngRow = 0 Then Exit Do
lngCol = 0
End If
Loop
Close #1
End If
End Sub
Function lVal(vStr As String) As Long
'convert little-endian string to long integer
Dim i As Integer
Dim t As Long
t = 0
For i = 1 To Len(vStr)
t = t + Asc(Mid(vStr, i, 1)) * (256 ^ (i - 1))
Next i
lVal = t
End Function
Sub BMPToChart()
frmBMPLoader.Show
Unload frmBMPLoader
End Sub