Tehnični članak

Izvlečenje tabel s strani PDF v Delphiju s PDFium

PDFium Component zazna tabele na strani PDF in jih vrne kot mrežo celic z razponi vrstic in stolpcev, glavnimi vrsticami in vrednostjo zaupanja, prek ExtractTables za eno stran in ExtractDocumentTables za celoten dokument. Vsaka tabela se z enim klicem pretvori v CSV ali JSON, tabele, ki se nadaljujejo čez prelom strani, pa je mogoče povezati v verigo nadaljevanja

PDF nima objekta tabele. Tabela v PDF je nabor besedilnih nizov, postavljenih tako, da jih človek bere kot mrežo, včasih z okoli njih narisanimi črtami, pogosto pa brez njih. Obnavljanje mreže pomeni rekonstrukcijo namena, ki ga datoteka nikoli ni zabeležila, zato vsako orodje za izvlečenje ustvari nekoliko drugačne rezultate in zakaj je orodje, ki vam pove svoje zaupanje, uporabnejše od tistega, ki tega ne stori

Dva načina zaznavanja za dve vrsti tabel

Zaznavanje s črtami uporablja narisane črte. Vsak obrobljen segment poti se prek matrike objekta strani preslika v koordinate strani, vodoravne in navpične črte se sekajo, presečišča pa tvorijo povezane komponente. Vsaka komponenta postane svoja urejena mreža položajev X in Y, kar preprečuje, da bi se dve ločeni tabeli na isti strani združili v eno nesmiselno mrežo

Zaznavanje s presledki obravnava tabele, narisane s poravnavo namesto s črtami. Okvirji besed so združeni v vizualne vrstice, vrzeli znotraj vrstice jo razdelijo v kandidatne stolpce, tabela pa je sprejeta samo takrat, ko se vsaj MinRows vrstic ponovi z vsaj MinColumns levo poravnanimi sidrišči znotraj AlignmentTolerance. Faktor vrzeli med vrsticami je privzeto 3, kar pokrije približno 30-točkovni razmik osnovnih črt, tipičen za 12-točkovno besedilo, ne da bi eni sami vrstici z več besedilnimi nizi dovolil, da se izdaja za tabelo

Diagram cevovoda zaznavanja tabel PDFium Component v Delphiju, kjer presečišča narisanih črt in s presledki poravnane vrstice besed hranijo en ocenjen zapis tabele z izvozom CSV in JSON
Zaznavanje s črtami seka narisane poteze, zaznavanje s presledki pa šteje poravnane vrstice okvirjev besed; kandidati, ki presežejo MinRows in MinColumns, dobijo pripeto oceno zaupanja in DetectionMode
uses
  PDFium;

var
  Pdf: TPdf;
  Options: TPdfTableExtractionOptions;
  Tables: TPdfTables;
  I: Integer;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'annual-report.pdf';
    Pdf.LoadDocument;
    Pdf.PageNumber := 12;                    // od 1 naprej

    Options := TPdfTableExtractionOptions.Default;
    Options.DetectRuledTables := True;
    Options.DetectWhitespaceTables := True;
    Options.MinConfidence := 0.6;            // privzeto je 0,5
    Options.HeaderRowCount := 1;

    Tables := Pdf.ExtractTables(Options);
    for I := 0 to High(Tables) do
      Writeln(Format('table %d: %dx%d cells, confidence %.2f, mode %d',
        [I, Tables[I].RowCount, Tables[I].ColumnCount,
         Tables[I].Confidence, Ord(Tables[I].DetectionMode)]));

    if Length(Tables) > 0 then
      SaveText('page12-table0.csv', Tables[0].ToCsv);
  finally
    Pdf.Free;
  end;
end;

Kako se obnovijo združene celice?

To je del, kjer naivni izvlekalniki zgrešijo. Združene celice ni mogoče identificirati samo iz globalne mreže, ker je mreža izpeljana iz vseh črt na strani, združenemu območju pa preprosto manjka notranja črta, ki bi ga ločila

Pravilo, uporabljeno tukaj, je lokalno: dve sosednji osnovni celici sta združeni, kadar nobena mejna črta ne pokriva intervala med njima. Union-find ju poveže, nastali pravokotni komponenti postaneta vrednosti RowSpan in ColumnSpan, besedilo pa je dodeljeno osnovni celici po njeni sredinski točki in nato sledi tej celici do njenega korena združevanja. Tako narejeno tudi ohranja strošek linearen v besedah plus celicah, namesto kvadratnega pregleda, ki bi ga dobili s testiranjem vsake besede proti vsaki celici

Diagram obnovitve združenih celic pri izvlečenju tabel PDFium za Delphi, kjer union-find poveže sosednje osnovne celice, kadar koli nobena mejna črta ne pokriva intervala med njima, kar da RowSpan in ColumnSpan
Union-find združi sosednje osnovne celice, katerih skupni interval ne nosi narisane meje, tako da se združena glava vrne kot ena celica z nastavljenim ColumnSpan namesto ene zapolnjene celice, obdane s praznimi

Praktičen učinek je, da finančna tabela z združeno glavo "Total", ki obsega tri stolpce, pride ven kot ena celica z razponom tri, namesto ene zapolnjene celice in dveh skrivnostnih praznih

