changeset 97:5960410c77e5

Refactoring - image processing is now separated from GUI robot class.
author Pavel Tisnovsky <ptisnovs@redhat.com>
date Mon, 23 Sep 2013 17:57:39 +0200
parents 4d9f9795d258
children 994289841798
files ChangeLog Makefile src/org/thermostat/qa/framework/GuiRobot.java src/org/thermostat/qa/framework/ImageProcessing.java
diffstat 4 files changed, 261 insertions(+), 184 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Sep 20 14:43:12 2013 +0200
+++ b/ChangeLog	Mon Sep 23 17:57:39 2013 +0200
@@ -1,3 +1,11 @@
+2013-09-23  Pavel Tisnovsky  <ptisnovs@redhat.com>
+
+	* Makefile:
+	* src/org/thermostat/qa/framework/GuiRobot.java:
+	* src/org/thermostat/qa/framework/ImageProcessing.java:
+	Refactoring - image processing is now separated from
+	GUI robot class.
+
 2013-09-20  Pavel Tisnovsky  <ptisnovs@redhat.com>
 
 	* src/org/thermostat/qa/reporter/IndexPageGenerator.java:
--- a/Makefile	Fri Sep 20 14:43:12 2013 +0200
+++ b/Makefile	Mon Sep 23 17:57:39 2013 +0200
@@ -66,6 +66,7 @@
 	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/TestStatus.class \
 	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/ThermostatGuiTest.class \
 	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/ThermostatTest.class \
+	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/ImageProcessing.class \
 	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/ThermostatUtilities.class \
 	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/ThermostatOutputTextsGenerator.class \
 	$(BUILD_DIR)/$(FRAMEWORK_PACKAGE)/GuiRobot.class \
--- a/src/org/thermostat/qa/framework/GuiRobot.java	Fri Sep 20 14:43:12 2013 +0200
+++ b/src/org/thermostat/qa/framework/GuiRobot.java	Mon Sep 23 17:57:39 2013 +0200
@@ -48,13 +48,26 @@
 
 import javax.imageio.ImageIO;
 
+
+
+/**
+ * Class used for automatic mouse and keyboard system events generation. This
+ * class also contains methods for capturing the screenshot and for finding some
+ * pattern in that screenshot.
+ * 
+ * @author Pavel Tisnovsky
+ */
 public class GuiRobot
 {
-    // threshold value for a ratio between correlation and autocorrelation values
-    private static final float CORRELATION_THRESHOLD = 0.9f;
 
+    /**
+     * Number of millisecond between two consecutive robot actions.
+     */
     private static final int ROBOT_DELAY = 100;
 
+    /**
+     * Number of millisecond for key press event. 
+     */
     private static final int KEY_PRESS_DELAY = 10;
 
     Robot robot = null;
@@ -127,7 +140,7 @@
     public Rectangle findPattern(String markerFileName) throws IOException
     {
         BufferedImage marker = ImageIO.read(new File(markerFileName));
-        return findPattern(marker, getScreenCapture());
+        return ImageProcessing.findPattern(marker, getScreenCapture());
     }
 
     public void highlightRectangle(Rectangle rect)
@@ -144,11 +157,19 @@
 
         int x = rectangle.x + rectangle.width / 2;
         int y = rectangle.y + rectangle.height / 2;
-        robot.mouseMove(x, y);
-        robot.delay(ROBOT_DELAY);
-        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
-        robot.delay(ROBOT_DELAY);
-        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+        click(x, y);
+    }
+
+    /**
+     * @param x
+     * @param y
+     */
+    private void click(int x, int y) {
+        this.robot.mouseMove(x, y);
+        this.robot.delay(ROBOT_DELAY);
+        this.robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+        this.robot.delay(ROBOT_DELAY);
+        this.robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
     }
 
     public void pressKey(int keycode)
@@ -206,181 +227,5 @@
         graphics.setColor(Color.BLACK);
         graphics.draw(rect2);
     }
-    /**
-     * Create three-dimensional array with the same size as tested image
-     * dimensions (last dimension is used for storing RGB components).
-     * 
-     * @param testImage
-     *            tested image
-     * @return newly created two-dimensional array
-     */
-    private static float[][][] createArrayForOneColorComponent(BufferedImage testImage)
-    {
-        return new float[testImage.getHeight()][testImage.getWidth()][3];
-    }
-
-    /**
-     * Conversion from BufferedImage into three dimensional float arrays.
-     * It's much faster to work with float arrays even if it's memory inefficient.
-     *
-     * @param testImage
-     *            tested image
-     * @param array array to fill
-     */
-    private static void convertImageToFloatArray(BufferedImage testImage, float[][][] array)
-    {
-        float redAverage = 0;
-        float greenAverage = 0;
-        float blueAverage = 0;
-        for (int y = 0; y < testImage.getHeight(); y++)
-        {
-            for (int x = 0; x < testImage.getWidth(); x++)
-            {
-                int c = testImage.getRGB(x, y);
-                // filter out alpha channel
-                c = c & 0xffffff;
-                redAverage += ((c >> 16) & 0xff);
-                greenAverage += ((c >> 8) & 0xff);
-                blueAverage += (c & 0xff);
-            }
-        }
-        int pixels = testImage.getWidth() * testImage.getHeight();
-        redAverage /= pixels;
-        greenAverage /= pixels;
-        blueAverage /= pixels;
-        //System.out.println("red: " + redAverage);
-        //System.out.println("green: " + greenAverage);
-        //System.out.println("blue: " + blueAverage);
-
-        for (int y = 0; y < testImage.getHeight(); y++)
-        {
-            for (int x = 0; x < testImage.getWidth(); x++)
-            {
-                int c = testImage.getRGB(x, y);
-                // filter out alpha channel
-                c = c & 0xffffff;
-                array[y][x][0] = ((c >> 16) & 0xff) - redAverage;
-                array[y][x][1] = ((c >> 8) & 0xff) - greenAverage;
-                array[y][x][2] = (c & 0xff) - blueAverage;
-            }
-        }
-    }
-
-    public static Rectangle findPattern(BufferedImage marker, BufferedImage screen){
-        Rectangle actionArea = new Rectangle(0,0,screen.getWidth(),screen.getHeight());
-        Rectangle result = new Rectangle(0,0,0,0);
-        boolean found = false;
-        boolean ok = true;
-        
-        for(int x = actionArea.x; (x < (actionArea.x + actionArea.width - marker.getWidth()) ) && !found; x++){
-            for(int y= actionArea.y; (y < (actionArea.y + actionArea.height - marker.getHeight()) ) && !found; y++){
-                
-                for(int mx = 0; (mx < marker.getWidth()) && ok; mx++){
-                    for(int my = 0; (my < marker.getHeight()) && ok; my++){
-                        if(marker.getRGB(mx, my) != screen.getRGB(x+mx,y+my)){
-                            ok = false;
-                        }
-                    }
-                }
-                if( ok ){
-                    found = true;
-                    result.x = x;
-                    result.y = y;
-                    result.height = marker.getHeight();
-                    result.width = marker.getWidth();
-                }else{
-                    ok = true;
-                }                
-            }
-        }
-        
-        if(found){
-        	return result;
-        }else{
-        	return null;
-        }
-    }
-
-    private static Rectangle findBlurredPattern(BufferedImage marker, BufferedImage testImage)
-    {
-        int maxX = testImage.getWidth() - marker.getWidth() - 1;
-        int maxY = testImage.getHeight() - marker.getHeight() - 1;
-        int markerMaxX = marker.getWidth();
-        int markerMaxY = marker.getHeight();
-
-        // it is much faster to work directly with color components stored as float values
-        float[][][] testImageArray = createArrayForOneColorComponent(testImage);
-        float[][][] markerImageArray = createArrayForOneColorComponent(marker);
-
-        //System.out.println("Starting conversion");
-        convertImageToFloatArray(testImage, testImageArray);
-        convertImageToFloatArray(marker, markerImageArray);
-        //System.out.println("Conversion done");
-
-        double autocorrelation = computeCorrelation(markerMaxX, markerMaxY, markerImageArray, markerImageArray, 0, 0);
-
-        int bestX = -1;
-        int bestY = -1;
-        double bestCorrelation = -1;
-        boolean foundExact = false;
-
-        for (int yoffset = 0; (yoffset < maxY) && !foundExact; yoffset++ )
-        {
-            //System.out.println("Processing line: " + yoffset + " of " + (maxY - 1));
-            for (int xoffset = 0; (xoffset < maxX) && !foundExact; xoffset++)
-            {
-                double correlation = computeCorrelation(markerMaxX, markerMaxY, testImageArray, markerImageArray, yoffset, xoffset);
-                if (correlation > bestCorrelation)
-                {
-                    bestCorrelation = correlation;
-                    bestX = xoffset;
-                    bestY = yoffset;
-                    if (correlation == autocorrelation)
-                    {
-                        foundExact = true;
-                    }
-                }
-            }
-        }
-
-        //System.out.println(autocorrelation);
-        //System.out.println(bestCorrelation);
-        //System.out.println(bestX + " " + bestY);
-        if (bestCorrelation / autocorrelation < CORRELATION_THRESHOLD)
-        {
-            return null;
-        }
-        return new Rectangle(bestX, bestY, marker.getWidth(), marker.getHeight());
-    }
-
-    /**
-     * Compute correlation for given two images and 2D offset.
-     *
-     * @param maxX
-     * @param maxY
-     * @param testImageArray
-     * @param markerImageArray
-     * @param yoffset
-     * @param xoffset
-     * @return
-     */
-    private static double computeCorrelation(int maxX, int maxY, float[][][] testImageArray,
-                    float[][][] markerImageArray, int yoffset, int xoffset)
-    {
-        double correlation = 0;
-        for (int y = 0; y < maxY; y++)
-        {
-            for (int x = 0; x < maxX; x++)
-            {
-                for (int rgbIndex = 0; rgbIndex < 3; rgbIndex++)
-                {
-                    float colorComponent1 = markerImageArray[y][x][rgbIndex];
-                    float colorComponent2 = testImageArray[yoffset + y][xoffset + x][rgbIndex];
-                    correlation += colorComponent1 * colorComponent2;
-                }
-            }
-        }
-        return correlation;
-    }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/thermostat/qa/framework/ImageProcessing.java	Mon Sep 23 17:57:39 2013 +0200
@@ -0,0 +1,223 @@
+/*
+
+    ThermostatQA - test framework for Thermostat Monitoring Tool
+
+    Copyright 2013 Red Hat, Inc.
+
+This file is part of ThermostatQA
+
+ThermostatQA is distributed under the GNU General Public License,
+version 2 or any later version (with a special exception described
+below, commonly known as the "Classpath Exception").
+
+A copy of GNU General Public License (GPL) is included in this
+distribution, in the file COPYING.
+
+Linking ThermostatQA code with other modules is making a combined work
+based on ThermostatQA.  Thus, the terms and conditions of the GPL
+cover the whole combination.
+
+As a special exception, the copyright holders of ThermostatQA give you
+permission to link this code with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on ThermostatQA code.  If you modify ThermostatQA, you may
+extend this exception to your version of the software, but you are
+not obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version.
+*/
+
+package org.thermostat.qa.framework;
+
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+public class ImageProcessing {
+
+    /**
+     * Threshold value for a ratio between correlation and autocorrelation values.
+     * This threshold is used by the algorithm for finding some pattern in a screenshot.
+     */
+    private static final float CORRELATION_THRESHOLD = 0.9f;
+
+    /**
+     * Create three-dimensional array with the same size as tested image
+     * dimensions (last dimension is used for storing RGB components).
+     * 
+     * @param testImage
+     *            tested image
+     * @return newly created two-dimensional array
+     */
+    private static float[][][] createArrayForOneColorComponent(BufferedImage testImage)
+    {
+        return new float[testImage.getHeight()][testImage.getWidth()][3];
+    }
+
+    /**
+     * Conversion from BufferedImage into three dimensional float arrays.
+     * It's much faster to work with float arrays even if it's memory inefficient.
+     *
+     * @param testImage
+     *            tested image
+     * @param array array to fill
+     */
+    private static void convertImageToFloatArray(BufferedImage testImage, float[][][] array)
+    {
+        float redAverage = 0;
+        float greenAverage = 0;
+        float blueAverage = 0;
+        for (int y = 0; y < testImage.getHeight(); y++)
+        {
+            for (int x = 0; x < testImage.getWidth(); x++)
+            {
+                int c = testImage.getRGB(x, y);
+                // filter out alpha channel
+                c = c & 0xffffff;
+                redAverage += ((c >> 16) & 0xff);
+                greenAverage += ((c >> 8) & 0xff);
+                blueAverage += (c & 0xff);
+            }
+        }
+        int pixels = testImage.getWidth() * testImage.getHeight();
+        redAverage /= pixels;
+        greenAverage /= pixels;
+        blueAverage /= pixels;
+        //System.out.println("red: " + redAverage);
+        //System.out.println("green: " + greenAverage);
+        //System.out.println("blue: " + blueAverage);
+
+        for (int y = 0; y < testImage.getHeight(); y++)
+        {
+            for (int x = 0; x < testImage.getWidth(); x++)
+            {
+                int c = testImage.getRGB(x, y);
+                // filter out alpha channel
+                c = c & 0xffffff;
+                array[y][x][0] = ((c >> 16) & 0xff) - redAverage;
+                array[y][x][1] = ((c >> 8) & 0xff) - greenAverage;
+                array[y][x][2] = (c & 0xff) - blueAverage;
+            }
+        }
+    }
+
+    public static Rectangle findPattern(BufferedImage marker, BufferedImage screen){
+        Rectangle actionArea = new Rectangle(0,0,screen.getWidth(),screen.getHeight());
+        Rectangle result = new Rectangle(0,0,0,0);
+        boolean found = false;
+        boolean ok = true;
+        
+        for(int x = actionArea.x; (x < (actionArea.x + actionArea.width - marker.getWidth()) ) && !found; x++){
+            for(int y= actionArea.y; (y < (actionArea.y + actionArea.height - marker.getHeight()) ) && !found; y++){
+                
+                for(int mx = 0; (mx < marker.getWidth()) && ok; mx++){
+                    for(int my = 0; (my < marker.getHeight()) && ok; my++){
+                        if(marker.getRGB(mx, my) != screen.getRGB(x+mx,y+my)){
+                            ok = false;
+                        }
+                    }
+                }
+                if( ok ){
+                    found = true;
+                    result.x = x;
+                    result.y = y;
+                    result.height = marker.getHeight();
+                    result.width = marker.getWidth();
+                }else{
+                    ok = true;
+                }                
+            }
+        }
+        
+        if(found){
+            return result;
+        }else{
+            return null;
+        }
+    }
+
+    private static Rectangle findBlurredPattern(BufferedImage marker, BufferedImage testImage)
+    {
+        int maxX = testImage.getWidth() - marker.getWidth() - 1;
+        int maxY = testImage.getHeight() - marker.getHeight() - 1;
+        int markerMaxX = marker.getWidth();
+        int markerMaxY = marker.getHeight();
+
+        // it is much faster to work directly with color components stored as float values
+        float[][][] testImageArray = createArrayForOneColorComponent(testImage);
+        float[][][] markerImageArray = createArrayForOneColorComponent(marker);
+
+        //System.out.println("Starting conversion");
+        convertImageToFloatArray(testImage, testImageArray);
+        convertImageToFloatArray(marker, markerImageArray);
+        //System.out.println("Conversion done");
+
+        double autocorrelation = computeCorrelation(markerMaxX, markerMaxY, markerImageArray, markerImageArray, 0, 0);
+
+        int bestX = -1;
+        int bestY = -1;
+        double bestCorrelation = -1;
+        boolean foundExact = false;
+
+        for (int yoffset = 0; (yoffset < maxY) && !foundExact; yoffset++ )
+        {
+            //System.out.println("Processing line: " + yoffset + " of " + (maxY - 1));
+            for (int xoffset = 0; (xoffset < maxX) && !foundExact; xoffset++)
+            {
+                double correlation = computeCorrelation(markerMaxX, markerMaxY, testImageArray, markerImageArray, yoffset, xoffset);
+                if (correlation > bestCorrelation)
+                {
+                    bestCorrelation = correlation;
+                    bestX = xoffset;
+                    bestY = yoffset;
+                    if (correlation == autocorrelation)
+                    {
+                        foundExact = true;
+                    }
+                }
+            }
+        }
+
+        //System.out.println(autocorrelation);
+        //System.out.println(bestCorrelation);
+        //System.out.println(bestX + " " + bestY);
+        if (bestCorrelation / autocorrelation < CORRELATION_THRESHOLD)
+        {
+            return null;
+        }
+        return new Rectangle(bestX, bestY, marker.getWidth(), marker.getHeight());
+    }
+
+    /**
+     * Compute correlation for given two images and 2D offset.
+     *
+     * @param maxX
+     * @param maxY
+     * @param testImageArray
+     * @param markerImageArray
+     * @param yoffset
+     * @param xoffset
+     * @return
+     */
+    private static double computeCorrelation(int maxX, int maxY, float[][][] testImageArray,
+                    float[][][] markerImageArray, int yoffset, int xoffset)
+    {
+        double correlation = 0;
+        for (int y = 0; y < maxY; y++)
+        {
+            for (int x = 0; x < maxX; x++)
+            {
+                for (int rgbIndex = 0; rgbIndex < 3; rgbIndex++)
+                {
+                    float colorComponent1 = markerImageArray[y][x][rgbIndex];
+                    float colorComponent2 = testImageArray[yoffset + y][xoffset + x][rgbIndex];
+                    correlation += colorComponent1 * colorComponent2;
+                }
+            }
+        }
+        return correlation;
+    }
+
+}