/** * Copyright 2010 Neuroph Project http://neuroph.sourceforge.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.neuroph.contrib.ocr; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import javax.imageio.ImageIO; import org.neuroph.contrib.imgrec.FractionRgbData; /** * Contains various utility methods used for OCR. * * @author Ivana Jovicic, Vladimir Kolarevic, Marko Ivanovic, Zoran Sevarac */ public class OcrUtils { /** * This method cleans input image by replacing * all non black pixels with white pixels * @param image - input image that will be cleaned * @return - cleaned input image as BufferedImage */ public static BufferedImage blackAndWhiteCleaning(BufferedImage image) { for (int j = 0; j < image.getHeight(); j++) { for (int i = 0; i < image.getWidth(); i++) { if (image.getRGB(i, j) != -16777216) { image.setRGB(i, j, -1); } } } return image; } /** * This method cleans input image by replacing all pixels with RGB values * from -4473925 (gray) to -1 (white) with white pixels and * from -4473925 (gray) to -16777216 (black) with black pixels * @param image - input image that will be cleaned * @return - cleaned input image as BufferedImage */ public static BufferedImage blackAndGrayCleaning(BufferedImage image) { for (int j = 0; j < image.getHeight(); j++) { for (int i = 0; i < image.getWidth(); i++) { if (image.getRGB(i, j) > -4473925) { image.setRGB(i, j, -1); } else { image.setRGB(i, j, -16777216); } } } return image; } /** * This method cleans input image by replacing all pixels with RGB values * from -3092272 (light gray) to -1 (white) with white pixels and * from -3092272 (light gray) to -16777216 (black) with black pixels * @param image - input image that will be cleaned * @return - cleaned input image as BufferedImage */ public static BufferedImage blackAndLightGrayCleaning(BufferedImage image) { for (int j = 0; j < image.getHeight(); j++) { for (int i = 0; i < image.getWidth(); i++) { if (image.getRGB(i, j) > -3092272) { image.setRGB(i, j, -1); } else { image.setRGB(i, j, -16777216); } } } return image; } /** * This method cleans input image by replacing all pixels with RGB values * from RGBcolor input (the input color) to -1 (white) with white pixels and * from RGBcolor input (the input color) to -16777216 (black) with black pixels * @param image - input image that will be cleaned * @param RGBcolor - input RGB value of wanted color as reference for celaning * @return - cleaned input image as BufferedImage */ public static BufferedImage colorCleaning(BufferedImage image, int RGBcolor) { for (int j = 0; j < image.getHeight(); j++) { for (int i = 0; i < image.getWidth(); i++) { if (image.getRGB(i, j) == RGBcolor) { image.setRGB(i, j, -16777216); } else { image.setRGB(i, j, -1); } } } return image; } /** * This method loads the input Image and returns the cleaned version * @param f - input file that will be loaded as image * @return - return cleaned loaded image as BufferedImage * @throws IOException - if error occurs during loading */ public static BufferedImage loadAndCleanImage(File f) throws IOException { BufferedImage image = ImageIO.read(f); return blackAndLightGrayCleaning(image); } /** * Loads image from the file. * @param file image file * @return loaded image * @throws IOException */ public static BufferedImage loadImage(File file) throws IOException { BufferedImage image = ImageIO.read(file); return image; } /** * This method reads the image pixels until it reads the first black pixel * by height and then returns that value * @param Img - input image that will be read * @return - returns the value of height when conditions are true */ private static int trimLockup(BufferedImage Img) { for (int j = 0; j < Img.getHeight(); j++) { for (int i = 0; i < Img.getWidth(); i++) { if (Img.getRGB(i, j) == -16777216) { return j; } } } return 0; } /** * This method reads the input image from the input from * start pixel height (y1) until it reads the first next row * where all pixel are white by height and return that value * @param Img - input image that will be read * @param y1 - input start height pixel of image * @return - returns the value of height when conditions are true */ private static int trimLockdown(BufferedImage Img, int y1) { for (int j = y1 + 1; j < Img.getHeight(); j++) { int counterWhite = 0; for (int i = 0; i < Img.getWidth(); i++) { if (Img.getRGB(i, j) == -1) { counterWhite++; } } if (counterWhite == Img.getWidth()) { //this is a chek for dots over the letters i and j //so they wont be missread as dots if (j > (Img.getHeight() / 2)) { return j; } } if (j == Img.getHeight() - 1) { return j + 1; } } return 0; } /** * This method trims the input image and returns it as a BufferedImage * @param imageToTrim input image that will be trimed * @return return trimed input image as BufferedImage */ public static BufferedImage trimImage(BufferedImage imageToTrim) { int y1 = trimLockup(imageToTrim); int y2 = trimLockdown(imageToTrim, y1); int x1 = 0; int x2 = imageToTrim.getWidth(); return imageToTrim.getSubimage(x1, y1, x2 - x1, y2 - y1); } /** * Resize image to specified dimensions * @param image image to resize * @param width new image width * @param height new image height * @return resized image */ public static BufferedImage resizeImage(BufferedImage image, int width, int height) { BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = resizedImage.createGraphics(); g.drawImage(image, 0, 0, width, height, null); g.dispose(); return resizedImage; } /** * Crops (returns subimage) of specified input image at specified points. * * @param image image to crop * @param x1 top left x coordinate * @param y1 top left y coordinate * @param x2 bottom right x coordinate * @param y2 bottom right y coordinate * * @return image croped at specified points */ public static BufferedImage cropImage(BufferedImage image, int x1, int y1, int x2, int y2) { return image.getSubimage(x1, y1, x2 - x1, y2 - y1); } /** * Creates and returns image from the given text. * @param text input text * @param font text font * @return image with input text */ public static BufferedImage createImageFromText(String text, Font font) { //You may want to change these setting, or make them parameters boolean isAntiAliased = true; boolean usesFractionalMetrics = false; FontRenderContext frc = new FontRenderContext(null, isAntiAliased, usesFractionalMetrics); TextLayout layout = new TextLayout(text, font, frc); Rectangle2D bounds = layout.getBounds(); int w = (int) Math.ceil(bounds.getWidth()); int h = (int) Math.ceil(bounds.getHeight()) + 2; BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); //for example; Graphics2D g = image.createGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, w, h); g.setColor(Color.BLACK); g.setFont(font); Object antiAliased = isAntiAliased ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, antiAliased); Object fractionalMetrics = usesFractionalMetrics ? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF; g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, fractionalMetrics); g.drawString(text, (float) -bounds.getX(), (float) -bounds.getY()); g.dispose(); return image; } /** * Returns RGB data for all input images * * @param imagesData data map with characters as keys and charcter images as values * @return data map with characters as keys and image rgb data as values */ public static Map<String, FractionRgbData> getFractionRgbDataForImages(HashMap<String, BufferedImage> imagesData) { Map<String, FractionRgbData> rgbDataMap = new HashMap<String, FractionRgbData>(); for (String character : imagesData.keySet()) { StringTokenizer st = new StringTokenizer(character, "."); BufferedImage image = imagesData.get(character); rgbDataMap.put(st.nextToken(), new FractionRgbData(image)); } return rgbDataMap; } }