Műszaki cikk

Táblázatok kinyerése PDF-oldalakból Delphiben a PDFiummal

A PDFium Component táblázatokat érzékel egy PDF-oldalon, és visszaadja őket cellák rácsaként sor- és oszlopátfogásokkal, fejlécsorokkal és egy megbízhatósági értékkel, az ExtractTables révén egyetlen oldalhoz, és az ExtractDocumentTables révén egy teljes dokumentumhoz. Minden táblázat egyetlen hívással CSV-vé vagy JSON-ná alakítható, és az oldaltörésen átnyúló táblázatok folytatási láncba köthetők

A PDF-nek nincs táblázatobjektuma. Egy táblázat egy PDF-ben szövegfutások olyan elrendezése, amelyet egy ember rácsként olvas, néha köréjük rajzolt vonalakkal, gyakran anélkül. A rács visszaállítása azt jelenti, hogy egy olyan szándékot rekonstruálunk, amelyet a fájl sosem rögzített, ezért minden kinyerő eszköz kicsit eltérő eredményt ad, és ezért hasznosabb egy olyan eszköz, amely megmondja a megbízhatóságát, mint egy, amelyik nem

Két érzékelési mód két táblázatfajtához

A vonalazott érzékelés a rajzolt vonalakat használja. Minden vonalazott útvonalszegmens átalakul oldalkoordinátákra az oldalobjektum mátrixán keresztül, a vízszintes és függőleges vonalak metszéspontjait veszik, és a metszéspontok összefüggő komponenseket alkotnak. Minden komponens saját rendezett X- és Y-pozíciórácsává válik, ami megakadályozza, hogy két külön táblázat ugyanazon az oldalon egyetlen értelmetlen rácsba olvadjon

Az üreshely-érzékelés a vonalak helyett igazítással rajzolt táblázatokat kezeli. A szódobozok vizuális sorokba csoportosulnak, egy soron belüli hézagok jelöltoszlopokra bontják, és egy táblázat csak akkor kerül elfogadásra, ha legalább MinRows sor ismétel legalább MinColumns balra igazított horgonyt az AlignmentTolerance-on belül. A sorköztényező alapértelmezetten 3, ami lefedi a 12 pontos szöveg jellemző, mintegy 30 pontos alapvonal-távolságát, anélkül hogy egyetlen, több szövegfutást tartalmazó sor táblázatnak tettetné magát

Diagram a PDFium Component táblázatérzékelési láncáról Delphiben, ahol a vonalazott vonalak metszéspontjai és az üreshellyel igazított szósorok egyetlen pontozott táblázatrekordba futnak be CSV- és JSON-exporttal
A vonalazott érzékelés a rajzolt vonalakat metszi, míg az üreshely-érzékelés az igazított szódoboz-sorokat számolja; a MinRows és MinColumns korlátokat teljesítő jelöltek megbízhatósági pontszámmal és DetectionMode-dal jelennek meg
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;                    // 1-től indexelve

    Options := TPdfTableExtractionOptions.Default;
    Options.DetectRuledTables := True;
    Options.DetectWhitespaceTables := True;
    Options.MinConfidence := 0.6;            // az alapértelmezés 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;

Hogyan állíthatók vissza az egyesített cellák?

Ez az a rész, amit a naiv kinyerők elrontanak. Egy egyesített cella nem azonosítható csak a globális rácsból, mert a rács az oldal összes vonalából származik, és egy egyesített régióból egyszerűen hiányzik az a belső vonal, amely elválasztotta volna

Az itt használt szabály helyi jellegű: két szomszédos alapcella akkor egyesül, ha semmilyen határvonal nem fedi le a köztük lévő intervallumot. Egy union-find algoritmus köti össze őket, a keletkező téglalap alakú komponensek RowSpan és ColumnSpan értékekké válnak, és a szöveget középpontja alapján rendelik egy alapcellához, majd az követi azt a cellát az egyesítés gyökeréig. Ez a megközelítés a költséget is lineárisan tartja szavak plusz cellák szerint, ahelyett hogy kvadratikus keresést kapnánk minden szó minden cella elleni teszteléséből

A gyakorlati hatás az, hogy egy pénzügyi táblázat, amelyben egy egyesített "Total" fejléc három oszlopot fog át, egyetlen, hármas átfogású cellaként jelenik meg, nem pedig egy kitöltött cellaként és két rejtélyes üres cellaként

Diagram az egyesített cellák visszaállításáról a PDFium táblázatkinyerésében Delphihez, ahol egy union-find algoritmus összeköti a szomszédos alapcellákat, amikor semmilyen határvonal nem fedi le a köztük lévő intervallumot, RowSpan és ColumnSpan értékeket eredményezve
A union-find összeköti azokat a szomszédos alapcellákat, amelyek közös intervallumán nincs rajzolt határ, így egy egyesített fejléc egyetlen, beállított ColumnSpan-nel rendelkező cellaként tér vissza, nem pedig egy kitöltött cellaként üresek között

Folytatás oldalakon átnyúlva