Nadaljevanje čez strani

Dolge tabele se prelomijo čez strani, obravnavanje odlomka vsake strani kot neodvisne tabele pa klicatelja sili, da jih sešije. ExtractDocumentTables jih lahko namesto tega poveže, vendar samo pod strogimi pogoji: odlomek mora biti najnižja tabela na zgodnejši strani, naslednji mora biti najvišja tabela na naslednji strani, številke strani morajo biti sosednje, meje stolpcev pa se morajo ujemati

Vsi štirje pogoji skupaj preprečujejo očitno napako, ki je verižiti vsako štiristolpčno tabelo v dokumentu v eno namišljeno mega-tabelo, ker si naključno delijo število stolpcev. Kadar pogoji držijo, si tabele delijo identifikator skupine nadaljevanja in nosijo metapodatke nadaljevanja; kadar ne držijo, dobite ločene tabele in se lahko odločite sami

Diagram nadaljevanja tabele čez strani PDF v Delphiju, kjer štirje strogi pragovi odločijo, ali se najnižji odlomek na eni strani pridruži najvišjemu odlomku na naslednji
Izvlečenje na ravni dokumenta poveže odlomke samo, kadar držijo vsi štirje pragovi, kar nepovezane štiristolpčne tabele varuje pred zlitjem v eno namišljeno mega-tabelo

Izvlečenje na ravni dokumenta si deli proračuna MaxCells in MaxTables čez strani namesto da bi ju ponastavil za vsako stran, aktivno stran pa obnovi v bloku finally, tako da zagon izvlečenja v pregledovalniku uporabnika pusti gledati stran, na kateri je bil

Izvoz brez poškodovanja podatkov

Oba izvoznika sta premišljena glede ubežnih zaporedij. CSV vedno postavi polja v narekovaje in podvoji notranje narekovaje, kar prepreči klasično napako, kjer celica z vejico tiho postane dva stolpca. Pri združenih celicah je vsebina izdana samo na zgornjem levem sidrišču, tako da krožna pot čez CSV ne podvoji razpenjajoče se glave čez stolpce, ki jih pokriva

JSON ohrani Unicode namesto da bi ga izpustil v ASCII, ubeži kontrolne znake in vključuje metapodatke, ki jih porabnik potrebuje za presojo kakovosti: način zaznavanja, zaupanje, meje, vrednosti razpona, zastavice glave in podatke o nadaljevanju. Če izvlečene tabele vnašate v poznejši sistem, dajte prednost JSON, ker vam vrstica CSV ne more povedati, da je tabela, iz katere prihaja, dosegla zaupanje 0,51:

// Izvlečenje za celoten dokument, obdrži samo tabele, vredne zaupanja
Tables := Pdf.ExtractDocumentTables(Options);
for I := 0 to High(Tables) do
begin
  if Tables[I].Confidence < 0.75 then
  begin
    Log(Format('page %d table needs review (%.2f)',
      [Tables[I].PageNumber, Tables[I].Confidence]));
    Continue;
  end;
  if Tables[I].ContinuationGroup > 0 then
    AppendToGroup(Tables[I].ContinuationGroup, Tables[I].ToJson)
  else
    EmitStandalone(Tables[I].ToJson);
end;

Prilagajanje in vedeti, kdaj nehati

Tri nastavitve so pomembnejše od ostalih. MinConfidence je vrata kakovosti, 0,5 pa je namerno prizanesljiva; povečajte jo za avtomatizirano zajemanje in znižajte za pregledni vmesnik, kjer človek potrdi vsak rezultat. MinColumnGap odloči, kaj šteje za mejo stolpca v načinu s presledki, in tesno postavljene tabele v gostih poročilih jo morda potrebujejo zmanjšano od privzete vrednosti 12 točk. MaxRowGapFactor odloči, kdaj navpična razdalja konča tabelo, kar je pomembno pri tabelah z občasnimi praznimi vrsticami

Bodite pošteni glede omejitev. Tabele s črtami se izvlečejo zanesljivo. Čisto poravnane tabele s presledki se izvlečejo dobro. Tabele z zasukanim besedilom, gnezdenimi tabelami ali celicami, katerih vsebina se prelomi v nekaj, kar je videti kot druga vrstica, bodo potrebovale pregled ne glede na to, kako so nastavljeni parametri. Zanje strukturirani besedilni model da surovino za gradnjo bralnika, specifičnega za domeno, opisano v članku strukturirani bloki besedila in vrstni red branja

Ena uporabna kombinacija: kadar skeniran dokument sploh nima besedila, zaznavanje tabel nima s čim delati, dokler ne obstaja besedilna plast. Najprej jo dodajte, kot je opisano v članku dodajanje preiskovalne besedilne plasti skeniranim PDF, nato izvlecite. Okvirji besed, ki jih vrne ponudnik OCR, so natanko tak vhod, kot ga zaznavanje s presledki potrebuje

Izvlečenje tabel, strukturirano besedilo in preoblikovanje toka vsi berejo iz istega modela strani v Delphiju, C++Builderju in Lazarusu; celoten API je opisan na strani PDFium Component for Delphi