Einzelnen Beitrag anzeigen

hanvas

Registriert seit: 28. Okt 2010
157 Beiträge
 
Delphi 11 Alexandria
 
#11

AW: Pixelerkennung, Kreativität gesucht die mir fehlt!

  Alt 24. Aug 2016, 15:33
Ich würde zunächst ein Array in den Dimensionen des Bildes anlegen, als Datentyp würde ich vermutlich Byte wählen, kann aber sein das Integer, wenn es auf Geschwindigkeit ankommt, ggf. besser wäre.

Anschließend würde ich an allen Positionen die im Bild der Suchfarbe entsprechen eine 1 im Array setzen, an allen anderen Positionen eine 0. Das Ergebnis bis hierhin ist praktisch Binärbild das die zu bearbeitenden Umrisse, die Buchstaben und die Paralellogramme des gesuchten Balkens enthalten.

Anschließend würde ich eine Liste der "verbundenen Komponenten" erstellen. Die nachfolgenden Prozeduren sollten nebenbei auch noch ein Labeling durchführen, das heißt jedem Umriss im erzeugten "Binärbild" eine andere Nummer, beginnend mit 2 zuordnen. Die erzeugte Liste enthält ein Objekt welches die Anzahl der zusammenhängenden Pixel speichert, das Rechteck für jeden Umriss das den Umriss gerade noch umschließt und das Label das mit dem Urisse in unseren Array korrospondiert.

Einfach mal so hingeschrieben, ungetestet, keine Garantie auf Korrektheit, beim dargestellten Problem (und s/w Bild) sollte die rekursive Version funktionieren.

Delphi-Quellcode:

const nr = YYYY; // Dimension in y
      nc = XXXX; // Dimension in x

type TData : Array[0..nr,0..nc] of byte;

      // Bitte selbst implementieren
      TObjectInfo = class(TObject) // oder record
      private
       FExtends : TRect;
       FLabel : Integer;
       FSize : Integer;
      public
       Constructor Create(aSize, aLabel : Integer; minX,minY,maxX,maxY : Integer );
      property
       Size : Integer
        read FSize;
      property
       R : TRect
         read FExtends
      property
       label : Integer
         read FLabel;
      end;

function ConnectedArea ( var data : TData; y,x : Integer; Searched : Integer= 1; Visited: Integer = 2; var minX,minY,maxX,maxY ) : Integer;
var v : Integer;
begin
  if ( y< nr ) and
     ( y >= 0 ) and
     ( x < nc ) and
     ( x >= 0 ) then
  begin
   v := Data[y,x];
   if (v=Searched) and //
      (v<>visited) then
      begin
       if (minX>x) then
           minX:= x;
       if (minY>y ) then
           minY:= y;
       if (maxX>x) then
           maxX := x;
       if (maxY>y) then
           maxY := y;
       result := 1;
       Data[y,x] := visited;
       result := result + ConnectedArea ( img, y+1, x , Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y+1, x+1, Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y+1, x-1, Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y-1, x , Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y-1, x-1, Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y-1, x+1, Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y , x+1, Value, minx,miny,maxx,maxy );
       result := result + ConnectedArea ( img, y , x-1, Value, minx,miny,maxx,maxy );
      end else
      result := 0;
  end else result := 0;
end;

function ListConnected
  ( var Data : TData; zx1, zy1, zx2, zy2 : Integer ) : TList;
var i,j : Integer;
    a, cnt : LongInt;
    minx,miny,
    maxx,maxy : Integer;
begin
 result := TList.Create;
 cnt := 2;
 minx := maxInt;
 miny := maxInt;
 maxx := 0;
 maxy := 0;
 for j := zy1 to zy2 do
   for i := zx1 to zx2 do
     if ( Data[j,i] = 1 ) then
      begin
       cnt := cnt + 1;
       a := ConnectedArea ( Data, 1, cnt, j,i, minx,miny,maxx,maxy );
       if ( a > NOISE ) then begin
                               result.Add(TObjectInfo.Create(a,cnt,minx,miny,maxx,maxy);
                               minx := maxInt;
                               miny := maxInt;
                               maxx := 0;
                               maxy := 0;
                             end;
      end;
end;

Wenn man sich deine Beispielbilder ansieht fällt auf das der von dir gesuchte Balken aus nebeneinanderliegenden Paralellogrammen besteht. Die Bilder sind für mich zu klein um erkennen zu können ob sich die Paralellogramme berühren, ich gehe mal von nein aus.

Die einander nicht berührenden Paralellogramme würden in der erzeugten Liste als jeweils eigene Objekte zu finden sein. Die y Koordinate der jeweiligen Grundlinien sollte gleich, oder durch Darstellungsfehler unter Umständen um ein Pixel nach oben oder unten verschoben sein. Die Rechtecke die die Ausmaße beschreiben müssen überlappen. Solange also mindestens zwei Paralellogramme existieren musst Du eigentlich nur nach überlappenden Objekten mit praktisch gleichen Dimensionen an unterschiedlichen X Positionen, aber (nahezu) gleichen Y Positionen suchen und das Rechteck bilden das alle Objekt die Du so findest einschließt.

[1] Wenn Du meine Prozedur von vertikal zuerst auf horizontal umstellst dann werden die Objekte sogar in der richtigen Reihenfolge erzeugt was das suchen und finden noch einfacher macht.

cu Ha-Jö

Geändert von hanvas (24. Aug 2016 um 15:36 Uhr) Grund: cnt muss mit 2 beginnen
  Mit Zitat antworten Zitat