AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

BitMap zeichnen per API

Ein Thema von sintronic86 · begonnen am 27. Nov 2012 · letzter Beitrag vom 5. Dez 2012
Antwort Antwort
Seite 1 von 2  1 2      
sintronic86

Registriert seit: 7. Dez 2009
Ort: Barsinghausen
90 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

BitMap zeichnen per API

  Alt 27. Nov 2012, 12:51
Hallo Community,

ich habe ein Problem, welches mich schon richtig frustriert.

Zur Vorgeschichte:
Ich habe ein Tool geschrieben, welches über eine ActiveX-Komponente Daten über die Ole-Schnittstelle
eines Bildverarbeitungsprogramms abgreift. Unter anderem erstellt dieses Programm auch Fotos über
angeschlossene Kameras, welche ich in meinem Tool anzeigen möchte.
Leider gibt das BV-Programm die Bilddaten nur im Typ OleVariant, hinter welchem sich der Typ Array of Array of Bytes verbirgt aus.

Diese Bytes "zu Fuß" auszuwerten und in ein BitMap zu zeichnen habe ich hinbekommen. Allerdings ist das ab einer
gewissen Kameraauflösung natürlich tierisch langsam.

Nun habe ich gehört, das es API-Funktionen gibt, mit denen das wesentlich schneller gehen soll.
Allerdings will es bei mir auf biegen und brechen nicht funktionieren!
Der häufigste Treffer meiner Suche war bisher immer die Funktion "SetDIBitsToDevice".
Aber ich weiss nicht, wie ich dort mein OleVariant unterbringen soll, geschweige wie die
Funktion im Allgemeinen fuktioniert.

Kann mir einer von euch da helfen?
Björn
  Mit Zitat antworten Zitat
nuclearping

Registriert seit: 7. Jun 2008
708 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 13:12
Wie zeichnest du denn jetzt? Wenn du Pixel für Pixel in die Bitmap platzierst, könnte man das ggf. mit ScanLine optimieren.

Bei SetDIBitsToDevice kannst du (afaik) keinen OleVariant direkt unterbringen, sondern musst das Ganze noch in einen entsprechend verständlichen Pointer "casten" bzw. umkopieren.

Alternativ kann man vlt. statt SetDIBitsToDevice auch BitBlt nutzen.
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 13:19
Diese Bytes "zu Fuß" auszuwerten und in ein BitMap zu zeichnen habe ich hinbekommen. Allerdings ist das ab einer
gewissen Kameraauflösung natürlich tierisch langsam.
Mit Scanline und Move sollte das aber nicht langsam sein, vieleicht zeigst du uns etwas Code.

SetDIBitsToDevice scheint hier nicht sinnvoll, wenn man die Daten davor umwandeln muss.
  Mit Zitat antworten Zitat
sintronic86

Registriert seit: 7. Dez 2009
Ort: Barsinghausen
90 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 13:28
Hey, das ging ja schnell!


also bisher sieht es so aus (der wichtigste Ausschnitt der Funktion):


for I := BILDHÖHE - 1 downto 0 do
begin

TmpLine := BITMAP.ScanLine[I];

for J := 0 to BILDBREITE - 1 do
begin
try
TmpRGB := (OLEVARIANT[I,J] or (OLEVARIANT[I,J] shl 8) or (OLEVARIANT[I,J] shl 16));

TmpLine[J * 3 + 2] := TmpRGB;
TmpLine[J * 3 + 1] := TmpRGB;
TmpLine[J * 3] := TmpRGB;
finally

end;
end;
end;






Ja, die Idee mit Scanline hatte ich auch.
das hätte ich dann ungefähr so gelöst:


var TmpLine : PByteArray;
TmpALine: array of Byte;

for I := BILDHÖHE - 1 downto 0 do
begin

TmpLine := BITMAP.ScanLine[I];
TmpALine := OLEVARIANT[I];
Move(TmpALine, TmpLine, ???); <- wobei ich hier nicht genau weiss, was ich eintragen müsste

end;


Aber leider stehen die Einträge der ersten Dimension des Arrays für die Spalten
und die Einträge der zweiten für die Zeilen. Womit sich das auch erledigt hat oder?



Kannst du mir denn mal ein Beispiel für "BitBlt" mit meinem OleVariant geben?
Björn

