Bild beschneiden, in der Größe verkleinern und aufhellen

  • VB.NET
  • .NET 4.5

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Bild beschneiden, in der Größe verkleinern und aufhellen

    Hallo Leute,

    ich stehe vor der Herausforderung einer Mini-Produktbildbearbeitung und würde mich da über Ideen und Anregungen für die Umsetzung sehr freuen.

    Was ich vor habe:
    * Kunden sollen Produktbilder in einem Lichtzelt aufnehmen (Produkt auf weißem Hingergrund) (FUNKTIONIERT BEREITS)
    * Rohbilder (JPG) per Drag and Drop in meine Anwendung ziehen (FUNKTIONIERT BEREITS)
    * Bilder sollen in eine Datei gespeichert werden (FUNKTIONIERT BEREITS)
    * Bilder sollen nun folgendermaßen bearbeitet werden:
    - Größe der Bilder (welche meist 3000 Pixel breit sind) auf 800 Pixel Breite bringen
    - weiße Flächen rund um die Objekte automatisch entfernen (siehe Bild anbei)
    - das Bild insgesamt aufhellen (mehr Belichtung)

    * Bilder sollen in den Webshop hochgeladen werden (FUNKTIONIERT BEREITS)

    Legende:
    Schwarz = hab ich schon lauffähig und funktioniert bereits
    Blau = wäre ein Zusatzgoodie, welches ich gerne umsetzen würde.

    Nun stellt sich die Frage wie ich an diese Aufgabenstellung (blau) am Besten herangehe.
    Bilder verkleinern hatte ich schon mal - das wäre wohl noch die einfachere Aufgabe.
    Beim Zuschneiden des weißen Bereiches hätte ich mir vorgestellt von außen nach innen Reihen und Spalten von Pixeln auszulesen und sobald man auf einen dunklen Bereich kommt dort dann aufhört und zuschneidet. Aber wie ich das mache, habe ich keine Ahnung. Das Bild insgesamt aufhellen - keine Ahnung wie.

    Habt Ihr dafür Lösungen oder Ideen?

    LG Roland

    *Topic verschoben*
    Bilder
    • produktfoto_image.jpg

      62,63 kB, 1.000×750, 23 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Bei der Entwicklung meiner Anwendung(en) steht nicht "Code nach .NET Lehrbuch" im Vordergrund, sondern eine stabile und brauchbare Anwendung die der Anwender ordentlich verwenden kann. Usability für den Kunden und Supportbarkeit beim Kunden stehen an oberster Stelle. Das spiegelt sich auch in meinen Fragen und Antworten wider. Bitte verzeiht, dass meine VB.NET Quellcodes etwas VB6-lastig sind aber das ist für das funktionierende Endergebnis nicht wirklich relevant.

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

    Hallo Leute,

    da heute wohl alle Fasching feiern und ich scheinbar als einziger am Schreibtisch sitze, habe ich meine grauen Zellen selbst mal angestrengt und zwei von drei Punkten erledigt.

    Wie Ihr am Screenshot anbei erkennen könnt, kann ich die Helligkeit schon einmal stufenlos ändern und auch die Bildgröße auf ein gewünschtes Maximalmaß bringen.
    Hier der Hauptkern der Funktion:

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Kopiert das Bild einer Picturebox in eine andere und passt die Helligkeit (Werte -1 bis +1) an und bringt die Bildgröße auf eine Maximalgröße (MaxBreite)
    3. ''' Das Bildverhältnis wird dabei beibehalten.
    4. ''' </summary>
    5. ''' <param name="Brightness"></param>
    6. ''' <param name="OriginalBildBox"></param>
    7. ''' <param name="ZielBildBox"></param>
    8. ''' <param name="MaxBreite"></param>
    9. ''' <remarks></remarks>
    10. Sub ModifyPicture(ByVal Brightness As Single, OriginalBildBox As PictureBox, ZielBildBox As PictureBox, MaxBreite As Integer)
    11. Dim g As Graphics
    12. Dim img As Image
    13. Dim r As Rectangle
    14. Dim Ratio As Double = 1
    15. Dim Breite As Integer = OriginalBildBox.Image.Width
    16. Dim Hoehe As Integer = OriginalBildBox.Image.Height
    17. 'Bildverhältnis beibehalten und Bild verkleinern, falls größer als Maximalbreite
    18. If breite > MaxBreite Then
    19. Ratio = 1 / breite * MaxBreite 'ergibt eine 0,irgendwas Zahl
    20. breite = MaxBreite
    21. hoehe = CInt(hoehe * Ratio)
    22. End If
    23. img = OriginalBildBox.Image
    24. ZielBildBox.Image = New Bitmap(breite, hoehe, PixelFormat.Format32bppArgb)
    25. g = Graphics.FromImage(ZielBildBox.Image)
    26. r = New Rectangle(0, 0, breite, hoehe)
    27. g.DrawImage(img, r)
    28. Dim colorMatrixVal As Single()() = { _
    29. New Single() {1, 0, 0, 0, 0}, _
    30. New Single() {0, 1, 0, 0, 0}, _
    31. New Single() {0, 0, 1, 0, 0}, _
    32. New Single() {0, 0, 0, 1, 0}, _
    33. New Single() {Brightness, Brightness, Brightness, 0, 1}}
    34. Dim colorMatrix As New ColorMatrix(colorMatrixVal)
    35. Dim ia As New ImageAttributes
    36. ia.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
    37. g.DrawImage(img, r, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, ia)
    38. ZielBildBox.Refresh()
    39. End Sub


    Nun werde ich mich daran machen, das Problem mit dem automatischen Beschneiden zu lösen ;)

    LG Roland
    Bilder
    • 05032019142020.jpg

      181,62 kB, 813×569, 22 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Bei der Entwicklung meiner Anwendung(en) steht nicht "Code nach .NET Lehrbuch" im Vordergrund, sondern eine stabile und brauchbare Anwendung die der Anwender ordentlich verwenden kann. Usability für den Kunden und Supportbarkeit beim Kunden stehen an oberster Stelle. Das spiegelt sich auch in meinen Fragen und Antworten wider. Bitte verzeiht, dass meine VB.NET Quellcodes etwas VB6-lastig sind aber das ist für das funktionierende Endergebnis nicht wirklich relevant.
    @dive26 Definiere Beschneiden.
    Das Bild insgasamt verkleinern / vergrößern geht so:

    VB.NET-Quellcode

    1. ' neue Bröße
    2. Dim imgWidth = 1278
    3. Dim imgHeight = 958
    4. ' Bitmap-Objekt in der neuen Größe erstellen
    5. Dim imgDest As New Bitmap(imgWidth, imgHeight)
    6. ' Bild interpolieren, damit die Qualität erhalten bleibt
    7. Using g As Graphics = Graphics.FromImage(imgDest)
    8. g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
    9. g.DrawImage(MyImgSource, New Rectangle(0, 0, imgWidth, imgHeight))
    10. End Using
    11. ' imgDest verwenden
    Wenn Du vom Bild einen (halbwegs) einfarbigen Rand abschneiden willst, musst Du alle paar Zeilen / Spalten von außen nach innen die erste relevante Farbveränderung suchen.
    Aus diese Koordinaten für jede Seite generierst Du Dir den Schneiderand und los.
    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).
    VB-Fragen über PN / Konversation werden ignoriert!
    @RodFromGermany
    Bild "kleiner" machen habe ich ja oben im Code schon. Was ich jetzt (schon gemacht habe), ist, automatisch alle weißen Flächen rund um das Bild entfernen - also das Produkt automatisch "freistellen". Das hab ich nun auch fertig. Das Ergebnis kannst im Screenshot unten sehen. Aus einem sehr dunklen Produktfoto wurde ein helles freigestelltes Produktfoto.

    Beim Freistellen bin ich den Weg gegangen alle Pixel von oben nach unten durchzulaufen und deren Helligkeitswert zu prüfen. Kommt ein dunklerer Pixel, dann wird zur Sicherheit noch der nächste Pixel abgefragt. Ist dieser auch dunkler, dann beginnt da wohl das Objekt und ich schneide ein paar Pixel vorher ab.
    Dies mache ich von allen vier Himmelsrichtungen und habe somit ein freigestelltes Objekt.
    Natürlich geht das Freistellen nur gut, wenn der Helligkeitswert des Hintergrundes stimmt - also annähernd weiß ist (90% Helligkeit).

    Hier der Code, der sicher noch optimiert werden könnte, aber vorerst einmal so funktioniert:
    (Der Parameter Schwellwert wurde noch nicht implementiert - vielleicht programmiere ich da noch einen Schwellwertregler der die 90% Helligkeit variabel regeln lässt.)

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Schneidet helle Bereiche um das Bild automatisch ab
    3. ''' </summary>
    4. ''' <param name="BildBox"></param>
    5. ''' <param name="Schwellwert"></param>
    6. ''' <remarks></remarks>
    7. Public Sub Beschneidebild(BildBox As PictureBox, Schwellwert As Integer)
    8. Dim BildZeilen As Integer = BildBox.Image.Height
    9. Dim BildSpalten As Integer = BildBox.Image.Width
    10. Dim BeschneideOben As Integer = 0
    11. Dim BeschneideUnten As Integer = BildZeilen
    12. Dim BeschneideLinks As Integer = 0
    13. Dim BeschneideRechts As Integer = BildSpalten
    14. 'von oben nach unten alle Pixel kontrollieren
    15. Dim MyBitmap As New Bitmap(BildBox.Image)
    16. Dim curPixColor As Color
    17. Dim PixelHelligkeit As Single = 1
    18. Dim ObjektGefunden As Boolean = False
    19. 'Von oben nach unten "scannen"
    20. ObjektGefunden = False
    21. For zeile As Integer = 1 To BildZeilen - 1
    22. If ObjektGefunden = True Then Exit For
    23. For spalte As Integer = 1 To BildSpalten - 1
    24. curPixColor = MyBitmap.GetPixel(spalte, zeile)
    25. PixelHelligkeit = curPixColor.GetBrightness()
    26. If PixelHelligkeit < 0.9 Then
    27. 'Prüfen ob das nächste Pixel auch dunkel ist, wenn ja, dann erst als Objekt identifizieren
    28. curPixColor = MyBitmap.GetPixel(spalte + 1, zeile)
    29. PixelHelligkeit = curPixColor.GetBrightness()
    30. If PixelHelligkeit < 0.9 Then
    31. ObjektGefunden = True
    32. BeschneideOben = zeile - 3
    33. If BeschneideOben < 0 Then BeschneideOben = 0
    34. Exit For
    35. End If
    36. End If
    37. Next spalte
    38. Next zeile
    39. 'Von links nach rechts "scannen"
    40. ObjektGefunden = False
    41. For spalte As Integer = 1 To BildSpalten - 1
    42. If ObjektGefunden = True Then Exit For
    43. For zeile As Integer = 1 To BildZeilen - 1
    44. curPixColor = MyBitmap.GetPixel(spalte, zeile)
    45. PixelHelligkeit = curPixColor.GetBrightness()
    46. If PixelHelligkeit < 0.9 Then
    47. 'Prüfen ob das nächste Pixel auch dunkel ist, wenn ja, dann erst als Objekt identifizieren
    48. curPixColor = MyBitmap.GetPixel(spalte, zeile + 1)
    49. PixelHelligkeit = curPixColor.GetBrightness()
    50. If PixelHelligkeit < 0.9 Then
    51. ObjektGefunden = True
    52. BeschneideLinks = spalte - 3
    53. If BeschneideLinks < 0 Then BeschneideLinks = 0
    54. Exit For
    55. End If
    56. End If
    57. Next zeile
    58. Next spalte
    59. 'Von unten nach oben "scannen"
    60. ObjektGefunden = False
    61. For zeile As Integer = BildZeilen - 1 To 1 Step -1
    62. If ObjektGefunden = True Then Exit For
    63. For spalte As Integer = 1 To BildSpalten - 1
    64. curPixColor = MyBitmap.GetPixel(spalte, zeile)
    65. PixelHelligkeit = curPixColor.GetBrightness()
    66. If PixelHelligkeit < 0.9 Then
    67. 'Prüfen ob das nächste Pixel auch dunkel ist, wenn ja, dann erst als Objekt identifizieren
    68. curPixColor = MyBitmap.GetPixel(spalte, zeile - 1)
    69. PixelHelligkeit = curPixColor.GetBrightness()
    70. If PixelHelligkeit < 0.9 Then
    71. ObjektGefunden = True
    72. BeschneideUnten = zeile + 3
    73. If BeschneideUnten > BildZeilen Then BeschneideUnten = BildZeilen - 1
    74. Exit For
    75. End If
    76. End If
    77. Next spalte
    78. Next zeile
    79. 'Von rechts nach links "scannen"
    80. ObjektGefunden = False
    81. For spalte As Integer = BildSpalten - 1 To BeschneideLinks + 1 Step -1
    82. If ObjektGefunden = True Then Exit For
    83. For zeile As Integer = 1 To BildZeilen - 1
    84. curPixColor = MyBitmap.GetPixel(spalte, zeile)
    85. PixelHelligkeit = curPixColor.GetBrightness()
    86. If PixelHelligkeit < 0.9 Then
    87. 'Prüfen ob das nächste Pixel auch dunkel ist, wenn ja, dann erst als Objekt identifizieren
    88. curPixColor = MyBitmap.GetPixel(spalte, zeile + 1)
    89. PixelHelligkeit = curPixColor.GetBrightness()
    90. If PixelHelligkeit < 0.9 Then
    91. ObjektGefunden = True
    92. BeschneideRechts = spalte + 3
    93. If BeschneideRechts > BildSpalten - 1 Then BeschneideRechts = BildSpalten - 1
    94. Exit For
    95. End If
    96. End If
    97. Next zeile
    98. Next spalte
    99. 'Bildmaße entsprechend anpassen
    100. BeschneideUnten -= BeschneideOben
    101. BeschneideRechts -= BeschneideLinks
    102. 'Hier Beschneiden
    103. Dim CropRect As New Rectangle(BeschneideLinks, BeschneideOben, BeschneideRechts, BeschneideUnten)
    104. Dim OriginalImage = BildBox.Image
    105. Dim CropImage = New Bitmap(CropRect.Width, CropRect.Height)
    106. Using grp = Graphics.FromImage(CropImage)
    107. grp.DrawImage(OriginalImage, New Rectangle(0, 0, CropRect.Width, CropRect.Height), CropRect, GraphicsUnit.Pixel)
    108. OriginalImage.Dispose()
    109. BildBox.Image = New Bitmap(CropRect.Width, CropRect.Height, PixelFormat.Format32bppArgb)
    110. BildBox.Image = CropImage
    111. BildBox.Refresh()
    112. End Using
    113. End Sub

    Bilder
    • 05032019171153.jpg

      186,64 kB, 691×571, 17 mal angesehen
    • 05032019171313.jpg

      168,18 kB, 689×573, 15 mal angesehen
    • 05032019171410.jpg

      192,78 kB, 687×570, 13 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Bei der Entwicklung meiner Anwendung(en) steht nicht "Code nach .NET Lehrbuch" im Vordergrund, sondern eine stabile und brauchbare Anwendung die der Anwender ordentlich verwenden kann. Usability für den Kunden und Supportbarkeit beim Kunden stehen an oberster Stelle. Das spiegelt sich auch in meinen Fragen und Antworten wider. Bitte verzeiht, dass meine VB.NET Quellcodes etwas VB6-lastig sind aber das ist für das funktionierende Endergebnis nicht wirklich relevant.
    @RodFromGermany
    Danke, alles erledigt. Manchmal frage ich einfach zu früh und kanns dann doch irgendwie selbst.
    Möglicherweise möchte ein Admin dies in Tips & Tricks kopieren. Vielleicht sucht mal jemand sowas.
    Liebe Grüße
    Roland Berghöfer

    Bei der Entwicklung meiner Anwendung(en) steht nicht "Code nach .NET Lehrbuch" im Vordergrund, sondern eine stabile und brauchbare Anwendung die der Anwender ordentlich verwenden kann. Usability für den Kunden und Supportbarkeit beim Kunden stehen an oberster Stelle. Das spiegelt sich auch in meinen Fragen und Antworten wider. Bitte verzeiht, dass meine VB.NET Quellcodes etwas VB6-lastig sind aber das ist für das funktionierende Endergebnis nicht wirklich relevant.

    dive26 schrieb:

    Möglicherweise möchte ein Admin dies in Tips & Tricks kopieren.
    Du kannst dort selbst einen Thread erstellen, der muss dann allerdings von einem Moderator freigeschaltet werden..
    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).
    VB-Fragen über PN / Konversation werden ignoriert!