AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Leere Seite (blank page) filtern bei DelphiTwain

Leere Seite (blank page) filtern bei DelphiTwain

Ein Thema von Schwedenbitter · begonnen am 24. Aug 2015 · letzter Beitrag vom 26. Aug 2015
Antwort Antwort
Seite 2 von 2     12
Jens01

Registriert seit: 14. Apr 2009
670 Beiträge
 
#11

AW: Leere Seite (blank page) filtern bei DelphiTwain

  Alt 26. Aug 2015, 11:52
Zitat:
Ich interpretiere das so, dass die Abfrage immer nur dann durchgeführt wird, wenn er einen schwarzen Pixel findet und sonst nicht. Wenn das Bild aber weiß ist, "scannt" er sowieso das gesamte Bild. Und wenn er schwarz ist, fliegt er spätestens einen Zyklus später raus? Kann man die Beschleunigung messen?
Du zählst dies lBlack hoch und prüfst es gegen eine Konstante. Du brauchst es aber nur prüfen, wenn es sich verändert hat (Inc(lBlack)). Ansonsten ist das Ergebnis der Prüfung (if lBlack >= MaxBlack then) gleich mit dem des vorherigen Schleifendurchlauf.
Wenn die Hauptschleifen oft durchlaufen wird, kann sich des schon zeitlich auswirken.
Achtung: Bin kein Informatiker sondern komme vom Bau.
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#12

AW: Leere Seite (blank page) filtern bei DelphiTwain

  Alt 26. Aug 2015, 12:15
...
Wenn die Hauptschleifen oft durchlaufen wird, kann sich des schon zeitlich auswirken.
OK. Das überzeugt mich. Ich habe es geändert.

Wenn ich Zeit und Lust habe, kann ich ja mal testen, wie es sich auswirkt. Vermutlich muss ich dazu aber ein festes Bitmap nutzen. Denn selbst beim selben Rohmaterial (=Papierseiten) kommen jedes Mal andere Bilder über den Scanner.
Alex Winzer
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#13

AW: Leere Seite (blank page) filtern bei DelphiTwain

  Alt 26. Aug 2015, 12:23
So als Verbesserungsvorschlag:

Verkleinere die Bitmaps, die du durchsuchen willst z.B. auf 300x300 Pixel. Durch das Zusammengematsche fallen einzeln stehende Punkte (Staub, kleine Kratzer) schon dabei raus und die Stellen mit Text tauchen als schwarze Balken auf. (jetzt mal Schwarz-Weiß betrachtet)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#14

AW: Leere Seite (blank page) filtern bei DelphiTwain

  Alt 26. Aug 2015, 13:33
So als Verbesserungsvorschlag:

Verkleinere die Bitmaps ...
Auch das hört sich überzeugend an,
ABER
manchmal schreibt auch ein Staatsanwalt nur mit sehr dünnem und spitzen Bleistift. Dann müsste ich vor dem Verkleinern am Kontrast schrauben, weil mir sonst die Striche durch die Lappen gehen und das Bild als leer identifiziert wird. Ich hatte irgendwo mal angemerkt, dass ich schon umfangreiche Tests gerade mit Bleistift gemacht hatte.
Das wiederum (erst Kontrast, dann BitBlt, dann Pixelsuche) führt am Ende vermutlich nicht mehr zu einer weiteren Beschleunigung. Ich fürchte, das macht es eher fehleranfällig.

Außerdem arbeiten wir im Moment mit Singlecore Celerons. Da läuft das schon flott. Wir stellen aber auf Windows 10 und zugleich auf Quadcore-Rechner um. Die sollen mal schön rechnen. Die Mitarbeiter müssen sich ja auch mal einen Kaffee holen können. Das schaffen die sowieso schon nicht mehr
Alex Winzer
  Mit Zitat antworten Zitat
Jens01

Registriert seit: 14. Apr 2009
670 Beiträge
 
#15

AW: Leere Seite (blank page) filtern bei DelphiTwain

  Alt 26. Aug 2015, 17:08
"Staatsanwalt"

Vielleicht solltest Du die "leeren" Seiten nicht verwerfen, sondern nur extra ablegen.
Achtung: Bin kein Informatiker sondern komme vom Bau.
  Mit Zitat antworten Zitat
hanvas

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

