2016-07-30 7 views
0

PDFファイルからテキストと画像を読み上げるアルゴリズムを開発中です。私はこの目的のためにiTextのJavaを使用し、基本的に私のアルゴリズムは次のように動作します。iTextは、テキストチャンクの位置が正しくない部分を抽出します。

  1. ページ内のすべてのテキストチャンクの座標は、iTextを使用して抽出されます。
  2. 抽出された座標を使用してRectangleオブジェクトが作成されます。このステップの後、ページ内の実際のテキストチャンクを表す四角形のオブジェクトが一揃いになります。
  3. 矩形をpdfページの実際の列に対応する大き​​なテキストブロックにグループ化します。
  4. YからXまでのテキストブロックを注文します。
  5. テキストブロックに1つずつlocationTextExtractionStrategyを適用します。

このアプローチでは、中規模から複雑なレイアウトのPDFファイルで約80%またはそれ以上の結果が得られます。私は、PDFファイルが情報を読み込み順序で保存しないため、100%の精度を得ることはほとんど不可能であることを知っています。

ここで私の正確さを高めることができますが、問題はiTextがそれをやめさせることです。私はiTextの問題を特定しました。時々、テキストチャンクの誤った場所が抽出され、アルゴリズムが正しくない場合があります。次の画像はそのための良い例です。

Actual Pdf Page Resulting Rectangles after extraction using iText

あなたは、実際のP​​DFページで列の間には明確なギャップがあることがわかります。しかし、結果の長方形には、その隙間の間にいくつかの欠陥のある長方形が含まれているため、正しい列を特定できません。

以下は、テキストチャンクの場所を抽出するために使用するコードです。私はそれらtextSegmentsに格納された座標を見て矩形オブジェクトを作成するために、得られたtextSegmentsのArrayListを使用

package com.InteliText.Extract; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Map.Entry; 

import com.itextpdf.text.Rectangle; 
import com.itextpdf.text.pdf.parser.ImageRenderInfo; 
import com.itextpdf.text.pdf.parser.LineSegment; 
import com.itextpdf.text.pdf.parser.SimpleTextExtractionStrategy; 
import com.itextpdf.text.pdf.parser.TextExtractionStrategy; 
import com.itextpdf.text.pdf.parser.TextRenderInfo; 
import com.itextpdf.text.pdf.parser.Vector; 

/* 
* THIS CLASS ACT AS THE TEXT EXTRACTOR FOR THE PREPROCESSOR 
*/ 
public class PreProcessorStrategy extends SimpleTextExtractionStrategy{ 

    private StringBuilder result = new StringBuilder(); 

    private ArrayList<Double> fontSizes = new ArrayList<Double>(); 
    private ArrayList<Double> lineSpaces = new ArrayList<Double>(); 
    private ArrayList<TextSegment> textSegments = new ArrayList<TextSegment>(); 

    Vector previousBaseLine = null; 

