Image aufhellen - aber wie?

  • VB.NET

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von egon.

    Image aufhellen - aber wie?

    Hallo,
    ich lade eine WMF-Bilddatei als Image und möchte es als PNG-File abspeichern. Das klappt soweit.
    Ich würde gerne das Bilde etwas noch aufhellen, habe aber keine Ahnung wie es geht. Könnt ihr mir hierbei weiterhelfen?
    Auch würde ich gerne einen Ausschnitt in ein neues Bild speichern.

    Mein bisheriger Code

    VB.NET-Quellcode

    1. Dim img As Image
    2. Dim img_klein As Image
    3. img = Image.FromFile("D:\PRINT9_korr.WMF")
    4. img_klein = New Bitmap(img, New Size(Convert.ToInt16(img.Width / 20),Convert.ToInt16((img.Height / 20))))
    5. img_klein.Save("D:\PRINT9_klein.png", Drawing.Imaging.ImageFormat.Png)


    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    @egon Entweder Du zerlegst das WMF und bearbeitest die Farben (würde ich Dir nicht empfehlen)
    oder
    Du gehst die Bitmap pixelweise durch, halbierst die R, G, B-Werte und addierst je 127.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Danke für den Hinweis.
    Letztlich hat deine Antwort zu einer leicht anderen Umsetzung geführt.

    VB.NET-Quellcode

    1. Function helligkeit(ByVal img As Bitmap, ByVal variable As Double) As Bitmap
    2. Dim imgneu As New Bitmap(img.Width, img.Height)
    3. Dim bmpp As Bitmap = DirectCast(img, Bitmap)
    4. Dim RR As Integer
    5. Dim GG As Integer
    6. Dim BB As Integer
    7. Try
    8. For x As Integer = 0 To img.Width - 1
    9. For y As Integer = 0 To img.Height - 1
    10. RR = img.GetPixel(x, y).R
    11. BB = img.GetPixel(x, y).B
    12. GG = img.GetPixel(x, y).G
    13. RR = Convert.ToInt16(RR * variable) : If RR > 255 Then RR = 255
    14. BB = Convert.ToInt16(BB * variable) : If BB > 255 Then BB = 255
    15. GG = Convert.ToInt16(GG * variable) : If GG > 255 Then GG = 255
    16. imgneu.SetPixel(x, y, Color.FromArgb(RR, GG, BB))
    17. Next
    18. Next
    19. Catch ex As Exception
    20. Me.Text = ex.ToString
    21. End Try
    22. Return imgneu
    23. End Function

    RodFromGermany schrieb:

    @egon Entweder Du zerlegst das WMF und bearbeitest die Farben (würde ich Dir nicht empfehlen)
    oder
    Du gehst die Bitmap pixelweise durch, halbierst die R, G, B-Werte und addierst je 127.


    Oder man nutzt eine ColorMatrix + ImageAttribute und zeichnest das Bild.

    VB.NET-Quellcode

    1. Private Bmp As New Bitmap("PATH")
    2. Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    3. Dim Opacity_ As Single = 1.0F
    4. Dim Britghness As Single = 0.5F '0.0F changes nothing 1.0f = invisible, -0.5f is darker
    5. Dim Contrast As Single = 1.0F
    6. Dim matrix()() As Single = {New Single() {Contrast, 0, 0, 0, 0},
    7. New Single() {0, Contrast, 0, 0, 0},
    8. New Single() {0, 0, Contrast, 0, 0},
    9. New Single() {0, 0, 0, Opacity_, 0},
    10. New Single() {Britghness, Britghness, Britghness, 0, 1}}
    11. Dim colorMatrix As Imaging.ColorMatrix = New ColorMatrix(matrix)
    12. Dim imageAtt As ImageAttributes = New ImageAttributes()
    13. imageAtt.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
    14. e.Graphics.DrawImage(Bmp, New Rectangle(0, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, imageAtt)
    15. End Sub

    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Wie kann man eigentlich die Geschwindigkeit der ganzen Routine mit mehreren Zwischenergebnissen bestimmen. Letztlich wird die WMF Datein in eine PNG Datei umgewandelt, die Größe und Helligkeit werden gewandelt, wieder als PNG abgespeichert und dann mit optpng das PNG-File optimiert und verkleinert. Das wird dann für merhrere Auflösungen wiederholt. Die Ausführung der gesammten Routine ist noch optimierungswürdig.
    Z.B. so:

    VB.NET-Quellcode

    1. Private Sub Gage()
    2. Dim ticker As New Stopwatch
    3. ticker.Start()
    4. Threading.Thread.Sleep(1000)
    5. Debug.WriteLine(ticker.Elapsed.ToString())
    6. Threading.Thread.Sleep(1000)
    7. Debug.WriteLine(ticker.Elapsed.ToString())
    8. End Sub


    Kannst mal ja 100 durchläufe mit Get/Setpixel machen und 100 mal mit dem gleichen! Bild die variante mit der ColorMatrix.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin
    Es wird sofort deutlich, dass meine Routine gnadenlos zu langsam ist. Könntest du mir bitte deine Version erklären.
    Wie muss ich die letzte Zeile anpassen? e.Graphics.DrawImage(Bmp, New Rectangle(0, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, imageAtt)
    Was bedeutet die Endung 0.5F ?
    Dein Code erzeugt bei mir noch Fehler. Wie muss noch richtig definiert werden?
    Bilder
    • fehler.png

      26,96 kB, 929×244, 106 mal angesehen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „egon“ ()

    Also 0.5 kann sowohl Single, Decimal wie auch Double sein, 0.5F das F steht hier für Float, in z.B. C/C++ ist Float = Single. Durch das f ist es explizit ein Float/Single, 0.5D z.B. wäre Double, weitere Variationen mit ganzzahligen Typen:

    VB.NET-Quellcode

    1. Dim i As Integer = 1I
    2. Dim s As Short = 1S
    3. Dim l As Long = 1L


    Ich zeige dir nun auf wie du ein Bild "in" ein anderes zeichnest, den rest solltest du dann hinbekommen.

    VB.NET-Quellcode

    1. Private Sub EditImage()
    2. Using bmp1 As New Bitmap("Path")
    3. Using bmp2 As New Bitmap(bmp1.Width, bmp1.Height)
    4. Using g As Graphics = Graphics.FromImage(bmp2)
    5. g.DrawImage(bmp1, 0, 0, bmp2.Width, bmp2.Height)
    6. bmp2.Save("Other Path", ImageFormat.Png)
    7. End Using
    8. End Using
    9. End Using
    10. End Sub

    Edit: @egon hab noch mal editiert.
    Importiere "System.Drawing.Imaging" oder änder das so ab "System.Drawing.Imaging.ColorMatrix". Die Fehlerkorrektur-Hilfe(cursor auf die Linie) sollte dir dies aber vorschlagen, zumindest mit dem abändern, da ich die ColorMatrix colorMatrix nannte(achte auf die gross/kleinschrift), der Import wurde deswegen nicht vorgeschlagen.
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „NoIde“ ()

    egon schrieb:

    Das wird dann für merhrere Auflösungen wiederholt.


    Das hatte ich garnicht beachtet, also warum nicht direkt alle grössen in einem Rutsch machen? Spart etwas Zeit ein, da nicht immer das Original-Bild neu geladen wird. Mann könnte das auch in einer For-Schleife machen, die grössen in einem Array sichern, bleibt der Code sogar kurz.(Die Schleife im Scope von bmp_original)

    VB.NET-Quellcode

    1. Private Sub EditImage()
    2. Using bmp_original As New Bitmap("Path")
    3. Using bmp_originalsize As New Bitmap(bmp_original.Width, bmp_original.Height)
    4. Using g As Graphics = Graphics.FromImage(bmp_originalsize)
    5. g.DrawImage(bmp_original, 0, 0, bmp_originalsize.Width, bmp_originalsize.Height)
    6. bmp_originalsize.Save("Other Path", ImageFormat.Png)
    7. End Using
    8. End Using
    9. Using bmp_halfsize As New Bitmap(bmp_original.Width \ 2, bmp_original.Height \ 2)
    10. Using g As Graphics = Graphics.FromImage(bmp_halfsize)
    11. g.DrawImage(bmp_original, 0, 0, bmp_halfsize.Width, bmp_halfsize.Height)
    12. bmp_halfsize.Save("An Other Path", ImageFormat.Png)
    13. End Using
    14. End Using
    15. End Using
    16. End Sub

    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „NoIde“ ()

    Das ist ein tolles Beispielprojekt um die Wirkung und Power der ColorMatrix zu verdeutlichen. :thumbup:
    Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
    „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
    Benjamin Franklin

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „NoIde“ ()

    ColorMatrix ist ne ganz gewöhnliche Matrix die man mit den Farben welche in dem Fall einfach als Vektoren( mit float werten zwischen 0 und 1) multipliziert wird.
    Ne Brightness Matrix ist dabei einfach das hier:

    Quellcode

    1. br 0 0 0
    2. 0 br 0 0
    3. 0 0 br 0
    4. 0 0 0 1

    wofür sorgt das z.B. wenn ich den Vektor (r,g,b,a) verwende und den it dieser Matrix multiplizier? Ganz einfach:

    Quellcode

    1. (r*br,g*br,b*br,a)

    Also nichts anderes als deine obige Multiplikation. Natürlich wird da auch noch viel 0*x und +0 etc gemacht, was einige unnötige Berechnungen sind. Beiim zeichnen wird auch noch alles mögliche überprüft und das ganze um am Ende den Code den du oben quasi hast in einer etwas leicht verbesserten Form zu machen.

    Das Problem was deinen Code so langsam macht ist GetPixel/SetPixel, weil das für jeden Pixel einzeln das komplette Bild für jeglichen Bearbeitungszugriff sperrt und am Ende wieder entsperrt, das ist sehr viel unnötiges hin und her. Macht man das ganze einmal dann wirst du die performance fliegen sehen.

    Schau dafür mal nach dem Thema LockBits.

    Ob das ganze am Ende des Tages dann schneller ist oder nicht lässt sich nur testen, denn viele der GDI+ Teile und damit auch das anwenden der ColorMatrix sind in C implementiert, was eventuell zu besser optimiertem Code führt. Aber ich würde vermuten, dass mit LockBits und direktbearbeitung ohne Pixelkopierung schneller seiin sollte. Da kommen wir dann aber schon an die grenzen von VB.Net und müssten C# verwenden^^
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Ich bedanke mich für eure Antworten. Das mit der Matrix ist schon ziemlich elegant und schnell. Mithilfe der Matrix ist der Code jetzt schnell genug geworden.
    Jetzt bremst nur noch das nachfolgende Verkleinern der PNG-Dateien mit "optipng.exe -o1 [Dateiname]". Das kann ich aber nicht mehr beeinflussen und betrachte daher diesen Teil des Projektes als abgeschlossen.

    egon schrieb:

    das nachfolgende Verkleinern der PNG-Dateien
    ist doch auch nur ein 5-Zeiler.
    Was passiert da?
    Was genau macht die Exe?
    Ist die von Dir?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Nein das Programm "OptiPNG" ist ein PNG Optimierer der die Größe von PNG-Dateien deutlich reduziert. Er hat nur den Nachteil nicht besonders schnell zu sein. Bei meinen kleinen Dateien macht sich das aber nur begrenzt bemerkbar (0,7s für die Bearbeitung und Optimierung von sechs Bilder am schnellen Rechner) und die geringste Kompressionsstufe erzeugt auch schon sehr kleine Dateien. Die ursprüngliche WMF-Datei wird als Hardcopy von einem Messgerät geliefert und an mein PC-Programm geschickt. Aus den 300kB (WMF) werden nun 8kB (PNG optimiert). Das ist schön klein und bläht auch ein größeres Word-Dokument für das die Bilder erzeugt werden nicht auf.
    Quelle für "OptiPNG": optipng.sourceforge.net/
    Hier einige Hintergrundinformationen: optipng.sourceforge.net/pngtech/optipng.html
    Ich habe OptiPNG auch in mein Zeichenprogramm pint.net eingebunden - das ist aber eine andere Geschichte. Bei großen png-Dateien dauerert es dann auch schon mal einige Sekunden. Ungewohnt in der heutigen Zeit. ;)

    Ich habe bisher noch keine Möglichkeit gefunden die PNG-Optimierung direkt über eine Bibliothek einzubinden. Mit ist nur der Umweg über die .exe bekannt.

    VB.NET-Quellcode

    1. Try
    2. Dim proc As Process = New Process()
    3. proc.StartInfo.FileName = "optipng.exe"
    4. proc.StartInfo.Arguments = "-o1 " + Zielpfad + "\" + ZielDateinamePNG + "_640x480_hell.png"
    5. proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
    6. proc.Start()
    7. proc.WaitForExit()
    8. Catch ex As Exception
    9. Console.WriteLine("Komprimierung fehlerhaft")
    10. End Try ' Ende Bilder heller, abspeichern, optimieren

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „egon“ ()