AW: Leere Seite (blank page) filtern bei DelphiTwain

  Alt 26. Aug 2015, 18:04
Eines vorweg, die meisten besseren Dokumentenscanner unterstützen dieses Feature in der Hardware oder im Treiber.

Falls ein solcher zum Einsatz kommt wäre es klüger die dort implementierten Verfahren zu verwenden. Das entsprechende Feature nennt sich ICAP_AUTODISCARDBLANKPAGES und ist ab der Revision 2.1 des Standards vorhanden, die meisten TWAIN Delphi Implementierungen basieren aber auf TWAIN 2.0 und haben deswegen die entsprechenden Konstanten nicht definiert.


Auch das hört sich überzeugend an,

ABER

manchmal schreibt auch ein Staatsanwalt nur mit sehr dünnem und spitzen Bleistift.
Der in diesem Fall einfachste - und dennch relativ zuverlässigste Weg wäre - ein leistungsfähiges globales oder lokales Verfahren zur Wandlung des Graustufenbildes in ein Schwarzweissbild zu verwenden. Das hat den Vorteil das der Vordergrund und der Hintergrund des Bildes relativ sauber getrennt wird, selbst dann wenn es über die Seite verteilt Unterschiede in der Helligkeit gibt. Normalerweise sollte auch der dünne Strich Deines Staatsanwaltes erhalten bleiben.

Ich habe Dir ein paar Beispiele dazu hingeschrieben.

Die Verwendung meiner Beispiele wäre :

Code:

 var x : Integer;

 x := TreshXXXX(Image);
 newImage := BinarizeThrsh(Image,x);
Aber Du kannst den Code ohnehin nicht 1:1 verwenden. ThreshOtuDisc wäre der Klassiker, ThreshEntropy ist aber schneller ich verwende in einer ähnlichen Situation :

Code:

     t := TOcrImage.CreateFromBitmap(Image.Bitmap);
     case isBW of
      0 : o := t; // wir sind sw ->
      1 : try
           thrsh := ThreshEntropy(t);
           if ( thrsh < 0 ) then
               thrsh := ThrshOptimum(t);
           if ((thrsh) < 0) then
             begin
             result := False;
             exit;
            end;
           o    := BinarizeThresh(t, thrsh);
          finally
           t.free;
          end;
     ......
     end;
Da Du anschließend ein Schwarweißbild hast führst Du eine Analyse der verbundenen Regionen durch - mit anderen Worten du arbeitest dich rekursiv bei einem Pixel in Schwarz zum nächsten Pixel vor das an das erste Pixel angrenzt dann zum nächsten usw. bis Du eine komplette zusammenhängende Region hast und speicherst diese Regionen und deren Eigenschaften in einer Liste.

Du kannst davon ausgehen das einzelne Pixel, oder Verbunde von Pixeln unterhalb eines gewissen Größe Dreck, Staub etc. sind. Diese Elemente kannst Du löschen. Anschließend stellt Du fest ob Du große zusammenhängende Regionen hast deren Bounding Box sehr schmal ist aber dafür nahezu die gesamte Höhe des gescannten Blattes einimmst. Dabei handelt es sich um horizontale Linien die normalerweise durch Dreck oder Kratzer auf dem Scannerglas entstanden sind. Auch die kannst Du löschen (aber nur wenn die Box wirklich relativ schmal ist)

Wenn Du auf diese Art alle unerwünschten Einflüsse eleminiert hast rekonstriest Du das Bild anhand der noch vorhandenen Elemente in der Liste. Anschließend bildest Du die Bounding Box über das gesamte Bild - ich würde übrigens beim Scannen den Rand in einer Breite von 5 - 15 Pixel noch vor der Erstellung der Liste löschen bzw. auf Weiss setzen.

Nun betrachtest Du nur den Inhalt in der Box und nimmst einen Wert zwischen 1% und 5% an - ist die Anzahl der gesetzten Pixel darunter kannst Du von einem leeren Bild ausgehen. Anpassungen an spezielle Problemstellungen sind natürlich möglich.

Im nachfolgenden Beispiel habe ich die Klasse TOcrImage nicht definiert - die einzelnen Zeilen eines Bildes sind aber nichts anderes als Arrays bzw. Zeiger auf Arrays deren einzelne Elemente Bytes sind - im Fall eines Graustufenbildes von 0-255 im S/W Fall eben 0/1.