Geändert von sintronic86 (27. Nov 2012 um 14:07 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#5

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 14:32
Du hast 3 Farbkanäle, die jeweils 1 Byte belegen, sprich 1 Farbpunkt belegt 3*1 = 3 Bytes.. Für jeden Farbpunkt pro Scanline musst du 3 Bytes kopieren. Dh. Breite * 3 kommt da rein.

Weiters ist mir persönlich aufgefallen, dass, wenn du die Scanlines ein einziges mal beim setzen der Dimensionen holst bzw zwischenpufferst, das ganze viel schneller läuft, als wenn du es jedes mal per Bitmap.Scanline[i] ne abfragst. Ich glaub der holt sich dann den jeweiligen Pointer per API Befehle, was unnötig ist!
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG
  Mit Zitat antworten Zitat
sintronic86

Registriert seit: 7. Dez 2009
Ort: Barsinghausen
90 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 14:41
@Aphton:
Ok, Breite mal 3: macht Sinn. Aber das würde doch an dem Problem nichts ändern, das ich nicht einfach sagen kann:

TmpALine := OLEVARIANT[I]

da ich damit ja die erste Spalte, statt Zeile anspreche.
Aber davon abgesehen, bekomme ich bei diesem Zugriff auch eine Fehlermeldung:

---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt XXXXXXX.exe ist eine Exception der Klasse EVariantBadIndexError mit der Meldung 'Variante oder sicheres Array-Index außerhalb des gültigen Bereichs' aufgetreten.
---------------------------
Anhalten Fortsetzen Hilfe
---------------------------


Diese kann ich mir aber nicht erklären, da der Zugriff im selben Moment auf OLEVARIANT[I,0] einen
gültigen Wert herausgiebt!

Ich bin echt am verzweifeln. Habe jetzt ein wenig mit BitBlt herumgespielt, und bekomme es hin,
von einem Image in eine Paintbox zu kopieren. Allerdings wüsste ich nicht, wie ich dort mein OleVariant unterbringen kann.
Björn
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 16:18
Irgendwie ist der Code seltsam, warum läuft deine I-Schleife gegen Null?
Im Array ist zu jedem Pixel nur ein Byte aufgezeichnet (Graustufen vermutlich).
Du baust daraus ein TmpRGB, verwendest danach aber nur das unteren Byte von TmpRGB.
Dieses wird für jeden Farbkanal einzeln geschrieben (BGR, Pixelformat pf24Bit).

Das geht auch einfacher:
Delphi-Quellcode:
var
  TmpLine: PByte;
  TmpByte: Byte;

for I := 0 to BILDHÖHE - 1 do
begin
  TmpLine := BITMAP.ScanLine[I];

  for J := 0 to BILDBREITE - 1 do
  begin
    TmpByte := OLEVARIANT[I, J]; // Grau
    TmpLine^ := TmpByte; // Blau
    Inc(TmpLine);
    TmpLine^ := TmpByte; // Gruen
    Inc(TmpLine);
    TmpLine^ := TmpByte; // Rot
    Inc(TmpLine);
  end;
end;
Ist das noch nicht schnell genug, wirds komplizierter:
- Pixelformat der Bitmap auf 256Farben mit Palette umgestellt
- Palette mit 256 Graustufen erstellen und für die Bitmap auswählen
- mit SafeArrayLock() und SafeArrayAccessData() einen Pointer auf die Daten des Variant besorgen
- die Daten direkt in die Bitmap kopieren
- mit SafeArrayUnaccessData() und SafeArrayUnlock() den Variant wieder entsperren
  Mit Zitat antworten Zitat
nuclearping

Registriert seit: 7. Jun 2008
708 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 17:02
Irgendwie ist der Code seltsam, warum läuft deine I-Schleife gegen Null?
Werden BMPs nicht kopfüber gespeichert?
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.679 Beiträge
 
Delphi 2007 Enterprise
 
#9

AW: BitMap zeichnen per API

  Alt 27. Nov 2012, 20:33
Fast immer. Fast! Windows bot da irgend einen Weg heruaszufinden, wie es denn nun wirklich hinterlegt ist (ich weiss leider echt nicht mehr was das genau war, aber es stand im MSDN (nicht in den Kommentaren)), aber es gibt wohl ganz selten mal den Fall, dass dem nicht so ist. Ob und wann genau das eintritt stand dort leider nicht, und mir sind bisher auch noch keine "richtig-falsch-herumen" Bitmaps begegnet. Das aber nur am Rande
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: BitMap zeichnen per API

  Alt 28. Nov 2012, 08:21
In welcher Reihenfolge die Bildzeilen im Speicher liegen, wird nicht dadurch beeinflusst, in welcher Reihenfolge ich diese kopiere.
Sowohl auf das Variantarray als auch auf ScanLine wird mit dem Index "I" zugegriffen.
Um das Bild vertikal zu spiegeln müsste genau einer der Zugriffe auf "BILDHÖHE - 1 - I" umgestellt werden.

ScanLine berücksichtigt bereits die Ausrichtung der Bilddaten im Speicher.
Scanline[0] ist immer die oberste Zeile, auch wenn diese im Speicher an letzter Stelle liegt.
Die Ole-Schnittstelle legt die Daten vermutlich in der richtigen Reihenfolge im Array ablegt.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:30 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz