/**
* 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.imgrec;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/**
* This class uses a given Robot object to sample images from the screen at an
* arbitrary sampling resolution. The coordinates of the scanning rectangle
* is (x, y) expressed as a fraction of the screen resolution, with the width also being
* a fraction.
*
* For example, when the screen is 800x600 resolution, to scan a rectangle with
* xy coordinates (400,300) to xy (600, 400), use the following rectangle as an argument:
*
* new Rectangle2D.Double(0.5, 0.5, 0.25, 0.16667)
*
* Scanning using sampling is faster than scanning using a screenshot, but is
* prone to introduce tearing and shearing into the scanned image. Scanning
* from a screenshot has no tearing or shearing at the cost of speed.
*
* Also provides method for downsampling (scaling) image.
* This class is based on the code from tileclassification by Jon Tait.
*
* @author Jon Tait
*
*/
public class ImageSampler
{
/**
* Scans screen location using screenshot
* @param robot
* @param rectangleAsDecimalPercent
* @param samplingResolution
* @return image sample from the specified location
*/
public static BufferedImage scanLocationUsingScreenshot(Robot robot,
Rectangle2D.Double rectangleAsDecimalPercent, Dimension samplingResolution)
{
return scanLocationUsingScreenshot(robot, rectangleAsDecimalPercent, samplingResolution, BufferedImage.TYPE_INT_RGB);
}
/**
* Scans screen location using screenshot
* @param robot
* @param rectangleAsDecimalPercent
* @param samplingResolution
* @param imageType
* @return image sample from the specified location
*/
public static BufferedImage scanLocationUsingScreenshot(Robot robot,
Rectangle2D.Double rectangleAsDecimalPercent, Dimension samplingResolution,
int imageType)
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int inspectX = (int) Math.round((screenSize.width * rectangleAsDecimalPercent.x));
int inspectY = (int) Math.round((screenSize.height * rectangleAsDecimalPercent.y));
int inspectWidth = (int) Math.round((screenSize.width * rectangleAsDecimalPercent.width));
int inspectHeight = (int) Math.round((screenSize.height * rectangleAsDecimalPercent.height));
Rectangle screenRect = new Rectangle(inspectX, inspectY, inspectWidth, inspectHeight);
BufferedImage screenCapture = robot.createScreenCapture(screenRect);
return downSampleImage(samplingResolution, screenCapture, imageType);
}
/**
* Scales image to the specified dimension
* @param samplingResolution sampling resolution/image size
* @param bigImg image to scale
* @return image scaled/downsampled to the specified dimension/resolution
*/
public static BufferedImage downSampleImage(
Dimension samplingResolution, BufferedImage bigImg) {
return downSampleImage(samplingResolution, bigImg, BufferedImage.TYPE_INT_RGB);
}
/**
* Scales image to the specified dimension
* @param samplingResolution sampling resolution/image size
* @param bigImg image to scale
* @param returnImageType type of the return image
* @return image scaled/downsampled to the specified dimension/resolution
*/
public static BufferedImage downSampleImage(Dimension samplingResolution,
BufferedImage bigImg, int returnImageType) {
int inspectX;
int inspectY;
int numberOfSamplesAcross = samplingResolution.width;
int numberOfSamplesDown = samplingResolution.height;
if(bigImg.getWidth() <= numberOfSamplesAcross || bigImg.getHeight() <= numberOfSamplesDown) {
return bigImg;
}
BufferedImage img = new BufferedImage(
numberOfSamplesAcross, numberOfSamplesDown,
returnImageType);
double samplingIncrementX = bigImg.getWidth() / (samplingResolution.getWidth() - 1);
double samplingIncrementY = bigImg.getHeight() / (samplingResolution.getHeight() - 1);
double sampleX = 0;
double sampleY = 0;
for(int y=0; y < numberOfSamplesDown; y++) {
for(int x=0; x < numberOfSamplesAcross; x++) {
inspectX = (int) Math.round(sampleX);
inspectY = (int) Math.round(sampleY);
if(inspectX >= bigImg.getWidth()) {
inspectX = bigImg.getWidth() - 1;
}
if(inspectY >= bigImg.getHeight()) {
inspectY = bigImg.getHeight() - 1;
}
int color = bigImg.getRGB(inspectX, inspectY);
img.setRGB(x, y, color);
sampleX+=samplingIncrementX;
}
sampleX=0;
sampleY+=samplingIncrementY;
}
return img;
}
/**
* Scans screen location using sampling
* @param robot an instance of java.awt.Robot for the scaned screen
* @param rectangleAsDecimalPercent
* @param samplingResolution
* @return image sample from the specified location
*/
public static BufferedImage scanLocationUsingSampling(Robot robot,
Rectangle2D.Double rectangleAsDecimalPercent, Dimension samplingResolution)
{
return scanLocationUsingSampling(robot, rectangleAsDecimalPercent, samplingResolution, BufferedImage.TYPE_INT_RGB);
}
/**
* Scans screen location using sampling
* @param robot an instance of java.awt.Robot for the scaned screen
* @param rectangleAsDecimalPercent
* @param samplingResolution
* @param imageType
* @return image sample from the specified location
*/
public static BufferedImage scanLocationUsingSampling(Robot robot,
Rectangle2D.Double rectangleAsDecimalPercent, Dimension samplingResolution,
int imageType)
{
double slotULXAsDecimalPercent = rectangleAsDecimalPercent.x;
double slotULYAsDecimalPercent = rectangleAsDecimalPercent.y;
double sampleIncrementAcrossAsDecimalPercent = rectangleAsDecimalPercent.width / (samplingResolution.getWidth()-1);
double sampleIncrementDownAsDecimalPercent = rectangleAsDecimalPercent.height / (samplingResolution.getHeight()-1);
int numberOfSamplesAcross = samplingResolution.width;
int numberOfSamplesDown = samplingResolution.height;
BufferedImage img = new BufferedImage(
numberOfSamplesAcross, numberOfSamplesDown,
imageType);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
waitForVerticalScreenRefresh();
double inspectXAsDecimalPercent = slotULXAsDecimalPercent;
double inspectYAsDecimalPercent = slotULYAsDecimalPercent;
for(int y=0; y < numberOfSamplesDown; y++) {
for(int x=0; x < numberOfSamplesAcross; x++) {
int inspectX = (int) Math.round((screenSize.width * inspectXAsDecimalPercent));
int inspectY = (int) Math.round((screenSize.height * inspectYAsDecimalPercent));
Color color = robot.getPixelColor(inspectX, inspectY);
img.setRGB(x, y, color.getRGB());
inspectXAsDecimalPercent+=sampleIncrementAcrossAsDecimalPercent;
}
inspectXAsDecimalPercent = slotULXAsDecimalPercent;
inspectYAsDecimalPercent+=sampleIncrementDownAsDecimalPercent;
}
return img;
}
/**
* Another name for this is "Vertical Sync". Minimizes frame shearing.
*/
private static void waitForVerticalScreenRefresh()
{
Toolkit.getDefaultToolkit().sync();
}
}