blob: 00545da0a33fabb41709ddbdc976ef11edc388aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2008 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Junji MAEDA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.visualization.engines.lowvision.image;
import java.awt.image.BufferedImage;
import java.io.PrintWriter;
import java.util.Vector;
import org.eclipse.actf.model.ui.editor.ImagePositionInfo;
import org.eclipse.actf.visualization.engines.lowvision.LowVisionCommon;
import org.eclipse.actf.visualization.engines.lowvision.LowVisionType;
import org.eclipse.actf.visualization.engines.lowvision.character.CandidateCharacter;
import org.eclipse.actf.visualization.engines.lowvision.character.CandidateUnderlinedCharacter;
import org.eclipse.actf.visualization.engines.lowvision.character.CharacterMS;
import org.eclipse.actf.visualization.engines.lowvision.character.CharacterSM;
import org.eclipse.actf.visualization.engines.lowvision.character.CharacterSS;
import org.eclipse.actf.visualization.engines.lowvision.checker.CharacterChecker;
import org.eclipse.actf.visualization.engines.lowvision.internal.util.DebugUtil;
import org.eclipse.actf.visualization.engines.lowvision.io.ImageReader;
import org.eclipse.actf.visualization.engines.lowvision.io.LowVisionIOException;
import org.eclipse.actf.visualization.engines.lowvision.problem.LowVisionProblemException;
import org.eclipse.actf.visualization.engines.lowvision.problem.LowVisionProblemGroup;
import org.eclipse.actf.visualization.engines.lowvision.util.DecisionMaker;
/*
* Rednered image of Web page
*
*/
public class PageImage implements LowVisionCommon {
private static final boolean DO_CHECK_CHARACTERS = false;
private static final boolean DO_CHECK_IMAGES = true;
// private static final boolean DO_CHAR_TEST = false;
Int2D pixel = null;
int numContainers; // containers.length;
Container[] containers;
int numNonContainedCharacters; // nonContainedCharacters.length
CharacterSM[] nonContainedCharacters; // SM Char
boolean extractedFlag = false; //
ImagePositionInfo[] imagePositions = null;
boolean useImagePositions = false;
InteriorImage[] interiorImageArray = null;
int currentContainerID = 1;
int[][] containerMap = null;
// for debug (TBD move back into extractCharacters())
Vector<Container> containerVector = new Vector<Container>();
Vector<CandidateCharacter> candidateCharacterVector = new Vector<CandidateCharacter>();
Vector<CandidateUnderlinedCharacter> candidateUnderlinedCharacterVector = new Vector<CandidateUnderlinedCharacter>();
PrintWriter writer = null;
public PageImage() {
}
public PageImage(Int2D _i2d) {
this(_i2d, true);
}
public PageImage(Int2D _i2d, boolean _removeScrollBar) {
Int2D i2d = null;
if (_removeScrollBar) {
if (LowVisionCommon.REMOVE_SURROUNDINGS) {
try {
i2d = _i2d.cutMargin(LowVisionCommon.SURROUNDINGS_WIDTH);
} catch (ImageException ie) {
// ie.printStackTrace();
i2d = _i2d;
}
} else {
i2d = _i2d;
}
if (LowVisionCommon.REMOVE_SCROLL_BAR_AT_RIGHT) {
Int2D tmpI2d = new Int2D(i2d.width
- LowVisionCommon.SCROLL_BAR_WIDTH, i2d.height);
for (int j = 0; j < tmpI2d.height; j++) {
for (int i = 0; i < tmpI2d.width; i++) {
tmpI2d.data[j][i] = i2d.data[j][i];
}
}
i2d = tmpI2d;
}
if (LowVisionCommon.REMOVE_SCROLL_BAR_AT_BOTTOM) {
Int2D tmpI2d = new Int2D(i2d.width, i2d.height
- LowVisionCommon.SCROLL_BAR_WIDTH);
for (int j = 0; j < tmpI2d.height; j++) {
for (int i = 0; i < tmpI2d.width; i++) {
tmpI2d.data[j][i] = i2d.data[j][i];
}
}
i2d = tmpI2d;
}
} else {
i2d = _i2d;
}
pixel = i2d.deepCopy();
i2d = null;
}
public void init(BufferedImage _bi) throws ImageException {
pixel = ImageUtil.bufferedImageToInt2D(_bi);
}
// for debug
public static PageImage readFromFile(String _fileName)
throws LowVisionIOException {
BufferedImage bi = ImageReader.readBufferedImage(_fileName);
// PageImage pi = new PageImage( bi );
Int2D i2d = new Int2D(bi);
PageImage pi = new PageImage(i2d);
return (pi);
}
public int getWidth() {
return (pixel.width);
}
public int getHeight() {
return (pixel.height);
}
public int[][] getPixelData() {
return (pixel.data);
}
public BufferedImage getBufferedImage() {
return (ImageUtil.int2DToBufferedImage(pixel));
}
public Int2D getInt2D() {
return (pixel);
}
public void disposeInt2D() {
pixel = new Int2D(0, 0);
}
public int getNumContainers() {
return (numContainers);
}
public Container[] getContainers() {
return (containers);
}
public int getNumSMCharacters() {
return (numNonContainedCharacters);
}
public CharacterSM[] getSMCharacters() {
return (nonContainedCharacters);
}
public int getNumNonContainedCharacters() {
return numNonContainedCharacters;
}
public CharacterSM[] getNonContainedCharacters() {
return nonContainedCharacters;
}
public void setWriter(PrintWriter _pw) {
writer = _pw;
}
public ImagePositionInfo[] getInteriorImagePosition() {
return (imagePositions);
}
public void setInteriorImagePosition(ImagePositionInfo[] infoArray) {
if (infoArray != null) {
imagePositions = infoArray;
}
}
public boolean isInteriorImageArraySet() {
if (interiorImageArray == null || interiorImageArray.length == 0) {
return (false);
} else {
return (true);
}
}
/*
* Estimate character/image positions in the PageImage.
*/
public void extractCharacters() throws ImageException {
if (DO_CHECK_CHARACTERS) {
extractAllCharacters();
}
if (DO_CHECK_IMAGES && imagePositions != null
&& imagePositions.length > 0) {
useImagePositions = true;
// for memory (create InteriorImages for each time (degrade
// performance))
// extractInteriorImages();
}
}
/*
* Extract all images in the page by using position info from DOM.
*
*/
private void extractInteriorImages() {
if (imagePositions == null)
return;
int numImages = imagePositions.length;
Vector<InteriorImage> imageVector = new Vector<InteriorImage>();
if (LowVisionCommon.REMOVE_SURROUNDINGS) {
for (int k = 0; k < numImages; k++) {
ImagePositionInfo pos = imagePositions[k];
pos.setX(pos.getX() - LowVisionCommon.SURROUNDINGS_WIDTH);
if (pos.getX() < 0) {
pos.setX(0);
}
pos.setY(pos.getY() - LowVisionCommon.SURROUNDINGS_WIDTH);
if (pos.getY() < 0) {
pos.setY(0);
}
}
}
for (int k = 0; k < numImages; k++) {
ImagePositionInfo curPos = imagePositions[k];
// InteriorImagePosition contains all image info in the Web page.
// However, PageImage only contains a part of Web page in the case
// of partial image dump. So, select images within the dumped image.
if (!isFullyContained(curPos)) {
continue;
}
InteriorImage curIm = new InteriorImage(this, curPos);
imageVector.addElement(curIm);
}
int size = imageVector.size();
if (size > 0) {
interiorImageArray = new InteriorImage[size];
for (int k = 0; k < size; k++) {
interiorImageArray[k] = (InteriorImage) (imageVector
.elementAt(k));
}
}
}
private boolean isFullyContained(ImagePositionInfo _pos) {
if (_pos.getX() + _pos.getWidth() > this.getWidth()) {
return (false);
}
if (_pos.getY() + _pos.getHeight() > this.getHeight()) {
return (false);
}
return (true);
}
private void extractAllCharacters() throws ImageException {
if (extractedFlag) {
return;
}
// TODO more improvement
int numProcessedColors = 0;
containerMap = new int[pixel.height][pixel.width];
ColorHistogram histogram = ColorHistogram.makeColorHistogram(pixel);
/*
* (1) estimate content type (container, char, etc.) from image by using
* connected components (each major color)
*/
int len = histogram.getSize();
numProcessedColors = len;
ColorHistogramBin[] histoArray = histogram.getSortedArrayByOccurrence();
for (int i = 0; i < len; i++) {
if (histoArray[i].occurrence < THRESHOLD_MIN_OCCURRENCES) {
numProcessedColors = i;
break;
}
}
for (int i = 0; i < numProcessedColors; i++) {
int curColor = histoArray[i].color;
BinaryImage binaryByColor = new BinaryImage(pixel,
BinaryImage.METHOD_SPECIFY_FOREGROUND, curColor);
// connected components
LabeledImage curLabeledImage = new LabeledImage(binaryByColor,
LabeledImage.METHOD_8_CONNECTIVITY);
int numComponents = curLabeledImage.numComponents;
ConnectedComponent[] components = curLabeledImage.components;
for (int j = 0; j < numComponents; j++) {
ConnectedComponent cc = components[j];
short type = DecisionMaker.judgeComponentType(cc, this, true);
if (type == PageComponent.CONTAINER_TYPE) {
Container tmpContainer = new Container(this,
currentContainerID, cc, curColor);
containerVector.addElement(tmpContainer);
paintContainerMap(currentContainerID, cc);
currentContainerID++;
} else if (type == PageComponent.CANDIDATE_CHARACTER_TYPE) {
CandidateCharacter tmpC = new CandidateCharacter(this, cc,
curColor);
candidateCharacterVector.addElement(tmpC);
} else if (type == PageComponent.CANDIDATE_UNDERLINED_CHARACTER_TYPE) {
CandidateUnderlinedCharacter tmpU = new CandidateUnderlinedCharacter(
this, cc, curColor);
candidateUnderlinedCharacterVector.addElement(tmpU);
} else if (type == PageComponent.OTHER_TYPE) {
;
} else {
throw new ImageException("Unexpected type = " + type);
}
}
}
// end (1)
// mark out containerMap
fillContainerMap(currentContainerID);
/*
* (2) Assign CharacterCandidates to Container
*/
int numCandChar = candidateCharacterVector.size();
for (int k = numCandChar - 1; k >= 0; k--) {
CandidateCharacter cChar = (CandidateCharacter) (candidateCharacterVector
.elementAt(k));
int w = cChar.cc.shape.width;
int i = 0;
for (; i < w; i++) {
if (cChar.cc.shape.data[0][i] != 0) {
break;
}
}
int id = containerMap[cChar.cc.top][cChar.cc.left + i];
if (id > 0) {// id of Container starts from 1
Container parentCont = containerVector.elementAt(id - 1);
cChar.setContainer(parentCont);
parentCont.candidateCharacterVector.addElement(cChar);
candidateCharacterVector.removeElementAt(k);
} // (id = 0) = does not belong to Container (= SM Char)
}
int numCandUnderChar = candidateUnderlinedCharacterVector.size();
for (int k = numCandUnderChar - 1; k >= 0; k--) {
CandidateUnderlinedCharacter cuChar = candidateUnderlinedCharacterVector
.elementAt(k);
int w = cuChar.cc.shape.width;
int i = 0;
for (; i < w; i++) {
if (cuChar.cc.shape.data[0][i] != 0) {
break;
}
}
int id = containerMap[cuChar.cc.top][cuChar.cc.left + i];
if (id > 0) {// id of Container starts from 1
Container parentCont = containerVector.elementAt(id - 1);
cuChar.setContainer(parentCont);
parentCont.candidateUnderlinedCharacterVector
.addElement(cuChar);
candidateUnderlinedCharacterVector.removeElementAt(k);
}// (id = 0) = does not belong to Container (= SM Char)
}
/*
* Other character candidates (do not belong to Container)
*/
Vector tmpSMCharacterVector = makeSMCharacterVector(
candidateCharacterVector, candidateUnderlinedCharacterVector);
this.candidateCharacterVector.removeAllElements();
this.candidateUnderlinedCharacterVector.removeAllElements();
int tmpTmpSMVecSize = tmpSMCharacterVector.size();
for (int k = tmpTmpSMVecSize - 1; k >= 0; k--) {
CharacterSM tmpSM = (CharacterSM) (tmpSMCharacterVector
.elementAt(k));
if (!(DecisionMaker.isSMCharacter(tmpSM))) {
tmpSMCharacterVector.removeElementAt(k);
}
}
this.numNonContainedCharacters = tmpSMCharacterVector.size();
this.nonContainedCharacters = new CharacterSM[numNonContainedCharacters];
for (int k = 0; k < numNonContainedCharacters; k++) {
nonContainedCharacters[k] = (CharacterSM) (tmpSMCharacterVector
.elementAt(k));
}
tmpSMCharacterVector.removeAllElements();
tmpSMCharacterVector = null;
/*
* (3) Container
*/
int numContainer = containerVector.size();
for (int k = 0; k < numContainer; k++) {
Container curCont = containerVector.elementAt(k);
int contW = curCont.cc.shape.width;
int contH = curCont.cc.shape.height;
int contX = curCont.cc.left;
int contY = curCont.cc.top;
int contColor = curCont.getColor();
BinaryImage contBin = new BinaryImage(contW, contH);
// Container (filled hole)
BinaryImage filledContBin = new BinaryImage(contW, contH);
// HashMap contMap = new HashMap();
// HashMap nonContMap = new HashMap();
// Object dummy = new Object();
for (int j = 0; j < contH; j++) {
for (int i = 0; i < contW; i++) {
int curPixel = pixel.data[j + contY][i + contX];
// distinguishable from container color?
try {
if (curPixel == contColor) {// same
contBin.data[j][i] = 1;
}
/*
* //TODO recover this? else{ Integer curInt = new
* Integer( curPixel ); if( contMap.get(curInt) != null ){ //
* similar contBin.data[j][i] = 1; continue; } if(
* nonContMap.get(curInt) != null ){ // differ continue; }
* //first time if(DecisionMaker.distinguishableColors(
* curPixel, contColor ) ){ // differ nonContMap.put(
* curInt, dummy ); } else{ // similar
*
* contBin.data[j][i] = 1; contMap.put( curInt, dummy ); } }
*/
} catch (Exception e) {
// e.printStackTrace();
throw new ImageException(
"An error occurred while making contBin.");
}
if (containerMap[j + contY][i + contX] == k + 1) {
filledContBin.data[j][i] = 1;
}
}
}
BinaryImage fgBin = BinaryImage.subtract(filledContBin, contBin);
// Find connected component
LabeledImage curLabImg = new LabeledImage(fgBin,
LabeledImage.METHOD_8_CONNECTIVITY);
int numComponents = curLabImg.numComponents;
if (numComponents == 0) {
continue;
}
ConnectedComponent[] components = curLabImg.components;
for (int l = numComponents - 1; l >= 0; l--) {
ConnectedComponent cc2 = components[l];
// convert to relative coordinates (Page)
cc2.setLeft(cc2.getLeft() + contX);
cc2.setTop(cc2.getTop() + contY);
if (collateCandidates(curCont, cc2)) {
// SS Char (or with underline)
continue;
// nothing to do here (already done in collateCandidates)
} else if (DecisionMaker.isMSCharacter(cc2)) {
int fg = -1;
if ((fg = getForegroundColor(cc2)) == -1) {
CharacterMS msc = new CharacterMS(this, cc2, curCont,
pixel);
curCont.msCharacterVector.addElement(msc);
} else {
/*
* to handle character written by using minor color in
* histogram
*/
short ssType = DecisionMaker.judgeComponentType(cc2,
this);
if (ssType == PageComponent.CANDIDATE_CHARACTER_TYPE) {
CharacterSS ssc = new CharacterSS(this, cc2,
curCont, fg);
curCont.ssCharacterVector.addElement(ssc);
} else if (ssType == PageComponent.CANDIDATE_UNDERLINED_CHARACTER_TYPE) {
CandidateUnderlinedCharacter cuc = new CandidateUnderlinedCharacter(
this, cc2, fg);
cuc.setContainer(curCont);
Vector sscVec = removeUnderlineAndGenerateSS(cuc);
for (int m = 0; m < sscVec.size(); m++) {
curCont.ssCharacterVector
.addElement((CharacterSS) (sscVec
.elementAt(m)));
}
sscVec.removeAllElements();
}
}
}
}
// remaining candidates -> SM Character
// TODO check more
Vector tmpVec = makeSMCharacterVector(
curCont.candidateCharacterVector,
curCont.candidateUnderlinedCharacterVector);
curCont.candidateCharacterVector.removeAllElements();
curCont.candidateUnderlinedCharacterVector.removeAllElements();
int tmpVecSize = tmpVec.size();
for (int l = tmpVecSize - 1; l >= 0; l--) {
CharacterSM smc = (CharacterSM) (tmpVec.elementAt(l));
if (smc.getForegroundColor() == curCont.getColor()) {
// remove elements (same color with Container)
// (e.g., hole of 'A','R' etc.)
tmpVec.removeElementAt(l);
} else if (includingMSCharacter(smc, curCont) != null) {
// remove elements contained in MS Char (*)
tmpVec.removeElementAt(l);
} else {
// check SS Character which has similar fg/bg color
// ((1)->OK but (3)->NG)
if (getBackgroundColor(smc.cc) > -1) {
CharacterSS ssc = new CharacterSS(this, smc.cc,
smc.container, smc.getForegroundColor());
curCont.ssCharacterVector.addElement(ssc);
tmpVec.removeElementAt(l);
}
}
}
/*
* Check very small MS Char. Need to do it after (*)
*/
int msVecSize = curCont.msCharacterVector.size();
for (int l = msVecSize - 1; l >= 0; l--) {
CharacterMS curMS = (CharacterMS) (curCont.msCharacterVector
.elementAt(l));
if (DecisionMaker.isTooSmallThinedMSCharacter(curMS)) {
curCont.msCharacterVector.removeElementAt(l);
}
}
curCont.ssVector2Array(); // ssCharacterVector->ssCharacters
curCont.msVector2Array(); // msCharacterVector->msCharacters
int tmptmpVecSize = tmpVec.size();
for (int l = tmptmpVecSize - 1; l >= 0; l--) {
CharacterSM tmpSM = (CharacterSM) (tmpVec.elementAt(l));
if (!(DecisionMaker.isSMCharacter(tmpSM))) {
tmpVec.removeElementAt(l);
}
}
curCont.numSMCharacters = tmpVec.size();
curCont.smCharacters = new CharacterSM[curCont.numSMCharacters];
for (int l = 0; l < curCont.numSMCharacters; l++) {
curCont.smCharacters[l] = (CharacterSM) (tmpVec.elementAt(l));
}
tmpVec.removeAllElements();
tmpVec = null;
}
// end (3)
// remove Containers without Character
for (int k = numContainer - 1; k >= 0; k--) {
Container curCont = containerVector.elementAt(k);
if (curCont.numSSCharacters == 0 && curCont.numMSCharacters == 0
&& curCont.numSMCharacters == 0) {
containerVector.removeElementAt(k);
}
}
numContainers = containerVector.size();
containers = new Container[numContainers];
for (int k = 0; k < numContainers; k++) {
containers[k] = containerVector.elementAt(k);
}
containerVector.removeAllElements();
extractedFlag = true;
}
// paint Container into ContainerMap
private void paintContainerMap(int _id, ConnectedComponent _cc) {
int w = _cc.shape.width;
int h = _cc.shape.height;
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
if (_cc.shape.data[j][i] != 0) {
containerMap[_cc.top + j][_cc.left + i] = _id;
}
}
}
}
/*
* fill hole of ContainerMap
*/
private void fillContainerMap(int _lastID) throws ImageException {
// ID=0 -> not in Container
for (int i = 1; i < _lastID; i++) {// Container ID starts from 1
fillOneContainer(i);
}
}
private void fillOneContainer(int _id) throws ImageException {
Container curCont = (Container) (containerVector.elementAt(_id - 1));
int curX0 = curCont.cc.left;
int curY0 = curCont.cc.top;
int curX1 = curX0 + curCont.cc.shape.width;
int curY1 = curY0 + curCont.cc.shape.height;
// left boundary=1,
// right boundary=2,
// both (1 pixel line)=3,
// others=0
int[][] workMap = new int[pixel.height][pixel.width];
for (int j = curY0; j < curY1; j++) {
// left boundary
boolean mostLeftFound = false;
boolean otherContainerLeft = false;
for (int i = curX0; i < curX1; i++) {
if (containerMap[j][i] == _id) {
if (!mostLeftFound) {
workMap[j][i] = 1;
mostLeftFound = true;
otherContainerLeft = false;
} else if (otherContainerLeft) {
workMap[j][i] = 1;
otherContainerLeft = false;
}
} else if (containerMap[j][i] > 0) {
otherContainerLeft = true;
}
}
// right boundary
boolean mostRightFound = false;
boolean otherContainerRight = false;
for (int i = curX1 - 1; i >= curX0; i--) {
if (containerMap[j][i] == _id) {
if (!mostRightFound) {
if (workMap[j][i] != 1) {
workMap[j][i] = 2;
} else {
workMap[j][i] = 3;
}
mostRightFound = true;
otherContainerRight = false;
} else if (otherContainerRight) {
if (workMap[j][i] != 1) {
workMap[j][i] = 2;
} else {
workMap[j][i] = 3;
}
otherContainerRight = false;
}
} else if (containerMap[j][i] > 0) {
otherContainerRight = true;
}
}
// fill between left/right boundary
boolean inTheContainer = false;
for (int i = curX0; i < curX1; i++) {
if (workMap[j][i] == 0 && inTheContainer) {
// debug (TBD remove this if sentence)
if (containerMap[j][i] != 0 && containerMap[j][i] != _id) {
DebugUtil.outMsg(this, "i = " + i + ", j = " + j);
DebugUtil.outMsg(this, "Dumping containerMap");
for (int k = 0; k < pixel.width; k++) {
System.err.print("" + containerMap[j][k]);
}
System.err.println("");
DebugUtil.outMsg(this, "Dumping workMap");
for (int k = 0; k < pixel.width; k++) {
System.err.print("" + workMap[j][k]);
}
System.err.println("");
throw new ImageException("filling error 0: id = " + _id);
}
containerMap[j][i] = _id;
} else if (workMap[j][i] == 1) {
// debug (TBD remove this if sentence)
if (inTheContainer) {
throw new ImageException("filling error 1: id = " + _id);
}
inTheContainer = true;
} else if (workMap[j][i] == 2) {
inTheContainer = false;
}
}
}
}
/*
* Collate candidates from (1) and (3) (-> SS Character)
*/
private boolean collateCandidates(Container _cont, ConnectedComponent _cc)
throws ImageException {
int numCand = _cont.candidateCharacterVector.size();
for (int k = numCand - 1; k >= 0; k--) {
CandidateCharacter cChar = _cont.candidateCharacterVector
.elementAt(k);
if (_cc.equals(cChar.cc)) {
// (confirmed) SS Character
CharacterSS ssc = new CharacterSS(cChar);
_cont.ssCharacterVector.addElement(ssc);
_cont.candidateCharacterVector.removeElementAt(k);
return (true);
}
}
int numUCand = _cont.candidateUnderlinedCharacterVector.size();
for (int k = numUCand - 1; k >= 0; k--) {
CandidateUnderlinedCharacter cuChar = _cont.candidateUnderlinedCharacterVector
.elementAt(k);
if (_cc.equals(cuChar.cc)) {
// (confirmed) Underlined SS Character
Vector sscVec = removeUnderlineAndGenerateSS(cuChar);
for (int l = 0; l < sscVec.size(); l++) {
_cont.ssCharacterVector.addElement((CharacterSS) (sscVec
.elementAt(l)));
}
_cont.candidateUnderlinedCharacterVector.removeElementAt(k);
return (true);
}
}
return (false);
}
/*
* Returns fg color of connected component (int) color: single fg color -1:
* multiple fg color/no fg color
*/
private int getForegroundColor(ConnectedComponent _cc) {
int fg = -1;
for (int j = 0; j < _cc.shape.height; j++) {
for (int i = 0; i < _cc.shape.width; i++) {
if (_cc.shape.data[j][i] != 0) {
if (fg == -1) {
fg = pixel.data[j + _cc.top][i + _cc.left];
} else if (fg != pixel.data[j + _cc.top][i + _cc.left]) {
return (-1);
}
}
}
}
return (fg);
}
/*
* Returns bg color of connected component (int) color: single bg color -1:
* multiple bg color/no bg color
*/
private int getBackgroundColor(ConnectedComponent _cc) {
int bg = -1;
for (int j = 0; j < _cc.shape.height; j++) {
for (int i = 0; i < _cc.shape.width; i++) {
if (_cc.shape.data[j][i] == 0) {
if (bg == -1) {
bg = pixel.data[j + _cc.top][i + _cc.left];
} else if (bg != pixel.data[j + _cc.top][i + _cc.left]) {
return (-1);
}
}
}
}
return (bg);
}
// Create SM Characters from candidateCharacter/candidateUnderlinedCharacter
private Vector makeSMCharacterVector(Vector<CandidateCharacter> _cVec,
Vector<CandidateUnderlinedCharacter> _uVec) throws ImageException {
Vector<CharacterSM> tmpVec = new Vector<CharacterSM>();
int numRemainingChar = _cVec.size();
for (int k = 0; k < numRemainingChar; k++) {
CandidateCharacter cChar = _cVec.elementAt(k);
CharacterSM smc = new CharacterSM(cChar, pixel);
tmpVec.addElement(smc);
}
int numRemainingUnderlinedChar = _uVec.size();
for (int k = 0; k < numRemainingUnderlinedChar; k++) {
CandidateUnderlinedCharacter cuChar = _uVec.elementAt(k);
Vector smcVec = removeUnderlineAndGenerateSM(cuChar);
for (int l = 0; l < smcVec.size(); l++) {
tmpVec.addElement((CharacterSM) (smcVec.elementAt(l)));
}
}
return (tmpVec);
}
// target SM Char is contained within MS Char in the Container?
private CharacterMS includingMSCharacter(CharacterSM _smc, Container _cont) {
for (int k = 0; k < _cont.msCharacterVector.size(); k++) {
CharacterMS curMS = (CharacterMS) (_cont.msCharacterVector
.elementAt(k));
if (_smc.cc.isIncludedBy(curMS.cc)) {
return (curMS);
}
}
return (null);
}
public LowVisionProblemGroup[] checkCharacters(LowVisionType _lvType)
throws ImageException, LowVisionProblemException {
LowVisionProblemGroup[] charProblemGroupArray = null;
LowVisionProblemGroup[] imgProblemGroupArray = null;
LowVisionProblemGroup[] answerArray = null;
if (DO_CHECK_CHARACTERS) {
CharacterChecker charChecker = new CharacterChecker(this);
charProblemGroupArray = charChecker.checkAllCharacters(_lvType);
}
if (DO_CHECK_IMAGES && useImagePositions) {
// for memory (create InteriorImages for each time (degrade
// performance))
extractInteriorImages();
imgProblemGroupArray = checkInteriorImages(_lvType);
// for memory
interiorImageArray = null;
}
if (charProblemGroupArray == null) {
if (imgProblemGroupArray == null) {
answerArray = new LowVisionProblemGroup[0];
} else {
answerArray = imgProblemGroupArray;
}
} else {
if (imgProblemGroupArray == null) {
answerArray = charProblemGroupArray;
} else {
int charLen = charProblemGroupArray.length;
int imgLen = imgProblemGroupArray.length;
int allLen = charLen + imgLen;
LowVisionProblemGroup[] allProblemGroupArray = new LowVisionProblemGroup[allLen];
for (int i = 0; i < charLen; i++) {
allProblemGroupArray[i] = charProblemGroupArray[i];
}
for (int i = 0; i < imgLen; i++) {
allProblemGroupArray[charLen + i] = imgProblemGroupArray[i];
}
answerArray = allProblemGroupArray;
}
}
return (answerArray);
}
private LowVisionProblemGroup[] checkInteriorImages(LowVisionType _lvType)
throws ImageException {
if (!useImagePositions) {
return (new LowVisionProblemGroup[0]);
}
Vector<LowVisionProblemGroup> problemVector = new Vector<LowVisionProblemGroup>();
int numInteriorImages = 0;
if (interiorImageArray != null && interiorImageArray.length > 0) {
numInteriorImages = interiorImageArray.length;
}
for (int k = 0; k < numInteriorImages; k++) {
InteriorImage curIm = interiorImageArray[k];
LowVisionProblemGroup[] probArray = curIm.checkColors(_lvType);
if (probArray != null) {
int numProb = probArray.length;
for (int l = 0; l < numProb; l++) {
problemVector.addElement(probArray[l]);
}
}
}
int size = problemVector.size();
if (size > 0) {
LowVisionProblemGroup[] allProbArray = new LowVisionProblemGroup[size];
for (int k = 0; k < size; k++) {
allProbArray[k] = problemVector.elementAt(k);
}
problemVector = null;
return (allProbArray);
} else {
problemVector = null;
return (new LowVisionProblemGroup[0]);
}
}
private LabeledImage removeUnderlineAndCCL(
CandidateUnderlinedCharacter _cuChar) throws ImageException {
BinaryImage origImage = _cuChar.cc.shape;
BinaryImage lineImage = origImage.drawUnderline();
BinaryImage removedImage = origImage.subtract(lineImage);
LabeledImage li = new LabeledImage(removedImage,
LabeledImage.METHOD_8_CONNECTIVITY);
return (li);
}
private Vector removeUnderlineAndGenerateSS(
CandidateUnderlinedCharacter _cuChar) throws ImageException {
Vector<CharacterSS> ssVec = new Vector<CharacterSS>();
int offsetX = _cuChar.cc.left;
int offsetY = _cuChar.cc.top;
short conn = _cuChar.cc.connectivity;
LabeledImage li = removeUnderlineAndCCL(_cuChar);
int numCC = li.numComponents;
for (int k = 0; k < numCC; k++) {
ConnectedComponent cc = li.components[k];
cc.left += offsetX;
cc.top += offsetY;
cc.connectivity = conn;
if (DecisionMaker.judgeComponentType(cc, this) == PageComponent.CANDIDATE_CHARACTER_TYPE) {
CharacterSS ssc = new CharacterSS(this, cc, _cuChar.container,
_cuChar.getForegroundColor());
ssVec.addElement(ssc);
}
}
return (ssVec);
}
private Vector removeUnderlineAndGenerateSM(
CandidateUnderlinedCharacter _cuChar) throws ImageException {
Vector<CharacterSM> smVec = new Vector<CharacterSM>();
int offsetX = _cuChar.cc.left;
int offsetY = _cuChar.cc.top;
short conn = _cuChar.cc.connectivity;
LabeledImage li = removeUnderlineAndCCL(_cuChar);
int numCC = li.numComponents;
for (int k = 0; k < numCC; k++) {
ConnectedComponent cc = li.components[k];
cc.left += offsetX;
cc.top += offsetY;
cc.connectivity = conn;
if (DecisionMaker.judgeComponentType(cc, this) == PageComponent.CANDIDATE_CHARACTER_TYPE) {
CharacterSM smc = new CharacterSM(this, cc, _cuChar.container,
_cuChar.getForegroundColor(), pixel);
smVec.addElement(smc);
}
}
return (smVec);
}
}