Bild automatisch zuschneiden

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von FormFollowsFunction.

    @Goof Dann musst Du die weißen Zeilen und Spalten zählen und daraus mit der Größe des Bildes den abzuschneidenden Rand ermitteln.
    Erstelle eine Bitmap der Zielgröße,
    davon holst Du Dir ein Graphics-Objekt
    und malst mit der richtigen Überladung von DrawImage() Dein Bild ohne Rand rein.
    Feddich.
    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!
    Den ersten Teil habe ich:


    Dim fileName = "C:\file.jpg"
    Dim CropRect As New Rectangle(100, 0, 100, 100)
    Dim OriginalImage = Image.FromFile(fileName)
    Dim CropImage = New Bitmap(CropRect.Width, CropRect.Height)
    Using grp = Graphics.FromImage(CropImage)
    grp.DrawImage(OriginalImage, New Rectangle(0, 0, CropRect.Width, CropRect.Height), CropRect, GraphicsUnit.Pixel)
    OriginalImage.Dispose()
    CropImage.Save(fileName)
    End Using


    Hier scheint es den Rest zu geben :)

    through-the-interface.typepad.…-bitmap-more-quickly.html

    Quellcode:
    through-the-interface.typepad.…lipboardManager-1.0.5.zip

    Wie bekomme ich das zusammen?


    Imports System.Drawing
    Imports System.Drawing.Imaging
    Imports System.Runtime.InteropServices

    Public Class ImageFunctions

    Public Shared Function SameColor(ByVal a As Color, ByVal b As Color) As Boolean
    Return (a.R = b.R And a.G = b.G And a.B = b.B)
    End Function

    Public Shared Function MostCommonColor(ByVal cols() As Color) As Color

    ' Use a dictionary to count our colors

    Dim cd As Dictionary(Of Color, Integer) = _
    New Dictionary(Of Color, Integer)

    ' Loop through the array, adding them one by one

    For Each col In cols

    If cd.ContainsKey(col) Then
    cd.Item(col) += 1
    Else
    cd.Add(col, 1)
    End If
    Next

    ' Now go through the dictionary and get the
    ' most popular color

    Dim max As Integer = 0
    Dim mostCommon As Color = Color.Black

    For Each kv In cd
    If kv.Value > max Then
    max = kv.Value
    mostCommon = kv.Key
    End If
    Next

    Return mostCommon

    End Function

    Public Shared Function Crop(ByVal b As Bitmap, ByVal bg As Color) As Bitmap

    ' Variables for the area to crop down to

    Dim left As Integer = b.Width
    Dim top As Integer = b.Height
    Dim right As Integer = 0
    Dim bottom As Integer = 0

    ' Indeces and the current pixel

    Dim x, y As Integer
    Dim c As Color

    If bg = Nothing Then

    ' If we don't have a background passed in, get the four
    ' corners' colors and find the most common of them

    Dim cols() As Color = { _
    b.GetPixel(0, 0), _
    b.GetPixel(0, b.Height - 1), _
    b.GetPixel(b.Width - 1, 0), _
    b.GetPixel(b.Width - 1, b.Height - 1)}

    bg = MostCommonColor(cols)

    End If

    ' Loop through each pixel

    For y = 0 To b.Height - 1
    For x = 0 To b.Width - 1
    c = b.GetPixel(x, y)

    ' If it's not the same as the background color

    If Not SameColor(c, bg) Then

    ' Then we update our variables, as appropriate

    If x < left Then left = x
    If y < top Then top = y
    If x > right Then right = x
    If y > bottom Then bottom = y
    End If
    Next x
    Next y

    ' Now calculate the dimensions of the cropped output

    Dim width As Integer = (right - left)
    Dim height As Integer = (bottom - top)

    ' Add a buffer of 5% of the largest dimension (a little padding)

    Dim buffer As Integer = Math.Max(width, height) * 0.05
    width += 2 * buffer
    height += 2 * buffer

    ' Create the new bitmap and the graphics object to draw to it

    Dim cropped As New Bitmap(width, height)
    Dim gfx As Graphics = Graphics.FromImage(cropped)
    Using gfx

    ' Set the color of the bitmap to our background

    gfx.Clear(bg)

    ' Draw the portion of the original image that we want to
    ' the new bitmap

    gfx.DrawImage( _
    b, New Rectangle(buffer, buffer, width, height), _
    New Rectangle(left, top, width, height), _
    GraphicsUnit.Pixel)
    End Using

    Return cropped

    End Function

    Public Shared Function GetPixel( _
    ByVal bd As BitmapData, _
    ByVal pf As PixelFormat, _
    ByVal x As Integer, ByVal y As Integer) As Color

    ' A counter and the RGB values of our color

    Dim idx, R, G, B As Integer

    If pf = PixelFormat.Format16bppRgb565 Then

    ' Variables for the raw bytes

    Dim bt1, bt2 As Byte

    ' Our pixels span 2 bytes - read them in

    idx = (bd.Stride * y) + (2 * x)
    bt1 = Marshal.ReadByte(bd.Scan0, idx)
    bt2 = Marshal.ReadByte(bd.Scan0, idx + 1)

    ' The first five bits define R

    R = ((bt1 And 245) >> 3) * 255 / 31

    ' Then next 6 define G

    G = (((bt1 And 7) << 3) + ((bt2 And 224) >> 5)) * 255 / 63

    ' And the last 5 define B

    B = (bt2 And 31) * 255 / 31

    ElseIf pf = PixelFormat.Format32bppRgb Then

    ' Our pixels span 4 bytes - only the first 3 are used

    idx = (bd.Stride * y) + (4 * x)
    R = Marshal.ReadByte(bd.Scan0, idx)
    G = Marshal.ReadByte(bd.Scan0, idx + 1)
    B = Marshal.ReadByte(bd.Scan0, idx + 2)

    End If

    Return Color.FromArgb(R, G, B)

    End Function

    Public Shared Function OptiCrop( _
    ByVal b As Bitmap, ByVal bg As Color) As Bitmap

    ' We only support 16- and 32-bit color bitmap encoding

    If b.PixelFormat <> PixelFormat.Format16bppRgb565 And _
    b.PixelFormat <> PixelFormat.Format32bppRgb Then
    Return b
    End If

    ' Variables for the area to crop down to

    Dim left As Integer = b.Width
    Dim top As Integer = b.Height
    Dim right As Integer = 0
    Dim bottom As Integer = 0

    ' Indeces and the current pixel

    Dim x, y As Integer
    Dim c As Color

    ' Lock the bitmap's memory for reading

    Dim bd As BitmapData = _
    b.LockBits( _
    New Rectangle(New Point(), b.Size), _
    ImageLockMode.ReadOnly, b.PixelFormat)

    If bg = Nothing Then

    ' If we don't have a background passed in, get the four
    ' corners' colors and find the most common of them

    Dim cols() As Color = { _
    GetPixel(bd, b.PixelFormat, 0, 0), _
    GetPixel(bd, b.PixelFormat, 0, b.Height - 1), _
    GetPixel(bd, b.PixelFormat, b.Width - 1, 0), _
    GetPixel(bd, b.PixelFormat, b.Width - 1, b.Height - 1)}

    bg = MostCommonColor(cols)

    End If

    ' Loop through each pixel

    For y = 0 To bd.Height - 1
    For x = 0 To bd.Width - 1
    c = GetPixel(bd, b.PixelFormat, x, y)

    ' If it's not the same as the background color

    If Not SameColor(c, bg) Then

    ' Then we update our variables, as appropriate

    If x < left Then left = x
    If y < top Then top = y
    If x > right Then right = x
    If y > bottom Then bottom = y
    End If
    Next x
    Next y

    ' Unlock the bitmap's memory

    b.UnlockBits(bd)

    ' Now calculate the dimensions of the cropped output

    Dim width As Integer = (right - left)
    Dim height As Integer = (bottom - top)

    ' Add a buffer of 5% of the largest dimension (a little padding)

    Dim buffer As Integer = Math.Max(width, height) * 0.05
    width += 2 * buffer
    height += 2 * buffer

    ' Create the new bitmap and the graphics object to draw to it

    Dim cropped As New Bitmap(width, height)
    Dim gfx As Graphics = Graphics.FromImage(cropped)
    Using gfx

    ' Set the color of the bitmap to our background

    gfx.Clear(bg)

    ' Draw the portion of the original image that we want to
    ' the new bitmap

    gfx.DrawImage( _
    b, New Rectangle(buffer, buffer, width, height), _
    New Rectangle(left, top, width, height), _
    GraphicsUnit.Pixel)
    End Using

    Return cropped

    End Function

    End Class

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Goof“ ()

    Goof schrieb:

    Wie bekomme ich das zusammen?
    Wie bekommst Du was zusammen?
    Sollen wir Deinen unformatierten Code, Deine Links und noch irgend was in Deinen laufenden Code konvertieren?
    Strukturiere Deine Code, erstelle Unterprogramme, die einzelne Sachen abarbeiten, gib ihnen wohlklingende Namen und dann stell Deinen Code vor und erläutere die Probleme.
    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!
    Is doch eigentlich simpel.. den Rahmen mittels einer Schleife zählen (getpixels) und ihn das Bild auf das ausgelesene zuschneiden.
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Hallo!

    Hab hier noch was gefunden:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Dim _bmp As Bitmap = New Bitmap("O.bmp")
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. PictureBox1.Image = _bmp
    6. PictureBox2.Image = _einschlRechteck(_bmp)
    7. End Sub
    8. 'Funktion - Einschliessendes Rechteck
    9. Public Function _einschlRechteck(ByVal _source As Bitmap) As Bitmap
    10. Dim __bmp As Bitmap = New Bitmap(_source.Width, _source.Height)
    11. Dim _minX As Integer
    12. Dim _maxX As Integer
    13. Dim _minY As Integer
    14. Dim _maxY As Integer
    15. Dim _width As Integer
    16. Dim _height As Integer
    17. Dim _lo As Integer = 0
    18. Dim _ro As Integer = 0
    19. Dim _lu As Integer = 0
    20. Dim _ru As Integer = 0
    21. _minX = _source.Width
    22. _maxX = 0
    23. _minY = _source.Height
    24. _maxY = 0
    25. _width = 0
    26. _height = 0
    27. For x = 0 To _source.Width - 1 ' links nach rechts
    28. For y = 0 To _source.Height - 1 'oben nach unten
    29. Dim _nCol As Color = _source.GetPixel(x, y) '_lockBits_A.GetPixel(x, y)
    30. 'If _nCol.R <> 255 AndAlso _nCol.G <> 255 AndAlso _nCol.B <> 255 Then
    31. If _nCol.R = 0 AndAlso _nCol.G = 0 AndAlso _nCol.B = 0 Then
    32. 'Einschliessendes Rechteck finden
    33. If y < _minY Then
    34. _minY = y - 2
    35. End If
    36. If y > _maxY Then
    37. _maxY = y + 3
    38. End If
    39. If x < _minX Then
    40. _minX = x - 2
    41. End If
    42. If x > _maxX Then
    43. _maxX = x + 2
    44. End If
    45. End If
    46. __bmp.SetPixel(x, y, _nCol)
    47. Next
    48. Next
    49. Console.WriteLine("TOP: " & _minY & " - " & "Bottom: " & _maxY & " -- " & "Left: " & _minX & " - " & "Right: " & _maxX)
    50. _width = _maxX - _minX
    51. _height = _maxY - _minY
    52. Using g As Graphics = Graphics.FromImage(__bmp)
    53. g.DrawRectangle(New Pen(Color.Red), New Rectangle(_minX, _minY, _width, _height))
    54. End Using
    55. Return __bmp
    56. End Function
    57. End Class


    Zwei PictureBoxen auf eine Form und diesen Code einfügen!

    ..und mit den Koordinaten, also _minX, _minY, _width, _height, kannst Du das Bild dann ausschneiden bzw. neu zeichnen!

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

    @ Morrison
    Lass das Option Strict On bitte weg, es währe wesentlich besser, wenn TE das mal eben in der IDE erledigt.
    Es wäre sogar gut, wenn sowas in jedem Thread, als erstes geklärt wird, wenn unklar !

    @ Goof
    Bitte mal lesen und umsetzen:
    Visual Studio - Empfohlene Einstellungen
    Böses aus VB6/VB2003 - und die richtigen VB.NET-Alternativen

    Post #5 ist ja grauenhaft :S , nutze bitte das VB.Net Tag um Code ordentlich zu formatieren !

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „FormFollowsFunction“ ()

    FormFollowsFunction schrieb:

    Lass das Option Strict On bitte weg

    Jedem das seine oder? Ich mach das auch immer oben in jeder Klasse.

    Folgendes sagt google:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing
    2. Imports System.Drawing.Drawing2D
    3. Imports System.Drawing.Imaging
    4. Imports System.IO
    5. Public Class ImageFunctions
    6. ''' <summary>
    7. ''' Crops the and resize image.
    8. ''' </summary>
    9. ''' <param name="img">The image</param>
    10. ''' <param name="targetWidth">Width of the target.</param>
    11. ''' <param name="targetHeight">Height of the target.</param>
    12. ''' <param name="x1">The position x1.</param>
    13. ''' <param name="y1">The position y1.</param>
    14. ''' <param name="x2">The position x2.</param>
    15. ''' <param name="y2">The position y2.</param>
    16. ''' <param name="imageFormat">The image format.</param>
    17. ''' <returns>MemoryStream of the cropped and resized image.</returns>
    18. Public Function CropAndResizeImage(img As Image, targetWidth As Integer, targetHeight As Integer, x1 As Integer, y1 As Integer, x2 As Integer, _
    19. y2 As Integer, imageFormat As ImageFormat) As MemoryStream
    20. Dim bmp = New Bitmap(targetWidth, targetHeight)
    21. Dim g As Graphics = Graphics.FromImage(bmp)
    22. g.InterpolationMode = InterpolationMode.HighQualityBicubic
    23. g.SmoothingMode = SmoothingMode.HighQuality
    24. g.PixelOffsetMode = PixelOffsetMode.HighQuality
    25. g.CompositingQuality = CompositingQuality.HighQuality
    26. Dim width As Integer = x2 - x1
    27. Dim height As Integer = y2 - y1
    28. g.DrawImage(img, New Rectangle(0, 0, targetWidth, targetHeight), x1, y1, width, height, _
    29. GraphicsUnit.Pixel)
    30. Dim memStream = New MemoryStream()
    31. bmp.Save(memStream, imageFormat)
    32. Return memStream
    33. End Function
    34. ''' <summary>
    35. ''' Resizes the image.
    36. ''' </summary>
    37. ''' <param name="img">The image</param>
    38. ''' <param name="targetWidth">Width of the target.</param>
    39. ''' <param name="targetHeight">Height of the target.</param>
    40. ''' <param name="imageFormat">The image format.</param>
    41. ''' <returns>MemoryStream of the resized image.</returns>
    42. Public Function ResizeImage(img As Image, targetWidth As Integer, targetHeight As Integer, imageFormat As System.Drawing.Imaging.ImageFormat) As MemoryStream
    43. Return CropAndResizeImage(img, targetWidth, targetHeight, 0, 0, img.Width, _
    44. img.Height, imageFormat)
    45. End Function
    46. ''' <summary>
    47. ''' Crops the image.
    48. ''' </summary>
    49. ''' <param name="img">The image</param>
    50. ''' <param name="x1">The position x1.</param>
    51. ''' <param name="y1">The position y1.</param>
    52. ''' <param name="x2">The position x2.</param>
    53. ''' <param name="y2">The position y2.</param>
    54. ''' <param name="imageFormat">The image format.</param>
    55. ''' <returns>MemoryStream of the cropped image.</returns>
    56. Public Function CropImage(img As Image, x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, imageFormat As System.Drawing.Imaging.ImageFormat) As MemoryStream
    57. Return CropAndResizeImage(img, x2 - x1, y2 - y1, x1, y1, x2, _
    58. y2, imageFormat)
    59. End Function
    60. End Class

    Qulle: https://dotnet-snippets.de/snippet/bilder-verkleinern-beschneiden-und-beides-gleichzeitig/1170



    Das ist lediglich eine Klasse mit Funktionen zum Beschneiden eines Bildes.
    Was dir nun fehlt:
    Via Schleife (For) und der Funktion GetPixel ermittelst du nun noch, wie dick der Rahmen ist.
    Im Anschluss, rufst du mit den ermittelten Daten einfach noch die Funktion zum Beschneiden (die ich dir oben gepostet habe) auf,
    und tada, das Bild hat nun keinen Rahmen mehr.
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    @ Gather
    Das Problematische daran ist, daß es dann wahrscheinlich volgendermassen ablauft:
    TE Kopiert den Code ohne zu verstehen , kopiert sich morgen woanders Strict Off Code und kreutzt hier dann übermorgen wieder damit auf.
    Daher scheint mir das nicht Sinvoll zu sein.