Ich habe nochmal etwas weiter dran gebastelt. Ich wollte hier auch schon von Beginn an darauf achten, das Programm sinnvoll zu strukturieren. Vielleicht habt ihr da noch Punkte zum Verbessern
Zum Einen benutze ich jetzt den sogenannten Floyd-Steinberg-Algorithmus und bekomme damit auf schwarz-weiß einen echten Eindruck der Helligkeit, der ursprünglichen Farbe. Außerdem gibt es jetzt eine Vorschau der Umwandlung. Also Bild rein, Vorschau wie es hinterher aussehen wird, und Ausgabe der Pixel als Binär-Darstellung. Im IrfanView kann man ein Bild auch mit dem Floyd-Steinberg Algorithmus bearbeiten. Das Ergebnis sieht dort anders aus. Die dunklen Stellen sind dunkler als bei mir. Das wisst ihr nicht zufällig noch, was man da noch für Einstellungen benutzen kann?
Form
Pixel
Die Algorithmus-Funktion Shared zu deklarieren hat mir das Studio empfohlen. Ob das irgendwas verbessert ist mir allerdings nicht bewusst, wenn man mehr als ein Form nutzt klar, aber mit nur einem Form macht es da einen Unterschied?
350.000 Pixel benötigen ~2 Sekunden zum verarbeiten. Aber das ist als Bild schon viel zu groß.
Zum Einen benutze ich jetzt den sogenannten Floyd-Steinberg-Algorithmus und bekomme damit auf schwarz-weiß einen echten Eindruck der Helligkeit, der ursprünglichen Farbe. Außerdem gibt es jetzt eine Vorschau der Umwandlung. Also Bild rein, Vorschau wie es hinterher aussehen wird, und Ausgabe der Pixel als Binär-Darstellung. Im IrfanView kann man ein Bild auch mit dem Floyd-Steinberg Algorithmus bearbeiten. Das Ergebnis sieht dort anders aus. Die dunklen Stellen sind dunkler als bei mir. Das wisst ihr nicht zufällig noch, was man da noch für Einstellungen benutzen kann?
VB.NET-Quellcode
- Friend Class Form1
- Private BitSet As List(Of List(Of Boolean))
- Private rowlength As Integer
- Private ReadOnly _pen As New Pen(Color.Black, 1)
- Private ReadOnly GP As New GraphicsPath
- Private Sub btnChoose_Click(sender As Object, e As EventArgs) Handles btnChoose.Click
- If OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
- Dim img1 = New Bitmap(OpenFileDialog1.FileName) 'Lesen
- SetBitsWith(img1) 'Verarbeiten
- img1.Dispose()
- SetPath() 'Zeichnen
- PictureBox1.Invalidate()
- End If
- End Sub
- Private Sub btnsave_Click(sender As Object, e As EventArgs) Handles btnsave.Click
- IO.File.WriteAllText("pfad", GetString()) 'Schreiben
- End Sub
- Private Sub SetBitsWith(bmp As Bitmap)
- rowlength = bmp.Width
- Dim LockedBitsImg1 = bmp.LockBits(New Rectangle(0, 0, bmp.Width, bmp.Height), Imaging.ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
- Dim rawdataImg1 = BytesFrom(LockedBitsImg1)
- bmp.UnlockBits(LockedBitsImg1)
- bmp.Dispose()
- FloydSteinbergToBitSet(DepictionOf(rawdataImg1))
- End Sub
- Private Function DepictionOf(data As Byte()) As List(Of List(Of Pixel))
- Dim Depictionrow As New List(Of Pixel)(CInt(data.Length / (4 * rowlength)))
- Dim Depiction As New List(Of List(Of Pixel))(rowlength)
- For i = 0 To data.Length - 1 Step 4 * rowlength
- If Depictionrow.Count > 0 Then Depictionrow = New List(Of Pixel)(CInt(data.Length / (4 * rowlength)))
- For j = i To i + 4 * rowlength - 1 Step 4
- Depictionrow.Add(New Pixel(data(j), data(j + 1), data(j + 2), data(j + 3)))
- Next
- Depiction.Add(Depictionrow)
- Next
- Return Depiction
- End Function
- Private Sub FloydSteinbergToBitSet(dp As List(Of List(Of Pixel)))
- dp = FloydSteinbergSW(dp)
- If BitSet Is Nothing Then
- BitSet = New List(Of List(Of Boolean))
- Else
- BitSet.Clear()
- End If
- Dim BitSetrow As New List(Of Boolean)
- Dim BlackPxl As New Pixel(0, 0, 0, 255)
- For y = 0 To dp.Count - 1
- If BitSetrow.Count > 0 Then BitSetrow = New List(Of Boolean)
- For x = 0 To dp(y).Count - 1
- BitSetrow.Add(dp(y)(x) = BlackPxl)
- Next
- BitSet.Add(BitSetrow)
- Next
- End Sub
- Private Shared Function FloydSteinbergSW(dp As List(Of List(Of Pixel))) As List(Of List(Of Pixel))
- Dim BlackPxl As New Pixel(0, 0, 0, 255)
- Dim WhitePxl As New Pixel(255, 255, 255, 255)
- Dim oldpixel, newpixel, pError As Pixel
- For y = 0 To dp.Count - 1 'Umgang mit Transparenz noch nicht entschieden, erstmal entfernen.
- For x = 0 To dp(y).Count - 1
- If dp(y)(x).Transparency <= 0 Then
- dp(y)(x) = WhitePxl
- Else
- dp(y)(x).Transparency = 255
- End If
- Next
- Next
- For y = 0 To dp.Count - 1
- For x = 0 To dp(y).Count - 1
- If dp(y)(x).Transparency = 0 Then dp(y)(x) = WhitePxl
- oldpixel = dp(y)(x)
- If oldpixel.BlackOrWhite Then 'Black True White False
- newpixel = BlackPxl
- Else
- newpixel = WhitePxl
- End If
- dp(y)(x) = newpixel
- pError = oldpixel - newpixel
- If x < dp(y).Count - 1 Then dp(y)(x + 1) += pError * 0.4375!
- If x > 0 AndAlso y < dp.Count - 1 Then dp(y + 1)(x - 1) += pError * 0.1875!
- If y < dp.Count - 1 Then dp(y + 1)(x) += pError * 0.3125!
- If x < dp(y).Count - 1 AndAlso y < dp.Count - 1 Then dp(y + 1)(x + 1) += pError * 0.0625!
- Next
- Next
- Return dp
- End Function
- Private Function BytesFrom(bmpDat As BitmapData) As Byte()
- Dim ptr As IntPtr = bmpDat.Scan0
- Dim bytes As Integer = Math.Abs(bmpDat.Stride) * bmpDat.Height
- Dim rgbValues(bytes - 1) As Byte
- System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)
- Return rgbValues
- End Function
- Private Function GetString() As String
- Dim strbBits As New Text.StringBuilder("")
- Dim addendum = 8 - rowlength Mod 8
- For i = 0 To BitSet.Count - 1
- For j = 0 To BitSet(i).Count - 1
- If BitSet(i)(j) Then
- strbBits.Append("1"c)
- Else
- strbBits.Append("0"c)
- End If
- Next
- strbBits.Append(String.Empty.PadLeft(addendum, "0"c))
- strbBits.Append(vbCrLf)
- Next
- Return strbBits.ToString
- End Function
- Private Sub SetPath()
- GP.Reset()
- For i = 0 To BitSet.Count - 1
- For j = 0 To BitSet(i).Count - 1
- Dim x = j * _pen.Width + CInt((PictureBox1.Width - BitSet(i).Count * _pen.Width) / 2)
- Dim y = i * _pen.Width + CInt((PictureBox1.Height - BitSet.Count * _pen.Width) / 2)
- If BitSet(i)(j) Then
- GP.AddLine(x, y, x + 0.1!, y)
- GP.CloseFigure()
- End If
- Next
- Next
- End Sub
- Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
- If BitSet IsNot Nothing AndAlso BitSet.Count > 0 Then e.Graphics.DrawPath(_pen, GP)
- End Sub
- Private Sub Form1_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
- _pen.Dispose()
- If GP IsNot Nothing Then GP.Dispose()
- End Sub
- End Class
VB.NET-Quellcode
- Friend Class Pixel
- Friend Property Red As Single
- Friend Property Green As Single
- Friend Property Blue As Single
- Friend Property Transparency As Byte
- Friend Sub New(B As Single, G As Single, R As Single, T As Byte)
- _Red = R
- _Green = G
- _Blue = B
- _Transparency = T
- End Sub
- Friend Function BlackOrWhite() As Boolean
- If Transparency = 0 Then Return False
- Dim Differenz = 255 - (Red + Green + Blue) / 3
- If Differenz <= 127 Then
- Return False
- Else
- Return True
- End If
- End Function
- Public Shared Operator -(first As Pixel, second As Pixel) As Pixel
- Return New Pixel(first.Blue - second.Blue, first.Green - second.Green, first.Red - second.Red, 255)
- End Operator
- Public Shared Operator +(first As Pixel, second As Pixel) As Pixel
- Return New Pixel(first.Blue + second.Blue, first.Green + second.Green, first.Red + second.Red, 255)
- End Operator
- Public Shared Operator *(px As Pixel, scalar As Single) As Pixel
- Return New Pixel(px.Blue * scalar, px.Green * scalar, px.Red * scalar, 255)
- End Operator
- Public Shared Operator =(first As Pixel, second As Pixel) As Boolean
- Return first.Blue = second.Blue AndAlso first.Red = second.Red AndAlso first.Green = second.Green AndAlso first.Transparency = second.Transparency
- End Operator
- Public Shared Operator <>(first As Pixel, second As Pixel) As Boolean
- Return Not first = second
- End Operator
- End Class
Die Algorithmus-Funktion Shared zu deklarieren hat mir das Studio empfohlen. Ob das irgendwas verbessert ist mir allerdings nicht bewusst, wenn man mehr als ein Form nutzt klar, aber mit nur einem Form macht es da einen Unterschied?
350.000 Pixel benötigen ~2 Sekunden zum verarbeiten. Aber das ist als Bild schon viel zu groß.
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()