Die Implementierungen sind entweder eine Umsetzung bekannter Verfahren oder ich habe Sie dem Buch "Practical Algorithms for Image Analysis" entnommen und von C nach Pascal umgesetzt.

Code:

type    TOcrIntegerHistogram = array of Integer;
         TOcrDoubleHistogram = array of Double;

procedure TOcrImage.Histogram ( var Hist : TOcrIntegerHistogram );
var i  : Integer;
    y,x : Integer;
begin
 SetLength ( Hist, 256 );
 for i := 0 to 255 do Hist[i] := 0;
 for y := 0 to pred ( Nr ) do
     for x := 0 to pred ( Nc ) do
               inc ( Hist[Data[y,x]] );
end;

procedure TOcrImage.RelativeHistogramm ( var hist : TOcrDoubleHistogram );
var histI  : TOcrIntegerHistogram;
    pixels : LongInt;
    counter : Integer;
begin
 pixels := Nr * Nc;
 SetLength ( hist, 256 );
 if ( pixels <= 0 ) then
 begin
  for counter := 0 to 255 do
      hist[counter] := 0;
  exit;
 end;
 Histogram ( histI );
 for counter := 0 to 255 do
     hist[counter] := histI[counter] / pixels;
 SetLength ( histI, 0 );
end;

function BinarizeThresh ( const ImgIn : TOcrImage; Thresh : Integer ) : TOcrImage;
var i,j  : Integer;
    pS,pT : pByte;
begin
  result := TOcrImage.Create ( ImgIn.Nr, ImgIn.Nc );
  for j := 0 to pred ( imgIn.Nr ) do
  begin
   i := 0;
   pS := imgIn.GetLinePointer ( j, 0 );
   pT := result.GetLinePointer ( j, 0 );
   while (i < imgIn.Nc ) do
    begin
       if ( pS^ < thresh ) then pT^ := _ON
                           else pT^ := _OFF;
       inc(pS);
       inc(pT);
       inc(i);
    end;
  end;
end;


function ThreshEntropy ( const ImgIn : TOcrImage ) : Integer;
var width, height : Integer;          (* image size *)
     Hn, Ps, Hs   : Double;
     psi, psiMax  : Double;
     x, y,                   (* image coordinates *)
     i, j, n      : Integer;
     iHist : array [0..NHIST-1] of integer;           (* hist. of intensities *)
     prob : array [0..NHIST-1] of Double;
begin
 result := -1;
(* allocate input and output image memory *)
  height := imgIn.Nr;
  width := imgIn.Nc;
(* compile histogram *)
  for i := 0 to pred ( NHIST ) do iHist[i] := 0;

  n := 0;
  for y := 0 to pred ( height ) do
    for x := 0 to pred ( width ) do
     begin
      inc(iHist[imgIn.Data[y,x]]);
      inc(n);
     end;

  if ( n <= 0 ) then begin
                       result := -1;
                       exit;
                     end;
  (* compute probabilities *)
  for i := 0 to pred ( NHIST ) do
      prob[i] := iHist[i] / n;

(* find threshold *)
  hn := 0;
  for i := 0 to pred ( NHIST ) do
    if (prob[i] <> 0.0) then
      Hn := hn - ( prob[i] * ln (prob[i]) );
  psiMax := 0.0;
  for i := 1 to pred ( NHIST ) do
   begin
     ps := 0;
     hs := 0;
     for j := 0 to pred ( i ) do
       begin
        Ps := ps + prob[j];
        if (prob[j] > 0.0) then
          Hs := hs - ( prob[j] * ln (prob[j]) );
    end;
    if (Ps > 0.0) and (Ps < 1.0) then
    begin
      psi := ln (Ps - Ps * Ps) + Hs / Ps + (Hn - Hs) / (1.0 - Ps);
      if (psi > psiMax) then
      begin
       psiMax := psi;
       result := i;
     end;
    end;
  end;
end;

function ThrshOptimum        ( const ImgIn : TOcrImage ) : Integer;
var x,y,Flag,j : Integer;
    hist      : TOcrDoubleHistogram;
    Sum       : Double;
