Zurück zur Homepage

Farbverteilung einer Bilddatei.

Beispieldatei (Farbverteilung.zip 31 kB)

Irgendwann ist die Frage aufgetaucht, ob es möglich ist, die Daten aus einem Digitalfoto bereitzustellen.

Es soll damit der prozentuale Pilzbefall auf Blattproben ermittelt werden, das heißt, der Anteil der braunen Flecken auf dem Blattgrün ist entscheidend.

Wie man das letztendlich auswertet, sei dahingestellt. Wichtig ist erst einmal, die Daten eines Digitalfotos für die Auswertung verfügbar zu machen Und genau das macht der nachfolgende Code.

In einem Dialog wird man aufgefordert, eine Bilddatei auszuwählen, deren Daten ausgelesen und bereitgestellt werden. Die zurückgelieferte Collection enthält ein dreidimensionales Array mit dem Schlüsselnamen "AllPixel".
Die erste Dimension gibt die Spalte an.
Die zweite Dimension gibt die Zeile an.
Die dritte Dimension gibt den Farbanteil an. Eins ist dabei der Rotanteil, zwei der Grünanteil und drei der Blauanteil.
Das heißt, myCollection("AllPixel")(1,2,3) würde den Blauanteil des Pixels in der ersten Spalte und der zweiten Zeile liefern.

Außerdem werden noch andere Infos zum Bild bereitgestellt. Der Schlüsselname der Informationscollection ist "Infos". In der Infos-Collection sind die eigentlichen Informationen unter verschiedenen Namen verfügbar.
Das Item "Breite" liefert die Breite , das Item "Höhe" die Höhe des Bildes. Gleichzeitig wurden alle Farbwerte der entsprechenden Grundfarbe des gesamten Bildes addiert. Das heißt, die Summen der Rot- Grün- und Blauanteile eines jedes Pixels wurden in einer Schleife gebildet und werden unter den Schlüsselnamen "Summe R", "Summe G", "Summe B" bereitgestellt.

Im folgenden Bild sieht man die Farbverteilung eines grünen Bildes (mit einem kleinen Blauanteil) mit 300x300 Pixel, das mit einer anderen Farbe verunreinigt wird. Der Anteil der braunen Flecken liegt je nach Bild zwischen 0 und 5%.

Die Bilder können Sie zum Herunterladen anklicken.

Am Ende finden Sie noch Code, wie man ein Bild in verschiedene Einzelbilder aufteilen kann und diese analysieren kann.

Hier der Code zur Analyse eines Bildes:

 

Option Explicit
Private Declare Function GetDIBits _
   
Lib "gdi32" ( _
   
ByVal aHDC As Long, _
   
ByVal hBM As Long, _
   
ByVal nStartSL As Long, _
   
ByVal nNumSL As Long, _
   lpBits 
As Any, _
   lpBI 
As Any, _
   
ByVal wUsage As Long _
   ) 
As Long
Private Declare Function GetDC _
   
Lib "user32" ( _
   
ByVal hwnd As Long _
   ) 
As Long
Private Declare Function ReleaseDC _
   
Lib "user32" ( _
   
ByVal hwnd As Long, _
   
ByVal hdc As Long _
   ) 
As Long
Private Type RGBQUAD
   rgbBlue 
As Byte
   rgbGreen 
As Byte
   rgbRed 
As Byte
   rgbReserved 
As Byte
End Type

Private Sub test1()
Dim varPixelarray As Collection
Dim strSource     As String
   
   strSource = Application.GetOpenFilename( _
      
"Pic Files (*.jpg;*.jpeg;*.bmp), *.jpg;*.jpeg;*.bmp" _
      )
   
If LCase(strSource) = "false" Or _
      LCase(strSource) = 
"falsch" Then Exit Sub

   
Set varPixelarray = ColFromPic( _
      LoadPicture(strSource))
      
   MsgBox 
"Red = " & varPixelarray("Infos")("Summe R") & vbCrLf & _
      
"Green = " & varPixelarray("Infos")("Summe G") & vbCrLf & _
      
"Blue = " & varPixelarray("Infos")("Summe B") & vbCrLf & _
      
"Breite = " & varPixelarray("Infos")("Breite") & vbCrLf & _
      
"Höhe = " & varPixelarray("Infos")("Höhe") & _
      vbCrLf & _
      