A hosszú táblázatok oldalakon átnyúlva törnek meg, és ha minden oldal töredékét független táblázatként kezeljük, a hívónak kell összefércelnie őket. Az ExtractDocumentTables ehelyett össze tudja kötni őket, de csak szigorú feltételek mellett: a töredéknek a korábbi oldal legalsó táblázatának kell lennie, a következőnek a következő oldal legfelső táblázatának, az oldalszámoknak szomszédosnak kell lenniük, és az oszlophatároknak egyezniük kell

Mind a négy feltétel együtt az, ami megakadályozza a nyilvánvaló hibát, azaz hogy a dokumentum minden négyoszlopos táblázatát egyetlen elképzelt megatáblázattá fűzzük, csak mert véletlenül ugyanannyi oszlopuk van. Ha a feltételek teljesülnek, a táblázatok egy közös folytatási csoportazonosítót és folytatási metaadatot hordoznak; ha nem, külön táblázatokat kap, és Ön dönthet

Diagram a táblázatfolytatásról PDF-oldalakon átnyúlva Delphiben, ahol négy szigorú feltétel dönti el, hogy az egyik oldal legalsó töredéke csatlakozik-e a következő oldal legfelső töredékéhez
A dokumentumszintű kinyerés csak akkor köti össze a töredékeket, ha mind a négy feltétel teljesül, megakadályozva, hogy nem összefüggő négyoszlopos táblázatok egyetlen elképzelt megatáblázattá olvadjanak

A dokumentumszintű kinyerés az oldalak között osztja meg a MaxCells és MaxTables korlátokat, ahelyett hogy oldalanként visszaállítaná őket, és egy finally blokkban állítja vissza az aktív oldalt, így egy megjelenítőben futtatott kinyerés azon az oldalon hagyja a felhasználót, ahol volt

Exportálás az adatok sérülése nélkül

Mindkét exportáló tudatos az escapelésben. A CSV mindig idézőjelbe teszi a mezőket, és megkettőzi a belső idézőjeleket, ami elkerüli azt a klasszikus hibát, amikor egy vesszőt tartalmazó cella csendben két oszloppá válik. Egyesített celláknál a tartalom csak a bal felső horgonynál jelenik meg, így egy CSV oda-vissza mentés nem duplikál egy átfogó fejlécet az általa lefedett oszlopokban

A JSON megőrzi a Unicode-ot ASCII-ba escapelés helyett, escapeli a vezérlőkaraktereket, és tartalmazza azt a metaadatot, amelyre egy fogyasztónak szüksége van a minőség megítéléséhez: érzékelési mód, megbízhatóság, határok, átfogásértékek, fejlécjelzők és folytatási információ. Ha kinyert táblázatokat táplál egy downstream rendszerbe, részesítse előnyben a JSON-t, mert egy CSV-sor nem tudja megmondani, hogy a táblázat, amelyből származik, 0,51-es megbízhatósági pontszámot kapott:

// Dokumentumszintű kinyerés, csak a megbízható táblázatok megtartásával
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;

Hangolás, és a leállás felismerése

Három beállítás számít a többinél jobban. A MinConfidence a minőségi kapu, és a 0,5 szándékosan engedékeny; emelje automatizált betöltéshez, csökkentse egy áttekintő felülethez, ahol egy ember minden eredményt megerősít. A MinColumnGap dönti el, mi számít oszlophatárnak üreshely-módban, és sűrű jelentésekben szorosan beállított táblázatoknak szükségük lehet a 12 pontos alapértelmezés csökkentésére. A MaxRowGapFactor dönti el, mikor ér véget egy táblázat a függőleges távolság alapján, ami az alkalmi üres sorokat tartalmazó táblázatoknál számít

Legyen őszinte a korlátokkal. A vonalazott táblázatok megbízhatóan kinyerhetők. A tisztán igazított üreshely-táblázatok jól kinyerhetők. A forgatott szöveget, beágyazott táblázatokat vagy másik sornak tűnő, tördelt tartalmú cellákat tartalmazó táblázatok bármilyen paraméterbeállítás mellett átvizsgálást igényelnek. Ezekhez a strukturáltszöveg-modell adja a nyersanyagot egy tartományspecifikus olvasó felépítéséhez, amit a strukturáltszöveg-blokkok és olvasási sorrend cikk ismertet

Egy hasznos párosítás: amikor egy szkennelt dokumentumban egyáltalán nincs szöveg, a táblázatérzékelésnek nincs mivel dolgoznia, amíg nem létezik szövegréteg. Adjon hozzá egyet először, ahogyan a kereshető szövegréteg hozzáadása szkennelt PDF-ekhez cikk ismerteti, majd nyerje ki. Az OCR-szolgáltató által visszaadott szódobozok pontosan az a bemenet, amelyre az üreshely-érzékelésnek szüksége van

A táblázatkinyerés, a strukturált szöveg és az újratördelés ugyanabból az oldalmodellből olvas Delphiben, C++Builderben és Lazarusban; a teljes API-t a PDFium Component for Delphi oldal ismerteti