RED-5381: Fixed spit by ruling
This commit is contained in:
parent
15c131d6c4
commit
c23dd86b6d
@ -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) {
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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())
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user