"Pixel 1,1 Rot = " & varPixelarray("AllPixel")(1, 1, 1) & _
      vbCrLf & _
      
"Pixel 1,1 Grün = " & varPixelarray("AllPixel")(1, 1, 2) & _
      vbCrLf & _
      
"Pixel 1,1 Blau = " & varPixelarray("AllPixel")(1, 1, 3)
      
      
End Sub

Public Function ColFromPic( _
   
ByVal lngPic As Long _
   ) 
As Collection
Dim audtRGB()                 As RGBQUAD
Dim alngStrukturen(1 To 10)   As Long
Dim abytPixel()               As Byte
Dim lngDC                     As Long
Dim i                         As Long
Dim k                         As Long
Dim curSumR                   As Currency
Dim curSumG                   As Currency
Dim curSumB                   As Currency
Dim colResult                 As New Collection
Dim colSummary                As New Collection

   
' ScreenDC ausleihen
   lngDC = GetDC(0)
   
   
'  Lange der Strukturen
   alngStrukturen(1) = 40
   
   
'Dimensionen ermitteln
   GetDIBits lngDC, lngPic, 0, 0, 
ByVal 0&, alngStrukturen(1), 0
      
   alngStrukturen(4) = &H200001
   
   
' Planes
   alngStrukturen(5) = 0
   
   
' Puffer bereitstellen
   
ReDim audtRGB(alngStrukturen(2) - 1, alngStrukturen(3) - 1)
   
   
' Warum auch immer, die negative Auzahl Scanzeilen
   alngStrukturen(3) = alngStrukturen(3) * -1
   
   
'  Array füllen
   GetDIBits lngDC, lngPic, 0, -alngStrukturen(3), _
      audtRGB(0, 0), alngStrukturen(1), 0
      
   
' DC zurückgeben
   ReleaseDC 0, lngDC
   
   
' Rückgabearray vorbereiten
   
ReDim abytPixel( _
      1 
To UBound(audtRGB, 1) + 1, _
      1 
To UBound(audtRGB, 2) + 1, _
      1 
To 3)
      
   
' Alle Pixel durchlaufen
   
For i = 0 To UBound(audtRGB, 1)
      
For k = 0 To UBound(audtRGB, 2)
         
With audtRGB(i, k)
         
            abytPixel(i + 1, k + 1, 1) = .rgbRed
            abytPixel(i + 1, k + 1, 2) = .rgbGreen
            abytPixel(i + 1, k + 1, 3) = .rgbBlue
            
            curSumR = curSumR + .rgbRed
            curSumG = curSumG + .rgbGreen
            curSumB = curSumB + .rgbBlue
            
         
End With
      
Next k
   
Next i
   
   
' Infos in eine Collection
   colSummary.Add curSumR, 
"Summe R"
   colSummary.Add curSumG, 
"Summe G"
   colSummary.Add curSumB, 
"Summe B"
   colSummary.Add 
UBound(audtRGB, 1) + 1, "Breite"
   colSummary.Add 
UBound(audtRGB, 2) + 1, "Höhe"
   
   
' Rückgabecollection vorbereiten
   colResult.Add colSummary, 
"Infos"
   colResult.Add abytPixel, 
"AllPixel"
   
   
' Zurückgeben
   
Set ColFromPic = colResult
   
End Function

 Hier der Code zum Aufsplitten eines Bildes:

 Option Explicit
Private Declare Function DeleteObject _
   
Lib "gdi32" ( _
   
ByVal hObject As Long _
   ) 
As Long
Private Declare Function CreateCompatibleBitmap _
   
Lib "gdi32" ( _
   
ByVal hdc As Long, _
   
ByVal nWidth As Long, _
   
ByVal nHeight As Long _
   ) 
As Long
Private Declare Function CreateCompatibleDC _
   
Lib "gdi32" ( _
   
ByVal hdc As Long _
   ) 
As Long
Private Declare Function SelectObject _
   
Lib "gdi32" ( _
   
ByVal hdc As Long, _
   
ByVal hObject As Long _
   ) 
As Long
Private Declare Function BitBlt _
   
Lib "gdi32" ( _
   
ByVal hDestDC As Long, _
   
ByVal As LongByVal As Long, _
   
ByVal nWidth As LongByVal nHeight As Long, _
   
ByVal hSrcDC As Long, _
   
ByVal xSrc As LongByVal ySrc As Long, _
   
ByVal dwRop As Long _
   ) 
