PIPP (Picture In Picture Picker)

    • VB.NET

    Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von VB1963.

      PIPP (Picture In Picture Picker)

      Dieser Thread (Bild in Bild erkennen und extra speichern) von @Kameo hatte mich inspiriert, dazu ein kleines Projekt zu machen...
      Mich interessierte es, wie man verschiedene Portraits bzw. Figuren aus einem Bild im angepassten Rechteck herauspicken kann.
      VORAUSSETZUNG: Diese Bilder müssen einen homogenen Hintergrund vorweisen und die Figuren (Portraits) müssen zueinander abgetrennt vorliegen.

      Das Kernstück dieses Projekts ist eine Routine, die ein Rechteck um eine Figur bestimmt.
      Diesen berechneten Bereich kann man dann beliebig weiter verwenden...

      Es gibt 2 Richtungen zum Pixel des innenliegenden Figurrands:
      Entweder man sucht außerhalb oder innerhalb der Figur zum Randpixel.

      Hat man dieses Randpixel festgestellt kann man danach den ganzen Figurrand abscannen.
      Es werden alle 8 Nachbarpixel des Randpixels beginnend ab 12 Uhr im Uhzeigersinn auf die Hintergrundfarbe getestet.

      Dabei gilt folgende Theorie:
      1) Zuerst muss ein Nachbarpixel eine Hintergrundfarbe vorweisen also unmittelbar außerhalb der Figur liegen.
      2) Das nächsterste Randpixel, dass von der Hintergrundfarbe wieder abweicht, befindet sich dann wieder im direkten Randbereich innerhalb der Kontour.
      3) Wenn das zutrifft, wird dieses als nächstes innenliegende Randpixel übernommen.
      4) Der gesuchte Rechteckauschnitt (Top, Bottom, Width, Height) wird nach diesem Pixel neu bestimmt.

      So wird die ganze Figur im Randbereich bis zum Startpunkt des Scans im Uhrzeigersinn abgescannt!
      Sollte diese Kontour im Hauptbild bis zu seinem Bildrand reichen, wird der Scan abgebrochen.


      scanDeteilPicture

      VB.NET-Quellcode

      1. ''' <summary>
      2. ''' Der Scan beginnt beim ersten bekannten Randpixel innerhalb der Figur
      3. ''' In der Schleife wird der Figurrand Pixelweise untersucht und
      4. ''' das Rectangel des Bildausschnittes wird ständig bei gültigen Pixel neu berechnet
      5. ''' Ist der Ausgangspunkt wieder erreicht => Ausstieg aus dem Loop
      6. ''' Bei einer Sackgasse werden die Pixel wieder retour gemommen...
      7. ''' </summary>
      8. Private Function scanDeteil(x As Integer, y As Integer) As Rectangle
      9. Dim top = y
      10. Dim bottom = y
      11. Dim left = x
      12. Dim right = x
      13. Dim cntBack = 1
      14. savePixel(x, y)
      15. Dim p = debugNextPixel(x, y)
      16. Do
      17. If Not isPixelPositionOK(p.X, p.Y) Then Exit Do
      18. If p = listEdgePixel.First.Point Then Exit Do
      19. If deadEnd Then
      20. cntBack += 1
      21. Dim i = listEdgePixel.Count - cntBack : If i < 0 Then Exit Do
      22. p = listEdgePixel(i).Point
      23. deadEnd = False
      24. p = debugNextPixel(p.X, p.Y)
      25. Else
      26. cntBack = 1
      27. savePixel(p.X, p.Y)
      28. If top > p.Y Then top = p.Y
      29. If bottom < p.Y Then bottom = p.Y
      30. If left > p.X Then left = p.X
      31. If right < p.X Then right = p.X
      32. p = debugNextPixel(p.X, p.Y)
      33. End If
      34. Loop
      35. Return New Rectangle(top, left, right - left + 1, bottom - top + 1)
      36. End Function
      37. ''' <summary>
      38. ''' Diese Methode dient nur zum Testen und kann mit der Methode 'getNextPixel' direkt ersetzt werden!
      39. ''' </summary>
      40. Private Function debugNextPixel(w As Integer, h As Integer) As Point
      41. Debug.WriteLine(String.Format("{0} {1} {2}", w, h, If(deadEnd, "R", "")))
      42. Return getNextPixel(w, h)
      43. End Function
      44. ''' <summary>
      45. ''' Test aller Nachbarpixel ab 12 Uhr im Uhrzeigersinn
      46. ''' 1) liegt ein Pixel innerhalb oder außerhalb der Figur 'outside'?
      47. ''' 2) liegt ein Pixel außerhalb und ein nächstes Pixel innerhalb der Figur?
      48. ''' 3) ist das vorherige Pixel noch nicht aufgenommen => Übernahme dieses nächsten Pixels!
      49. ''' </summary>
      50. Private Function getNextPixel(w As Integer, h As Integer) As Point
      51. Dim outside = False
      52. Do
      53. h -= 1 : outside = isPixelOK(w, h) 'OBEN
      54. If listEdgePixel.First.Point = New Point(w, h) Then Exit Do 'WIEDER AM START
      55. If deadEnd Then Exit Do 'WIEDER ZURÜCK
      56. If w < 0 AndAlso h < 0 Then Exit Do 'AUSSERHALB
      57. w += 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else w -= 1 'OBEN RECHTS
      58. w += 1 : outside = isPixelOK(w, h) 'OBEN RECHTS
      59. h += 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else h -= 1 'RECHTS
      60. h += 1 : outside = isPixelOK(w, h) 'RECHTS
      61. h += 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else h -= 1 'UNTEN RECHTS
      62. h += 1 : outside = isPixelOK(w, h) 'UNTEN RECHTS
      63. w -= 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else w += 1 'UNTEN
      64. w -= 1 : outside = isPixelOK(w, h) 'UNTEN
      65. w -= 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else w += 1 'LINKS UNTEN
      66. w -= 1 : outside = isPixelOK(w, h) 'LINKS UNTEN
      67. h -= 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else h += 1 'LINKS
      68. h -= 1 : outside = isPixelOK(w, h) 'LINKS
      69. h -= 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else h += 1 'LINKS OBEN
      70. h -= 1 : outside = isPixelOK(w, h) 'LINKS OBEN
      71. w += 1 : If outside AndAlso isPixelOK(w, h, False) AndAlso reverseNextPixel(w, h) Then Exit Do Else w -= 1 'OBEN
      72. Loop
      73. Return New Point(w, h) 'Übernahme des Pixels
      74. End Function
      75. ''' <summary>
      76. ''' Überprüfung, ob das Pixel schon einmal aufgenommen wurde.
      77. ''' Wenn das der Fall ist, wird mit 'deadend' (Sackgasse) zurückgeschaltet.
      78. ''' Das Ergebnis wird erst beim nächsten Pixel aktuell geprüft => Return NOT Found
      79. ''' </summary>
      80. Private Function reverseNextPixel(w As Integer, h As Integer) As Boolean
      81. Dim found = listEdgePixel.Contains(New Pixel(New Point(w, h)))
      82. deadEnd = found 'Sackgasse
      83. Return Not found
      84. End Function
      85. ''' <summary>
      86. ''' Überprüfung auf die korrekte Position des Pixels
      87. ''' Und dann Test auf Vordergrund- oder Hintergrundfarbe
      88. ''' </summary>
      89. ''' <param name="onTheEdge">Test auf außerhalb (True) oder innerhalb (False) der Figur liegendes Pixel</param>
      90. Private Function isPixelOK(w As Integer, h As Integer, Optional onTheEdge As Boolean = True) As Boolean
      91. If Not isPixelPositionOK(w, h) Then Return False
      92. If onTheEdge Then
      93. Return (bmpTarget.GetPixel(w, h) = colorBackground) 'außerhalb der Figur
      94. Else
      95. Return (bmpTarget.GetPixel(w, h) <> colorBackground) 'innerhalb der Figur
      96. End If
      97. End Function


      Dieser Scan tut, was er soll - aber er ist leider nicht gerade der schnellste!
      (ich werde als nächstes das mit LockBits versuchen...)
      Anbei das Testprojekt und ein Beispielbild von Kameo.
      Bilder
      • TestPicture.png

        112,72 kB, 538×703, 186 mal angesehen
      Dateien
      • PIPP02.zip

        (30,63 kB, 168 mal heruntergeladen, zuletzt: )

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

      @VB1963 Dein Programm, Dein TestPicture, Auto Pick und Save Detail, da kommt eine 15x1-Pixel-PNG raus, was wohl nicht zum Plan gehört.
      Der By-Hand-Mode funktioniert merkwürdig, der Mauszeiger flattert scheinbar unmotiviert.
      Vielleicht wäre ein Zoom angebracht.
      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!

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

      mit dem gegebenen Bild funzt das bei mir.
      Ob der Randläufer-Algo in allen Situationen korrekt ist, weiß ich nicht - ich find ihn sehr schwer verständlich, auch weil undokumentiert.

      Ich hab auch mal ein Randläufer-Algo implementiert, sogar wiederverwendbar, wie ich hoffe. Ich hab die Klasse "Turtle" genannt. Prinzip ist, dass es eine Anzahl Richtungen gibt - bei vb1963 sinds 8, bei meim Turtle nur 4 - aber das müsste sich anpassen lassen.
      Bei mir allerdings werden die Richtungen einfach hochgezählt. Also Turtle wendet sich nach rechts, indem Direction erhöht wird, und wendet nach links, indem es erniedrigt wird. Einen Rand entlang läuft man (linksrum), indem man immer das freie Feld sucht, dessen rechter Nachbar nicht frei ist.

      Zusätzlich zur Randläuferei muss ein Turtle natürlich auch gradeaus laufen können, nämlich bis es auf einen Rand trifft.

      Also ein Turtle muss im wesentlichen die Methoden TryStep() As Boolean haben zum Gradeauslauf bis zum Hindernis, und dann StepAgainstBorder(), um dem Rand zu folgen.
      An Status-Informationen braucht es Location - wo es grade ist, und Direction - wo es als nächstes hinzusteppen versucht.

      VB.NET-Quellcode

      1. Imports System.ComponentModel
      2. Public Class Turtle : Implements INotifyPropertyChanged, INotifyPropertyChanging
      3. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
      4. Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
      5. Public Direction As New Direction
      6. ''' <summary> this validator is meant to be set from outside </summary>
      7. Public Canstep As Func(Of Point, Boolean)
      8. Private _Location As Point = Nothing
      9. Public Property Location() As Point
      10. Get
      11. Return _Location
      12. End Get
      13. Set(value As Point)
      14. If _Location = value Then Return
      15. RaiseEvent PropertyChanging(Me, New PropertyChangingEventArgs("Location"))
      16. _Location = value
      17. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Location"))
      18. End Set
      19. End Property
      20. ''' <summary> try move in its Direction </summary>
      21. Public Function TryStep() As Boolean
      22. Dim pt = Direction.Move(_Location)
      23. If Not Canstep(pt) Then Return False
      24. Location = pt
      25. Return True
      26. End Function
      27. ''' <summary> move along the Border - Border on left hand </summary>
      28. Public Sub StepAgainstBorder()
      29. 'suche rechtsrum eine freie Richtung. Wenn gefunden, 1 Schritt, dann Richtung decrementieren damit wieder gegen die Grenze gerichtet.
      30. For i = 0 To 3
      31. If TryStep() Then
      32. Direction -= 1
      33. Return
      34. End If
      35. Direction += 1
      36. Next
      37. End Sub
      38. End Class
      Ausserdem habich eine Direction-Klasse erfunden, die man unendlich erhöhen/verringern kann ohne Überlauf - dreht sich stattdessen nur im Kreis.
      Besonders anne Direction ist, dass die eigliche Ortsveränderung Move() hier angesiedelt ist, und nicht im Turtle:

      VB.NET-Quellcode

      1. Imports System.Diagnostics
      2. <DebuggerDisplay("{Value}")> _
      3. Public Structure Direction
      4. Private Shared _Directions As Integer = 4
      5. Public Value As Integer
      6. Private Shared Function cyclicAddition(left As Integer, right As Integer) As Integer
      7. cyclicAddition = (left + right) Mod _Directions
      8. If cyclicAddition < 0 Then cyclicAddition += _Directions
      9. End Function
      10. Public Shared Operator +(ByVal left As Direction, ByVal right As Integer) As Direction
      11. Return New Direction With {.Value = cyclicAddition(left.Value, right)}
      12. End Operator
      13. Public Shared Operator -(ByVal left As Direction, ByVal right As Integer) As Direction
      14. Return New Direction With {.Value = cyclicAddition(left.Value, -right)}
      15. End Operator
      16. Public Shared Widening Operator CType(ByVal initialData As Integer) As Direction
      17. Return New Direction With {.Value = initialData}
      18. End Operator
      19. Public Function Move(pt As Point) As Point
      20. If (Value And 1) = 1 Then 'horizontal
      21. pt.X += 2 - Value
      22. Else 'vertical
      23. pt.Y += Value - 1
      24. End If
      25. Return pt
      26. End Function
      27. End Structure


      Zur Performance: Jo, wenn man dieses elende .GetPixel() durch BitmapData-Zugriffe ersetzt, wird die Geschichte sofort rasend schnell, dass sich weitere Optimierungen erübrigen.

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

      RodFromGermany schrieb:

      Der By-Hand-Mode funktioniert merkwürdig, der Mauszeiger flattert scheinbar unmotiviert
      Hi Rod, das hat sich bei mir eigentlich nicht so störend gezeigt. Das könnte daran liegen, dass bei der Mouseposition genau nur ein Pixel auf den Hintergrund getestet wird. Ich habe das jetzt abgefedert, indem ein Bereich um diese Position auf die Hintergrundfarbe getestet wird...

      RodFromGermany schrieb:

      da kommt eine 15x1-Pixel-PNG raus, was wohl nicht zum Plan gehört
      Da hatte ich leider beim Speichern noch nicht darauf getestet gehabt...

      ErfinderDesRades schrieb:

      Ob der Randläufer-Algo in allen Situationen korrekt ist, weiß ich nicht - ich find ihn sehr schwer verständlich, auch weil undokumentiert.
      Ja - diese Methode ist ein bisschen schwierig zu verstehen, weil die Pixel (Hauptpixel und 8 zugehörende Nachbarpixel) zueinander in einem Loop abgefragt werden.
      Ich habe diese Passage jetzt ordentlich dokumentiert und auch Variablen unbenannt und das Ganze ist oben im Spoiler 'scanDetailPicture' ersichtlich...

      Danke für deinen Randläufer - muss ich mir anschauen :)



      Das Projekt habe ich noch einmal überarbeitet und zum Testen hochgeladen.
      Es wird jetzt auch beim Laden auf ein geeignetes Hauptbild geprüft...
      Sollte ein Bild ungeeignet sein, darf trotzdem die Routine in keinen Fehler laufen und ein fehlerhaftes 1-pixelreihiges Hauptbild anzeigen (ab 5 Zeilen und 5 Spalten wird's zugelassen)
      Ich habe bis jetzt noch kein Fehlverhalten beim Scannen eines Figurrandes feststellen können. ( sollte das doch der Fall sein, bin ich sehr dankbar für Bild und einen Hinweis :) )

      lg
      VB1963

      VB.NET-Quellcode

      1. dlg.InitialDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures)
      solltest Du rausnehmen, es ist echt nervig, wenn die Bilder woanders liegen.
      Zum angehängten Testbild sagt er "Ist leider ungeeignet".Und dann passiert nix weiter. ;(
      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!
      Moin Moin!

      @VB1963
      Finde ich super das du aus meinem Problem eine Lösung gemacht hast :D :thumbup:
      Ich habe das ganze jetzt auf eine "QuickAndDirty" variante gelöst (siehe Anhang)
      Ja, es ist nicht Fehlerfrei, Ja es kann sehr leicht abstürzen, ABER es ist nur für meine Freundin um ihr die arbeit zu erleichtern, deswegen werden nur leicht Bugfixed gemacht.
      Da ihr mir aber so sehr im oben genanten Thread geholfen habt, dachte ich mir zeige ich einmal was ich gemacht habe.

      P.S. Bilder einfach per Drag´n´Drop in die Picturebox.

      Reihenfolge wie folgt damit das Program "Sauber" arbeitet:
      • Bild per [...] auswählen oder per Drag´n´Drop in die Picturebox ziehen
      • Roten Rahmen auf den gewünschten Ausschnitt ziehen (mit Trackbar und Numerics größe anpassen)
      • "Preview Button" klicken
      • mit "Pick Color(F6)" Farbe wählen die gelöscht werden soll
      • mit "Set Color (F7)" gewählte Farbe einloggen
      • "Delete Color"
      • "Save Color"

      Viele Grüße, und nochmal danke für die Hilfe!
      Dateien
      • SpriteSaver.zip

        (170,4 kB, 152 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Gelöschter Benutzer“ ()

      @Kameo Ist Deine 7z-Datei in Ordnung? Bei mir kommt pro Dateidie Fehlermeldung

      und es wird nur eine leere Datei angelegt. ;(
      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!
      @Kameo Immer noch komisch.
      WinRAR 5.01 - 64
      Spoiler anzeigen
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver.sln.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver.suo.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\app.config.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Debug\SpriteSaver.exe.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Debug\SpriteSaver.exe.config.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Debug\SpriteSaver.pdb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Debug\SpriteSaver.vshost.exe.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Debug\SpriteSaver.vshost.exe.config.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Debug\SpriteSaver.xml.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Release\SpriteSaver.exe.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Release\SpriteSaver.exe.config.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Release\SpriteSaver.pdb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\bin\Release\SpriteSaver.xml.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\MainFrm.Designer.vb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\MainFrm.resx.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\MainFrm.vb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\app.manifest.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\Application.Designer.vb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\Application.myapp.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\AssemblyInfo.vb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\Resources.Designer.vb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\Resources.resx.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\Settings.Designer.vb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\My Project\Settings.settings.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\DesignTimeResolveAssemblyReferences.cache.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\DesignTimeResolveAssemblyReferencesInput.cache.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.exe.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.MainFrm.resources.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.pdb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.Resources.resources.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.vbproj.FileListAbsolute.txt.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.vbproj.GenerateResource.Cache.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\SpriteSaver.xml.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Debug\TempPE\My Project.Resources.Designer.vb.dll.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\DesignTimeResolveAssemblyReferencesInput.cache.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.exe.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.MainFrm.resources.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.pdb.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.Resources.resources.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.vbproj.FileListAbsolute.txt.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.vbproj.GenerateResource.Cache.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\SpriteSaver.xml.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\obj\x86\Release\TempPE\My Project.Resources.Designer.vb.dll.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\Resources\Background.PNG.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\SpriteSaver.ico.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\SpriteSaver.vbproj.
      ! C:\Temp\SpriteSaver.zip: Unbekannte Methode in SpriteSaver\SpriteSaver\SpriteSaver.vbproj.user.
      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!
      @Kameo Jou. Jetzt hat es geklapt.
      Unterscheide mal
      - Move mit Mouse - inne drinne
      - Zoom mit Mouse - aufm Rand
      --
      - ggf. Fortsetzung in x und y mit der Größe und "AutoAdjust", es werden Zeilen / Spalten auf Hintergrund getestet und ggf. Höhe / Breite +-1 angepasst.
      ==> Auto-Mode, gefunden: n Stück, die werden dann alle abgespeichert.
      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!
      @VB1963: hier findste den Upload dazu: "TurtleTester" in FightingSnakes
      Das Testprojekt kannste vlt. sogar nutzen, um deinen eigenen Algo zu verifizieren - weil man kann da Irrgärten basteln, und gucken, wie Turtle klarkommt.

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

      VB1963 schrieb:

      ich werde als nächstes das mit LockBits versuchen...

      Anbei das umgeschriebene Projekt mit Nutzung einer eigenen Klasse FastBitmap, wo mit Lock- und UnLockBits gearbeitet wird.
      Bei meiner Randläufer-Methode ist es sehr wichtig, dass die Figurränder sich vom Hintergrund gut abheben.
      Daher habe ich jetzt noch zusätzlich eine Methode CompositeBackground eingebaut, die den ganzen Hintergrund der Hauptbilder homogenisiert, damit die Picker-Funktion noch besser arbeitet.

      Lg
      VB1963
      Dateien
      • PIPP03.zip

        (33,23 kB, 134 mal heruntergeladen, zuletzt: )
      • Beispielbilder.rar

        (1,12 MB, 172 mal heruntergeladen, zuletzt: )
      Bedeutet das, dass der Hintergrund dezente Farbunterschiede haben kann?
      Auf der Suche nach Coding-Kursen auf Lence.at