begin
 ImgIn.RelativeHistogramm ( hist );
 for y := 0 to 255 do
  begin
   sum := 0;
   for x := -15 to 15 do
    begin
     j := y-x;
     if ( ( j ) >= 0  ) and
         ( ( j < 255 ) ) then Sum := Sum + Hist[j];
    end;
   Hist[y] := SUM / 31 ;
  end;
  Y     := 2;
  FLAG  := 0;
  result := 0;
  while ( Flag = 0 ) and ( y < 254 ) do
   begin
    if ( ( HIST [Y-1] >= HIST[y ] )  and
         ( HIST [Y]  < HIST[y+1] ) ) then
           begin
            Flag  := 1;
            result := Y;
           end;
    inc ( y );
   end;
 SetLength ( hist, 0 );
end;

function ThrshMovingAvarage (const imgIn : TOcrImage ) : TOcrImage;
var    NC, row, col, _inc : Integer ;
       mean, s, sum      : Double;
       N, i              : Integer;
      im                : TOcrImage;
begin
  im  := TOcrImage.CopyCreate ( imgIn );
   N  := im.nc * im.nr;
   NC := im.nc;
   s  := (NC/Navg);
   sum := 127*s;
   row := 0;
  col := 0;
   _inc := 1;

   for i:= 0 to pred ( N-1 ) do
   begin
     if (col >= NC) then  begin
       col := NC-1;
      inc(row);
       _inc := -1;
      end
    else
     if (col < 0) then
      begin
         col := 0;
        inc(row);
        _inc := 1;
       end;

   // Estimate the mean of the last NC/8 pixels.
     sum := sum - sum/s + im.Data[row,col];
     mean := sum/s;
     if ( im.Data[row,col] < mean*(100-pct)/100.0) then im.Data[row,col] := 0
                                                  else im.Data[row,col] := 255;
     col := col + _inc;
   end;
  im.Invert;
  result := im;
end;

function ThreshOtuDisc ( const ImgIn : TOcrImage ) : Integer;
var
  width, height,          (* image size *)
  nHistM1,
  x, y,                   (* image coordinates *)
  i, j, n : Integer;
  m0Low, m0High, m1Low, m1High, varLow, varHigh,
  varWithin, varWMin : Double;
  prob : array [0..NHIST-1] of double;
  iHist : array [0..NHIST-1] of integer;     (* hist. of intensities *)
begin
 (* allocate input and output image memory *)
  height := imgIn.Nr;
  width := imgIn.Nc;
 (* compile histogram *)
 FillChar ( iHist[0], NHIST * SizeOf(Integer), 0 );
 // for i := 0 to pred ( NHIST ) do iHist[i] := 0;
  n := 0;
  for y := 0 to pred ( height ) do
    for x := 0 to pred ( width ) do
     begin
      inc(iHist[imgIn.Data[y,x]]);
      inc(n);
     end;
(* compute probabilities *)
  for i := 0 to pred ( NHIST ) do prob[i] := iHist[i] / n;

(* find best threshold by computing moments for all thresholds *)
  nHistM1 := NHIST - 1;
  result := 0;
  varWMin := 100000000.0;
  for  i := 1 to pred ( nHistM1 ) do
   begin
    m0Low  := 0.0;
    m0High := 0.0;
    m1Low  := 0.0;
    m1High := 0.0;
    varLow := 0.0;
    varHigh := 0.0;
    for j := 0 to i do
     begin
      m0Low := m0Low + prob[j];
      m1Low := m1Low + j * prob[j];
     end;
    if ( m0Low <> 0.0 ) then m1Low := m1Low / m0Low
                        else m1Low := i;
    for j := i + 1 to pred ( NHIST ) do
     begin
      m0High := m0High + prob[j];
      m1High := m1High + j * prob[j];
     end;
    if ( m0High <> 0 ) then m1High := m1High / m0High
                       else m1High := 1;
    for j := 0 to i do
        varLow := varLow + ( (j - m1Low) * (j - m1Low) * prob[j] );
    for j := i + 1 to pred ( NHIST ) do
        varHigh := varHigh + ( (j - m1High) * (j - m1High) * prob[j] );

    varWithin := m0Low * varLow + m0High * varHigh;
    if (varWithin < varWMin) then
     begin
      varWMin := varWithin;
      result := i;
    end;
  end;
end;
cu Ha-Jö
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 11:24 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