As Long
Private Declare Function DeleteDC _
   
Lib "gdi32" ( _
   
ByVal hdc As Long _
   ) 
As Long
   
Private Const SRCCOPY = &HCC0020

Private Sub Teilen()
Dim lngDC1 As Long
Dim lngDC2 As Long

Dim objPic1 As StdPicture
Dim lngBMPOld1 As Long
Dim lngBMPOld2 As Long
Dim P2BIT As Long
Dim varPixelarray As Collection

   
' DC erstellen, der Kompatibel zum Screen ist
   lngDC1 = CreateCompatibleDC(0&)
   
' StdPicture-Objekt anlegen
   
' Quellbild ist 300 x 300 Pixel
   
Set objPic1 = LoadPicture("C:\GrünBraun3%.jpg")
   
' Bild in den DC stellen
   lngBMPOld1 = SelectObject(lngDC1, objPic1)
    
   
   
' Bitmap anlegen von 100 x 100 Pixel
   P2BIT = CreateCompatibleBitmap(lngDC1, 100, 100)
   
' DC erstellen, der Kompatibel zum Screen ist
   lngDC2 = CreateCompatibleDC(0&)
   
' Neu angelegte Bitmap in den neuen DC stellen
   lngBMPOld2 = SelectObject(lngDC2, P2BIT)


   
' Ausschnitt von Position 0,0 in der Größe 100 x 100
   
' in das Ziel kopieren (SRCCOPY) an Position 0,0
   
' Die Position beginnt links oben mit 0,0 und wird nach
   
' rechts und unten größer.
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 0, 0, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 2, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 100,0 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 100, 0, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 3, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 200,0 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 200, 0, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 4, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 0,100 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 0, 100, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 5, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 0,200 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 0, 200, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 6, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 100,100 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 100, 100, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 7, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 100,200 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 100, 200, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 8, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 200,100 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 200, 100, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 9, 30, varPixelarray("Infos")
   
   
' Ausschnitt von Position 200,200 in der Größe 100 x 100
   
' in das Ziel kopieren
   BitBlt lngDC2, 0, 0, 100, 100, lngDC1, 200, 200, SRCCOPY
   
Set varPixelarray = ColFromPic(P2BIT)
   Eintragen 
"Farbverteilung", 10, 30, varPixelarray("Infos")
   
   
   
   
' Originale Bitmap in den DC stellen
   SelectObject lngDC1, lngBMPOld1
   SelectObject lngDC2, lngBMPOld2
   
' Angelegte DC löschen
   DeleteDC lngDC2
   DeleteDC lngDC1
   
' Angelegte Bitmap löschen
   DeleteObject P2BIT
    


End Sub


Public Sub Eintragen( _
   strTabelle 
As String, _
   lngZielspalte 
As Long, _
   lngZielzeile 
As Long, _
   colInfo 
As Collection)
   
Dim dblEinProzent As Double
On Error GoTo Fehlerbehandlung

With Worksheets(strTabelle)

   .Cells(lngZielzeile, lngZielspalte).Value = colInfo(
"Breite")
   .Cells(lngZielzeile + 1, lngZielspalte).Value = colInfo(
"Höhe")
   
   .Cells(lngZielzeile + 2, lngZielspalte).Value = _
      
CDec(colInfo("Summe R"))
   .Cells(lngZielzeile + 3, lngZielspalte).Value = _
      
CDec(colInfo("Summe G"))
   .Cells(lngZielzeile + 4, lngZielspalte).Value = _
      
CDec(colInfo("Summe B"))
   
   dblEinProzent = colInfo(
"Summe R") + _
      colInfo(
"Summe G") + _
      colInfo(
"Summe B")
   dblEinProzent = dblEinProzent / 100
   
   .Cells(lngZielzeile + 5, lngZielspalte).Value = _
      
CDbl(colInfo("Summe R")) / dblEinProzent
   .Cells(lngZielzeile + 6, lngZielspalte).Value = _
      
CDbl(colInfo("Summe G")) / dblEinProzent
   .Cells(lngZielzeile + 7, lngZielspalte).Value = _
      
CDbl(colInfo("Summe B")) / dblEinProzent
      
End With

Exit Sub
Fehlerbehandlung:
MsgBox 
"Fehler beim Eintragen in Tabellenblatt"
End Sub