    @Override 
    public void beginTextBlock() { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void endTextBlock() { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void renderImage(ImageRenderInfo arg0) { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void renderText(TextRenderInfo renderInfo) { 

     //This code assumes that if the baseline changes then we're on a newline 
     Vector curBaseline = renderInfo.getBaseline().getStartPoint(); 
     Vector topRight = renderInfo.getAscentLine().getEndPoint(); 
     //System.out.println(renderInfo.getText()+"\t"+curBaseline.get(0)+"\t"+topRight.get(0)); 

     if(curBaseline.get(1) < 800 && curBaseline.get(1) > 50) { 
      // Chunk of text as a rectangle 
      Rectangle rect = new Rectangle(curBaseline.get(0), curBaseline.get(1), topRight.get(0), topRight.get(1)); 

      double curFontSize = rect.getHeight(); 
      fontSizes.add(curFontSize); 
      String text = renderInfo.getText(); 
      boolean isBullet = text.contains("•"); 
      if(!(text.equals(" ") || text.equals(" ") || text.equals(" ")) && !isBullet) { 
       double endX = topRight.get(0); 
       if(text.endsWith(" ")) 
        endX -= 8; 

       textSegments.add(new TextSegment(curBaseline.get(0),endX,curBaseline.get(1),topRight.get(1),renderInfo.getText(),curFontSize)); 
      } 

      result.append(renderInfo.getText()); 
     } 
     previousBaseLine = topRight; 
    } 

    @Override 
    public String getResultantText() { 
     // TODO Auto-generated method stub 
     return result.toString(); 
    } 

    public ArrayList<TextSegment> getResultantTextSegments() { 
     return this.textSegments; 
    } 

。私はこれがiTextのバグかもしれないと思う。

現在のところ、テキストチャンクの内容が空白で終わっている場合は、テキストチャンクを少し縮小しています。しかし、これは一時的な修正です。正しいテキストチャンクを縮小するので、これをやりたくありません。

この問題を回避する方法はありますか?または、私のコードで問題がある場合は、それを修正するのを手伝ってください。

+0

操作を示すテキストが、ボックスの一部であり、列の境界線を越える後続のスペースを示すようです。 – mkl

答えて

1

ここでは、正しい列に各矩形を割り当てることができた列を知っていたと仮定しています。右側の列の左端に線を引いた場合、その中心がその端の右または左にあるかどうかに基づいて矩形のほぼすべてを正しく割り当てることができます。したがって、問題は、異常値が存在する場合に、データを最もよく記述するパラメータ(特に右端の列の左端)を見つけることです。

統計的モデルにはまったく正しい方法があるかもしれませんが、うまくいくかもしれない簡単なハックがいくつかあると思います。

1)画像の重なり合う矩形はすべて非常に小さいようです。おそらく、指定されたサイズ以下の四角形を削除し、列がどこにあるべきかを決め、その中心が右の列の左端の左か右のどちらになるかによってそれぞれの小さな四角形を割り当てます。

2)https://en.wikipedia.org/wiki/RANSACから派生できる異常値によって汚染されたデータをフィッティングするための一般的な戦略があります。

2a)モデルを少量のデータに合わせることから始めます。あなたは2aと2bを何度も繰り返し、最良の結果を選ぶでしょう。これらのケースの1つのために選択された最初のポイントには外れ値がまったくないことが期待されます。 N個の異常値があり、データをN + 1個のチャンクに分割する場合、これらのチャンクの少なくとも1つに異常値が完全になくてはならないことに注意してください。

2b)最初にフィットしたら、すべてのデータを見て外れ値である点を見つけ出し、一時的に無視します(つまり、k個の最悪適合点を除いて)。残りの点を使用してモデルを再びフィットさせます。多くの場合、このステップを無期限に繰り返すと、最終的に何かに収束することが証明できます.k worst fitsとして識別されたポイントを変更するとフィット感が向上し、モデルを再フィットするので、変更がない場合は、プロセスが収束したと宣言します。

+0

これらの提案をありがとうございました。あなたの最初の提案は動作しません。なぜなら、いくつかのpdfファイルでは、ほぼすべての矩形がかなり小さいからです。 iTextはテキストチャンクごとに1文字しか抽出しないためです。だから小さな箱を無視すると、必要な四角形がたくさん残ってしまうかもしれません。 2番目の提案に移動すると、上の例の答えがうまくいくかもしれません。しかし、私は非常に多くのpdfページを見てきました。ほとんどすべてのテキスト行が他の列を傍受しています。そのような場合には、外れ値を無視しても良い結果は得られません...あなたはどう思いますか? –

+0

これを行う正しい方法は、矩形がどのように生成され、どこで終わるかについての統計モデルを作成し、このモデルを利用可能なデータに適合させることです。このようなことをテストしてモデルを開発するには、テストデータのコレクションが必要です。特に、質問を提供したページのように実際の状況のほとんどを表すものではない場合があります。または機械学習を使用します。ページと四角形のどの機能が重要かを選んでください(これは難しい部分です)。 Wekaは様々な機械学習スキームを試しています。 – mcdowella

関連する問題