package net.hearthstats.game.ocr;
import net.hearthstats.game.ScreenConfig;
import net.sourceforge.tess4j.TessAPI;
import java.awt.image.BufferedImage;
/**
* Performs OCR on images that contain a deck name in the top-right corner of the screen.
*/
public class DeckNameOcr extends OcrBase {
@Override
protected BufferedImage crop(BufferedImage image, int iteration) {
float ratio = ScreenConfig.getRatio(image);
int xOffset = ScreenConfig.getXOffset(image, ratio);
int x = (int) (1256 * ratio + xOffset);
int y = (int) (65 * ratio);
int width = (int) (262 * ratio);
int height = (int) (34 * ratio);
return image.getSubimage(x, y, width, height);
}
@Override
protected String parseString(String ocrResult, int iteration) {
// Opponent names could be just about anything, so only trim spaces at the start and end
return ocrResult == null ? "" : ocrResult.trim();
}
@Override
protected boolean tryProcessingAgain(String ocrResult, int iteration) {
// Only try processing the deck name once
return false;
}
@Override
protected String getFilename() {
return "deckname";
}
@Override
protected BufferedImage filter(BufferedImage image, int iteration) throws OcrException {
int width = image.getWidth();
int height = image.getHeight();
int bigWidth = width * 2;
int bigHeight = height * 2;
BufferedImage newImage = new BufferedImage(bigWidth, bigHeight, BufferedImage.TYPE_INT_RGB);
newImage.createGraphics();
// Extract only the black & white parts of the image, removing any coloured parts. This results in just the
// deck name being left... all of the background *should* magically disappear.
// First pass: identifies which pixels are coloured, which are black & white
short[][] levelArray = new short[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
// Get the individual components of this pixel
int inputRgba = image.getRGB(x, y);
int red = (inputRgba >> 16) & 0xFF;
int green = (inputRgba >> 8) & 0xFF;
int blue = (inputRgba >> 0) & 0xFF;
// If the pixel is coloured, exclude it
if (Math.abs(red - green) > 1 || Math.abs(red - blue) > 1 || Math.abs(green - blue) > 1) {
levelArray[x][y] = -1;
} else {
levelArray[x][y] = (short) red; // (255 - red);
}
}
}
// Second pass: draws a new image in black & white that excludes all the background
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
short level;
// If any of the neighbouring pixels is excluded, then exclude this pixel too - this avoids orphaned pixels
if (levelArray[x][y] == -1 // this pixel is excluded
|| (x > 0 && levelArray[x-1][y] == -1) // left pixel is excluded
|| (x + 1 < width && levelArray[x+1][y] == -1) // right pixel is excluded
|| (y > 0 && levelArray[x][y-1] == -1) // top pixel is excluded
|| (y + 1 < height && levelArray[x][y+1] == -1) // bottom pixel is excluded
) {
level = 255;
} else {
level = (short) (255 - levelArray[x][y]);
}
int outputRgba = ((255 & 0xFF) << 24) |
((level & 0xFF) << 16) |
((level & 0xFF) << 8) |
((level & 0xFF) << 0);
int x2 = x << 1;
int y2 = y << 1;
newImage.setRGB(x2, y2, outputRgba);
newImage.setRGB(x2 + 1, y2, outputRgba);
newImage.setRGB(x2, y2 + 1, outputRgba);
newImage.setRGB(x2 + 1, y2 + 1, outputRgba);
}
}
return newImage;
}
@Override
protected int getTesseractPageSegMode(int iteration) {
return TessAPI.TessPageSegMode.PSM_SINGLE_LINE;
}
}