Das Objekt wird bereits an anderer Stelle verwendet.

  • VB.NET
  • .NET (FX) 4.0

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von n1nja.

    Das Objekt wird bereits an anderer Stelle verwendet.

    Hey Leute,

    Ich bastel mir gerade eine Software für die Arbeit, das nichts weiter macht als 2 Bilder zu vergleichen und auszuwerten.
    Ich stoß jetzt aber auf ne Fehlermeldung:

    "Ein Ausnahmefehler des Typs "System.InvalidOperationException" ist in System.Drawing.dll aufgetreten.
    Zusätzliche Informationen: Das Objekt wird bereits an anderer Stelle verwendet."

    Ich weiß aber leider nicht genau wo das Problem ist, da ist nicht immer auftritt, sondern immer beim 2-4 mal ca.

    Hier ist der Codeabschnitt wo die Fehlermeldung kommt und zwar in der Zeile 7.

    VB.NET-Quellcode

    1. Dim list As New ArrayList
    2. Dim flag As Boolean
    3. For i As Integer = 0 To x - 1
    4. For i2 As Integer = 0 To y - 1
    5. Dim col1 As Color = img_referenz.GetPixel(i, i2)
    6. Dim col2 As Color = img_trigger.GetPixel(i, i2)
    7. flag = compare(col1, col2, 15)
    8. list.Add(flag)
    9. If flag = True Then wrong += 1
    10. If flag = False Then good += 1
    11. drawing(flag, i, i2)
    12. Next
    13. Next


    Das ganze läuft natürlich in einen ausgelagerten Thread.

    Wäre euch sehr dankbar.
    Einmal macht es was es soll, dann wieder nicht :)

    In "compare" werden nur die Pixel zerlegt und mit dem Wert ausgewertet und gibt mir den Bool zurück, ob die Farben annähend gleich sind.
    Ich hab jetzt ne Info gefunden, irgendwas mit Relase-HDC. Aber ich hab keine Ahnung. Google spuckt nicht wirklich was hilfreiches aus.
    Da das ganze früher oder später performancemäßig anstrengend wird, nutze LockBits. Vllt behebt das zufällig auch dein Problem.

    Edit: Ich denke es wäre angebracht, aus list eine List(Of Boolean) zu machen.
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    Also bis jetzt bin ich zufrieden was die Geschwindigkeit angeht. Glaube so ca 10-70ms für ein Bild mit 3MP. Mit Lockbits hab ich noch nicht gearbeitet. Gibt es einen gewissen Vorteil dadurch? Bzw was ist anders? Und welche Funktionen sind es?

    n1nja schrieb:

    gewissen Vorteil
    gewaaltigen Vorteil.
    Du siehst nicht meher die Pixel, sondern den Bildspeicher. Und da kannst Du drauf rumrasen wie es Dir gefällt.
    Mit C#-unsafe hast Du da die beste Performance.
    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!
    Ok dann werde ich das mal ausprobieren.
    Vllt ist dann mein Fehler wirklich weg:)

    Habt ihr ne gute Seite wo ich mich einlesen kann?!
    Könnte ich das so umsetzen:
    mfranc.com/programming/operacje-na-bitmapkach-net-1/
    oder gibt es bessere Lösungen?


    Alsoooo, ich hab jetzt mal etwas abgeändert und hab ne Lib mit C# gemacht und mein Code angepasst.
    Fehlermeldung ist immernoch vorhanden, allerdings jetzt kommt der Fehler in der Lib.

    Hier ist mein geänderter Code:

    VB.NET-Quellcode

    1. sw.Start()
    2. Dim list As New List(Of Boolean)
    3. Dim flag As Boolean
    4. Dim lock_trigger As New LockBitmap.LockBitmap(img_trigger)
    5. Dim lock_referenz As New LockBitmap.LockBitmap(img_referenz)
    6. lock_trigger.LockBits()
    7. lock_referenz.LockBits()
    8. Dim col1 As Color
    9. Dim col2 As Color
    10. For i As Integer = 0 To x - 1
    11. For i2 As Integer = 0 To y - 1
    12. col2 = img_trigger.GetPixel(i, i2)
    13. col1 = img_referenz.GetPixel(i, i2)
    14. flag = compare(col1, col2, quality)
    15. list.Add(flag)
    16. If flag = True Then good += 1
    17. If flag = False Then wrong += 1
    18. drawing(flag, i, i2)
    19. Next
    20. Next
    21. lock_trigger.UnlockBits()
    22. lock_referenz.UnlockBits()
    23. If flag_auto = True Then compare_done_automatic() : Exit Sub
    24. compare_done()


    Und hier die Klasse dazu:
    Spoiler anzeigen

    C#-Quellcode

    1. namespace LockBitmap
    2. {
    3. public class LockBitmap
    4. {
    5. Bitmap source = null;
    6. IntPtr Iptr = IntPtr.Zero;
    7. BitmapData bitmapData = null;
    8. public byte[] Pixels { get; set; }
    9. public int Depth { get; private set; }
    10. public int Width { get; private set; }
    11. public int Height { get; private set; }
    12. public LockBitmap(Bitmap source)
    13. {
    14. this.source = source;
    15. }
    16. public void LockBits()
    17. {
    18. try
    19. {
    20. Width = source.Width;
    21. Height = source.Height;
    22. int PixelCount = Width * Height;
    23. Rectangle rect = new Rectangle(0, 0, Width, Height);
    24. Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
    25. if (Depth != 8 && Depth != 24 && Depth != 32)
    26. {
    27. throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
    28. }
    29. bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
    30. source.PixelFormat);
    31. int step = Depth / 8;
    32. Pixels = new byte[PixelCount * step];
    33. Iptr = bitmapData.Scan0;
    34. Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
    35. }
    36. catch (Exception ex)
    37. {
    38. throw ex;
    39. }
    40. }
    41. public void UnlockBits()
    42. {
    43. try
    44. {
    45. Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
    46. source.UnlockBits(bitmapData);
    47. }
    48. catch (Exception ex)
    49. {
    50. throw ex;
    51. }
    52. }
    53. public Color GetPixel(int x, int y)
    54. {
    55. Color clr = Color.Empty;
    56. int cCount = Depth / 8;
    57. int i = ((y * Width) + x) * cCount;
    58. if (i > Pixels.Length - cCount)
    59. throw new IndexOutOfRangeException();
    60. if (Depth == 32)
    61. {
    62. byte b = Pixels[i];
    63. byte g = Pixels[i + 1];
    64. byte r = Pixels[i + 2];
    65. byte a = Pixels[i + 3]; // a
    66. clr = Color.FromArgb(a, r, g, b);
    67. }
    68. if (Depth == 24)
    69. {
    70. byte b = Pixels[i];
    71. byte g = Pixels[i + 1];
    72. byte r = Pixels[i + 2];
    73. clr = Color.FromArgb(r, g, b);
    74. }
    75. if (Depth == 8)
    76. {
    77. byte c = Pixels[i];
    78. clr = Color.FromArgb(c, c, c);
    79. }
    80. return clr;
    81. }
    82. public void SetPixel(int x, int y, Color color)
    83. {
    84. int cCount = Depth / 8;
    85. int i = ((y * Width) + x) * cCount;
    86. if (Depth == 32)
    87. {
    88. Pixels[i] = color.B;
    89. Pixels[i + 1] = color.G;
    90. Pixels[i + 2] = color.R;
    91. Pixels[i + 3] = color.A;
    92. }
    93. if (Depth == 24)
    94. {
    95. Pixels[i] = color.B;
    96. Pixels[i + 1] = color.G;
    97. Pixels[i + 2] = color.R;
    98. }
    99. if (Depth == 8)
    100. {
    101. Pixels[i] = color.B;
    102. }
    103. }
    104. }
    105. }



    Der Fehler wo oben gesagt, kommt in der Zeile 56 der Klasse.
    Der Code ist ausn Netz (codeproject) kopiert:)

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

    Tipp: Verwende statt einer ArrayList eine typisierte List<T>, denn die unterstützt Generika, was die ArrayList nicht tut.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ja kommt bei Throw im Try Block.
    mach ich ihn weg, kommt der Fehler wieder in meiner Sub mit der Fehlermeldung die ich die ganze Zeit habe.
    Aber auch nicht immer, wie gesagt, nach 2,3 mal. Aaabee dann kommt die Fehlermelung, das der Bildbereich gesperrt ist, langsam Blick ich nimmer durch.

    n1nja schrieb:

    Ja kommt bei Throw im Try Block.
    Das ist identisch mit dem Weglassen allen Exceptionhandlings, nur dass die eigentliche Fehlermeldung in der InnerException steht. Diese Information wäre nützlich.
    Lass den Try / Catch-Mist weg, schließlich willst Du Fehler finden, nicht verschleiern.
    Wenn Du dann iwann fertig bist und Exceptions vom System abfangen musst, dann und erst dann fange diese und zwar genau diese und keine anderen Exceptions ab.
    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!
    Ja aber weis nicht was der Fehler bedeutet bzw mir sagen will. Das mit Bitmap Bereich ist gesperrt hab ich gelöst. Aber jetzt kommt das mit den Object wird bereits verwendet. Lass ich den Try Block weg in der Lib taucht der Fehler da auf wo ich ihn anfangs beschrieben habe.

    n1nja schrieb:

    da auf
    Na klar, aber halt mit einer ordentlichen Beschreibung und Zeilenangabe.
    Und die solltest Du posten.
    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!
    Ich schätze das Problem ist, dass du deine Objekte nicht freigibst.

    Zunächst: Ein Bitmap-Objekt kapselt eine unverwaltete Systemressource, in diesem Fall ein Handle auf einen GDI Device Context (HDC). Das ist eine Referenz, deren Zielobjekt irgendwo Speicher belegt (wo ist egal). Für jedes Handle gilt: Es muss freigegeben werden. Für GDI und Window Handles gilt: Sie sind nicht threadsicher. Dein Code läuft dann so ab:

    1. Durchlauf (Thread A):
    Bitmap erstellen
    Irgendwas damit machen
    nicht freigeben
    2. Durchlauf (Thread B):
    Irgendwas mit der Bitmap machen
    --> System prüft den Besitzer des offenen HDC (Thread A)
    # Fail, Thread B kann das Objekt nicht auch noch verwenden
    # Das liegt daran, dass ein Handle auf eine Ressource nicht dem Thread, sondern dem Prozess zugeordnet ist (wie so ziemlich jede Systemressource).

    Die Lösung ist einfach: Gib die Bitmap nach Benutzung frei (Dispose aufrufen). Lies dazu unbedingt: codeproject.com/Articles/29534…ther-Never-Told-You-About

    Fall der Fehler ab und zu nicht direkt beim zweiten Mal passiert, hast du vielleicht zufällig dieselbe Thread-ID erwischt (nur eine Vermutung).
    Gruß
    hal2000

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

    Also das mit Dispose werd ich mal probieren.
    Kommt aufs selber raus.
    Fehler besteht weiterhin:(
    Hab jetzt auch mal die FastBitmap Lib von hier versucht.
    Auch das gleiche.

    Was halt seltsam ist, das ich nur diesen einen Thread benutze und sonst halt nur der Hauptthread, aber bei diesen läuft nix mit der Berechnung oder sonst was. Das mit den HDC hab ich scho mal gelesen, aber könnte nicht wirklich was damit anfangen.

    Ich häng hier nochmal mein Sub an die das starten veranlässt.

    VB.NET-Quellcode

    1. img_trigger = New Bitmap(x, y)
    2. lbl_status.Text = "Status: Compare..."
    3. lbl_proz.Text = "Procent: ..."
    4. lbl_speed.Text = "Speed: ..."
    5. PictureBox_trigger.Image = Nothing
    6. maxpix = x * y
    7. img_trigger = CType(PictureBox.Image, Bitmap)
    8. PictureBox_trigger.SizeMode = PictureBoxSizeMode.StretchImage
    9. quality = CInt(TextBox_quality.Text)
    10. th_compare = New Thread(AddressOf calculate)
    11. th_compare.IsBackground = True
    12. th_compare.Start()

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

    n1nja schrieb:

    VB.NET-Quellcode

    1. img_trigger = New Bitmap(x, y)
    Auch eine Bitmap will wieder freigegeben werden.
    Kannst Du da einen freundlichen Using-Block nehmen?
    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!
    Hab grad festgestellt das ich die Anweißung gar nicht brauche.
    Da ich später ja die Bitmap durch die Picturebox zuweiße.

    Ich bekomm jetzt wieder nen ganz anderen Fehler:
    Ungültiger Parameter bei "col2 = img_trigger.GetPixel(i, i2)"

    Ich versteh langsam gar nix mehr...