RED-5381: Fixed spit by ruling

This commit is contained in:
deiflaender 2022-10-17 10:56:10 +02:00
parent 15c131d6c4
commit c23dd86b6d
8 changed files with 171 additions and 105 deletions

View File

@ -3,6 +3,7 @@ package com.iqser.red.service.redaction.v1.server.classification.service;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
@ -33,7 +34,7 @@ public class BlockificationService {
public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines, public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines,
List<Ruling> verticalRulingLines, PDRectangle cropbox) { List<Ruling> verticalRulingLines, int rotation, PDRectangle cropbox) {
// sortRotatedSequences(textPositions); // sortRotatedSequences(textPositions);
@ -53,14 +54,14 @@ public class BlockificationService {
boolean xIsBeforeFirstX = prev != null && word.getX1() < minX; boolean xIsBeforeFirstX = prev != null && word.getX1() < minX;
boolean newLineAfterSplit = prev != null && word.getY1() != prev.getY1() && wasSplitted && splitX1 != word.getX1(); boolean newLineAfterSplit = prev != null && word.getY1() != prev.getY1() && wasSplitted && splitX1 != word.getX1();
boolean splittedByRuling = boolean splittedByRuling =
isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), verticalRulingLines,cropbox.getHeight()) || isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), verticalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight()) ||
isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), horizontalRulingLines,cropbox.getHeight()) isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), horizontalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight())
|| isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), horizontalRulingLines,cropbox.getHeight()) || isSplittedByRuling(maxX, minY, word.getX1(), word.getY1(), horizontalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight())
|| isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), verticalRulingLines,cropbox.getHeight()); || isSplittedByRuling(minX, minY, word.getX1(), word.getY2(), verticalRulingLines, word.getDir().getDegrees(), cropbox.getWidth(), cropbox.getHeight());
boolean splitByDir = prev != null && !prev.getDir().equals(word.getDir()); boolean splitByDir = prev != null && !prev.getDir().equals(word.getDir());
if (prev != null && (lineSeparation || startFromTop || xIsBeforeFirstX || splitByX || splitByDir || startFromTop)) { if (prev != null && (lineSeparation || startFromTop || xIsBeforeFirstX || splitByX || splitByDir || startFromTop || splittedByRuling)) {
Orientation prevOrientation = null; Orientation prevOrientation = null;
if (!chunkBlockList1.isEmpty()) { if (!chunkBlockList1.isEmpty()) {
@ -112,55 +113,55 @@ public class BlockificationService {
chunkBlockList1.add(cb1); chunkBlockList1.add(cb1);
} }
// Iterator<AbstractTextContainer> itty = chunkBlockList1.iterator(); Iterator<AbstractTextContainer> itty = chunkBlockList1.iterator();
//
// TextBlock previousLeft = null; TextBlock previousLeft = null;
// TextBlock previousRight = null; TextBlock previousRight = null;
// while (itty.hasNext()) { while (itty.hasNext()) {
// TextBlock block = (TextBlock) itty.next(); TextBlock block = (TextBlock) itty.next();
//
// if (previousLeft != null && block.getOrientation().equals(Orientation.LEFT)) { if (previousLeft != null && block.getOrientation().equals(Orientation.LEFT)) {
// if (previousLeft.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousLeft if (previousLeft.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousLeft
// .getMinY()) { .getMinY()) {
// previousLeft.add(block); previousLeft.add(block);
// itty.remove(); itty.remove();
// continue; continue;
// } }
// } }
//
// if (previousRight != null && block.getOrientation().equals(Orientation.RIGHT)) { if (previousRight != null && block.getOrientation().equals(Orientation.RIGHT)) {
// if (previousRight.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousRight if (previousRight.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousRight
// .getMinY()) { .getMinY()) {
// previousRight.add(block); previousRight.add(block);
// itty.remove(); itty.remove();
// continue; continue;
// } }
// } }
//
// if (block.getOrientation().equals(Orientation.LEFT)) { if (block.getOrientation().equals(Orientation.LEFT)) {
// previousLeft = block; previousLeft = block;
// } else if (block.getOrientation().equals(Orientation.RIGHT)) { } else if (block.getOrientation().equals(Orientation.RIGHT)) {
// previousRight = block; previousRight = block;
// } }
// } }
//
// itty = chunkBlockList1.iterator(); itty = chunkBlockList1.iterator();
// TextBlock previous = null; TextBlock previous = null;
// while (itty.hasNext()) { while (itty.hasNext()) {
// TextBlock block = (TextBlock) itty.next(); TextBlock block = (TextBlock) itty.next();
//
// if (previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation() if (previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation()
// .equals(Orientation.LEFT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY()) || previous != null && previous .equals(Orientation.LEFT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY()) || previous != null && previous
// .getOrientation() .getOrientation()
// .equals(Orientation.LEFT) && block.getOrientation() .equals(Orientation.LEFT) && block.getOrientation()
// .equals(Orientation.RIGHT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY())) { .equals(Orientation.RIGHT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY())) {
// previous.add(block); previous.add(block);
// itty.remove(); itty.remove();
// continue; continue;
// } }
//
// previous = block; previous = block;
// } }
return new Page(chunkBlockList1); return new Page(chunkBlockList1);
} }
@ -221,10 +222,10 @@ public class BlockificationService {
private boolean isSplittedByRuling(float previousX2, float previousY1, float currentX1, float currentY1, private boolean isSplittedByRuling(float previousX2, float previousY1, float currentX1, float currentY1,
List<Ruling> rulingLines, float pageHeight) { List<Ruling> rulingLines, float rotation, float pageWidth, float pageHeight) {
for (Ruling ruling : rulingLines) { for (Ruling ruling : rulingLines) {
var line = new Line2D.Float(pageHeight -ruling.y1 , ruling.x1, pageHeight -ruling.y2, ruling.x2); var line = convertToJavaCoord(ruling, rotation, pageWidth, pageHeight);
if (line.intersectsLine(previousX2, previousY1, currentX1, currentY1)) { if (line.intersectsLine(previousX2, previousY1, currentX1, currentY1)) {
return true; return true;
} }
@ -233,6 +234,74 @@ public class BlockificationService {
} }
private Line2D.Float convertToJavaCoord(Ruling ruling, float rotation, float pageWidth, float pageHeight){
return new Line2D.Float(convertPoint(ruling.x1, ruling.y1, rotation, pageWidth, pageHeight), convertPoint(ruling.x2, ruling.y2, rotation, pageWidth, pageHeight));
}
private Point2D convertPoint(float x, float y, float rotation, float pageWidth, float pageHeight){
var xAdj = getXRot(x,y,rotation, pageWidth, pageHeight);
var yAdj = 0f;
if (rotation == 0 || rotation == 180)
{
yAdj = pageHeight - getYLowerLeftRot(x,y,rotation, pageWidth, pageHeight);
}
else
{
yAdj = pageWidth - getYLowerLeftRot(x,y,rotation, pageWidth, pageHeight);
}
return new Point2D.Float(xAdj, yAdj);
}
private float getXRot(float x, float y, float rotation, float pageWidth, float pageHeight)
{
if (rotation == 0)
{
return x;
}
else if (rotation == 90)
{
return y;
}
else if (rotation == 180)
{
return pageWidth - x;
}
else if (rotation == 270)
{
return pageHeight - y;
}
return 0;
}
private float getYLowerLeftRot(float x, float y, float rotation, float pageWidth, float pageHeight)
{
if (rotation == 0)
{
return y;
}
else if (rotation == 90)
{
return pageWidth - x;
}
else if (rotation == 180)
{
return pageHeight - y;
}
else if (rotation == 270)
{
return x;
}
return 0;
}
public Rectangle calculateBodyTextFrame(List<Page> pages, FloatFrequencyCounter documentFontSizeCounter, public Rectangle calculateBodyTextFrame(List<Page> pages, FloatFrequencyCounter documentFontSizeCounter,
boolean landscape) { boolean landscape) {

View File

@ -106,7 +106,7 @@ public class PdfSegmentationService {
PDRectangle cropbox = pdPage.getCropBox(); PDRectangle cropbox = pdPage.getCropBox();
CleanRulings cleanRulings = rulingCleaningService.getCleanRulings(pdfTableCells.get(pageNumber), stripper.getRulings(), stripper.getMinCharWidth(), stripper.getMaxCharHeight()); CleanRulings cleanRulings = rulingCleaningService.getCleanRulings(pdfTableCells.get(pageNumber), stripper.getRulings(), stripper.getMinCharWidth(), stripper.getMaxCharHeight());
Page page = blockificationService.blockify(stripper.getTextPositionSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical(), cropbox); Page page = blockificationService.blockify(stripper.getTextPositionSequences(), cleanRulings.getHorizontal(), cleanRulings.getVertical(), rotation, cropbox);
float cropboxArea = cropbox.getHeight() * cropbox.getWidth(); float cropboxArea = cropbox.getHeight() * cropbox.getWidth();

View File

@ -4,6 +4,7 @@ import com.dslplatform.json.JsonAttribute;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.iqser.red.service.redaction.v1.model.Rectangle; import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.server.classification.model.Orientation; import com.iqser.red.service.redaction.v1.server.classification.model.Orientation;
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -30,35 +31,31 @@ public abstract class AbstractTextContainer {
@JsonIgnore @JsonIgnore
private Orientation orientation = Orientation.NONE; private Orientation orientation = Orientation.NONE;
public abstract String getText(); public abstract String getText();
public boolean contains(AbstractTextContainer other) { public boolean containsBlock(TextBlock other) {
return this.minX <= other.getX1() && this.maxX >= other.getX2() && this.minY >= other.getY1() && this.maxY <= other.getY2();
}
public boolean contains(AbstractTextContainer other) {
return this.minX <= other.minX && this.maxX >= other.maxX && this.minY >= other.minY && this.maxY <= other.maxY; return this.minX <= other.minX && this.maxX >= other.maxX && this.minY >= other.minY && this.maxY <= other.maxY;
} }
public boolean contains(Rectangle other) { public boolean contains(Rectangle other) {
return page == other.getPage() && this.minX <= other.getTopLeft().getX() && this.maxX >= other.getTopLeft().getX() + other.getWidth() && this.minY <= other.getTopLeft().getY() && this.maxY >= other.getTopLeft().getY() + other.getHeight();
return page == other.getPage() && this.minX <= other.getTopLeft().getX() && this.maxX >= other.getTopLeft().getX() + other.getWidth() && this.minY <= other.getTopLeft()
.getY() && this.maxY >= other.getTopLeft().getY() + other.getHeight();
} }
@JsonIgnore @JsonIgnore
@JsonAttribute(ignore = true) @JsonAttribute(ignore = true)
public float getHeight() { public float getHeight() {
return maxY - minY; return maxY - minY;
} }
@JsonIgnore @JsonIgnore
@JsonAttribute(ignore = true) @JsonAttribute(ignore = true)
public float getWidth() { public float getWidth() {
return maxX - minX; return maxX - minX;
} }

View File

@ -94,7 +94,7 @@ public class TableExtractionService {
Iterator<AbstractTextContainer> itty = page.getTextBlocks().iterator(); Iterator<AbstractTextContainer> itty = page.getTextBlocks().iterator();
while (itty.hasNext()) { while (itty.hasNext()) {
AbstractTextContainer textBlock = itty.next(); AbstractTextContainer textBlock = itty.next();
if (table.contains(textBlock) && position == -1) { if (textBlock instanceof TextBlock ? table.containsBlock((TextBlock) textBlock) : table.contains(textBlock) && position == -1) {
position = page.getTextBlocks().indexOf(textBlock); position = page.getTextBlocks().indexOf(textBlock);
} }
} }

View File

@ -97,41 +97,41 @@ public class PdfVisualisationService {
contentStream.addRect(textBlock.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1()); contentStream.addRect(textBlock.getX1(), textBlock.getY1(), textBlock.getX2() - textBlock.getX1(), textBlock.getY2() - textBlock.getY1());
contentStream.stroke(); contentStream.stroke();
if (textBlock.getClassification() != null) { // if (textBlock.getClassification() != null) {
contentStream.beginText(); // contentStream.beginText();
//
contentStream.setFont(PDType1Font.TIMES_ROMAN, 6f); // contentStream.setFont(PDType1Font.TIMES_ROMAN, 6f);
//
contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2() + 2); // contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2() + 2);
contentStream.showText(textBlock.getClassification() + textBlock.getOrientation() + "-->" + textBlock.getSequences().get(0).getDir()); // contentStream.showText(textBlock.getClassification() + textBlock.getOrientation() + "-->" + textBlock.getSequences().get(0).getDir());
//
contentStream.endText(); // contentStream.endText();
//
//
contentStream.setNonStrokingColor(Color.BLUE); // contentStream.setNonStrokingColor(Color.BLUE);
contentStream.setFont(PDType1Font.TIMES_ROMAN, 2f); // contentStream.setFont(PDType1Font.TIMES_ROMAN, 2f);
//
//
//
contentStream.beginText(); // contentStream.beginText();
contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY1()); // contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY1());
contentStream.showText("MinX,MinY(" + textBlock.getX1() + "," + textBlock.getY1() + ")"); // contentStream.showText("MinX,MinY(" + textBlock.getX1() + "," + textBlock.getY1() + ")");
contentStream.endText(); // contentStream.endText();
contentStream.beginText(); // contentStream.beginText();
contentStream.newLineAtOffset(textBlock.getX2(), textBlock.getY1()); // contentStream.newLineAtOffset(textBlock.getX2(), textBlock.getY1());
contentStream.showText("MaxX,MinY(" + textBlock.getX2() + "," + textBlock.getY1() + ")"); // contentStream.showText("MaxX,MinY(" + textBlock.getX2() + "," + textBlock.getY1() + ")");
contentStream.endText(); // contentStream.endText();
contentStream.beginText(); // contentStream.beginText();
contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2()); // contentStream.newLineAtOffset(textBlock.getX1(), textBlock.getY2());
contentStream.showText("MinX,MaxY(" + textBlock.getX1() + "," + textBlock.getY2() + ")"); // contentStream.showText("MinX,MaxY(" + textBlock.getX1() + "," + textBlock.getY2() + ")");
contentStream.endText(); // contentStream.endText();
contentStream.beginText(); // contentStream.beginText();
contentStream.newLineAtOffset(textBlock.getX2(), textBlock.getY2()); // contentStream.newLineAtOffset(textBlock.getX2(), textBlock.getY2());
contentStream.showText("MaxX,MaxY(" + textBlock.getX2() + "," + textBlock.getY2() + ")"); // contentStream.showText("MaxX,MaxY(" + textBlock.getX2() + "," + textBlock.getY2() + ")");
//
//
contentStream.endText(); // contentStream.endText();
} // }
} }

View File

@ -1098,7 +1098,7 @@ public class RedactionIntegrationTest {
System.out.println("classificationTest"); System.out.println("classificationTest");
AnalyzeRequest request = prepareStorage("files/new/VV-511309_OCR.pdf"); AnalyzeRequest request = prepareStorage("files/Metolachlor/S-Metolachlor_RAR_01_Volume_1_2018-09-06.pdf");
RedactionRequest redactionRequest = RedactionRequest.builder() RedactionRequest redactionRequest = RedactionRequest.builder()
.dossierId(request.getDossierId()) .dossierId(request.getDossierId())