yaowei 发表于 2010-2-3 18:16:51

求教一个可靠性高,且性能好的图片验证方法

求教一个可靠性高,且性能好的图片验证方法。以下是我写的图片匹配方法,可靠性稍好,但是性能比较低。不符合使用要求,请高手指点一下,哪里可以优化或者有其它好的算法。这个方法在32位显示模式下匹配比16位显示模式下可靠性高,我希望是在不同模式下都有高可靠性和性能。谢谢了。


import java.awt.AWTException;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import javax.imageio.ImageIO;
import resources.IdentifyByAberrationHelper;
import com.rational.test.ft.*;
import com.rational.test.ft.object.interfaces.*;
import com.rational.test.ft.object.interfaces.SAP.*;
import com.rational.test.ft.object.interfaces.WPF.*;
import com.rational.test.ft.object.interfaces.dojo.*;
import com.rational.test.ft.object.interfaces.siebel.*;
import com.rational.test.ft.object.interfaces.flex.*;
import com.rational.test.ft.script.*;
import com.rational.test.ft.value.*;
import com.rational.test.ft.vp.*;
/**
* Description   : Functional Test Script 色差法图片识别
* @author
*/
public class IdentifyByAberration extends IdentifyByAberrationHelper
{

public static int _MODELER_CHRABE = 40; //像素误差值,该值可根据情况适当调整
public static double xyz [][] = new double; //XYZ
public static int rgb [][] = new int;      //RGB
public static double lab [][] = new double; //LAB
public static ColorModel cm = ColorModel.getRGBdefault();
public static double delta [] = new double; //delta
/**
* Script Name   : <b>IdentifyByAberration</b>
* Generated   : <b>2010-2-3 上午10:57:56</b>
* Description   : Functional Test Script
* Original Host : WinNT Version 5.1Build 2600 (S)
*
* @since2010/02/03
* @author
*/
public void testMain(Object[] args)
{
RootTestObject root = RootTestObject.getRootTestObject();
//BufferedImage imgSrc = root.getScreenSnapshot(new Rectangle(21,376,31,33));
BufferedImage imgSrc = root.getScreenSnapshot(new Rectangle(0,0,250,550));
String imgBase = "F:\\desktop.png";
try {
   System.out.println(Calendar.getInstance().getTime());
   Point point = findFistImg(imgSrc,ImageIO.read(new File(imgBase)));
   System.out.println(Calendar.getInstance().getTime());
   if(point != null)
   {
    System.out.println(point);
    Robot robot;
    try {
   robot = new Robot();
   //robot.mouseMove(point.x+21, point.y+376);
   robot.mouseMove(point.x, point.y);
   //sleep(20);
    } catch (AWTException e) {
   e.printStackTrace();
    }
   
   }else{
    System.out.println("null");
   }
} catch (IOException e) {
   e.printStackTrace();
}
}

/**
* 在目标图片中查找指定图片
* @param formImg 目标图片
* @param ctrlImg 指定图片
* @return Point-图片中心坐标 null-未找到
* @throws IOException
*/
public static Point findFistImg(BufferedImage formImg, BufferedImage ctrlImg) throws IOException
{

int formWidth = formImg.getWidth();
int formHeight = formImg.getHeight();
int ctrlWidth = ctrlImg.getWidth();
int ctrlHeight = ctrlImg.getHeight();
Point start = new Point(0, 0);
Point center = new Point(0, 0);
boolean findIt = false;
int[] CtrlPixels = new int;
int[] FormPixels = new int;
try
{
   PixelGrabber pg1 = new PixelGrabber(ctrlImg, 0, 0, ctrlWidth,ctrlHeight, CtrlPixels, 0, ctrlWidth);
   pg1.grabPixels();
   PixelGrabber pg2 = new PixelGrabber(formImg, 0, 0, formWidth,formHeight, FormPixels, 0, formWidth);
   pg2.grabPixels();
}
catch (InterruptedException e)
{
   e.printStackTrace();
}
for (int y = 0; y < formHeight - ctrlHeight; ++y)
{
   for (int x = 0; x < formWidth - ctrlWidth; ++x)
   {
    start.x = x;
    start.y = y;
    findIt = isItHere(start, FormPixels, formWidth,CtrlPixels, ctrlWidth, ctrlHeight);
    if (findIt)
    {
   break;
    }   
   }
   if (findIt)
   {
    break;
   }
}
if (findIt)
{
   center.x = start.x + ctrlWidth / 2;
   center.y = start.y + ctrlHeight / 2;
   return center;
}
return null;
}

/**
* 比较目标图片当前坐标对应的局部图片是否与基准图片一样
* @param start 当前坐标
* @param FormPixels 目标图片像素集合
* @param formWidth 目标图片宽度
* @param CtrlPixels 基准图片像素集合
* @param ctrlWidth 基准图片宽度
* @param ctrlHeight 基准图片高度
* @return true-一样 false-不一样
*/
private static boolean isItHere(Point start, int[] FormPixels,int formWidth, int[] CtrlPixels, int ctrlWidth,int ctrlHeight)
{
boolean b = true;
for (int y = 0; y < ctrlHeight; ++y)
{
   for (int x = 0; x < ctrlWidth; ++x)
   {
   b = compareByColorDiff(CtrlPixels,FormPixels[(start.y + y) * formWidth + start.x + x]);   
   if(b == false)
   {
      return false;
   }
   }
}
return b;
}

/**
* 在目标对象中查找指定图片
* @param form 目标对象
* @param controlImgFile 指定图片路径
* @return Point-图片中心坐标 null-未找到
* @throws IOException
*/
public static Point findFistImg(TopLevelSubitemTestObject form,String controlImgFile) throws IOException
{
form.click(new Point(5, 5));
BufferedImage formImg = form.getImage("");
BufferedImage ctrlImg = ImageIO.read(new File(controlImgFile));
return findFistImg(formImg, ctrlImg);
}

/**
* 色差法比较两个像素点是否一样
* @param basePixel 基准像素点
* @param sorcPixel 目标像素点
* @return true-一样 false-不一样
*/
public static boolean compareByColorDiff(int basePixel,int sorcPixel)
{
setRGB(basePixel,sorcPixel);
setXYZ();
setLAB();
setDeltaE();
if (delta > _MODELER_CHRABE)
{   
   return false;   
}else{
   return true;
}
}

/**
* 获得基准像素点和目标像素点的RGB值
* @param basePixel 基准像素点
* @param sorcPixel 目标像素点
*/
public static void setRGB(int basePixel,int sorcPixel)
{
rgb = cm.getRGB(basePixel);//基准像素点RGB值
rgb = cm.getRed(basePixel);//基准像素点R值
rgb = cm.getGreen(basePixel);//基准像素点G值
rgb = cm.getBlue(basePixel);//基准像素点B值
rgb = cm.getRGB(sorcPixel);//目标像素点RGB值
rgb = cm.getRed(sorcPixel);//目标像素点R值
rgb = cm.getGreen(sorcPixel);//目标像素点G值
rgb = cm.getBlue(sorcPixel);//目标像素点B值
}

/**
* 获得基准像素点和目标像素点的XYZ值
*/
public static void setXYZ()
{
xyz = (0.490*rgb + 0.310*rgb + 0.200*rgb) / (0.667*rgb + 1.132*rgb + 1.200*rgb);//基准像素点X值
xyz = (0.117*rgb + 0.812*rgb + 0.010*rgb) / (0.667*rgb + 1.132*rgb + 1.200*rgb);//基准像素点Y值
xyz = (0.000*rgb + 0.010*rgb + 0.990*rgb) / (0.667*rgb + 1.132*rgb + 1.200*rgb);//基准像素点Z值
xyz = (0.490*rgb + 0.310*rgb + 0.200*rgb) / (0.667*rgb + 1.132*rgb + 1.200*rgb);//目标像素点X值
xyz = (0.117*rgb + 0.812*rgb + 0.010*rgb) / (0.667*rgb + 1.132*rgb + 1.200*rgb);//目标像素点Y值
xyz = (0.000*rgb + 0.010*rgb + 0.990*rgb) / (0.667*rgb + 1.132*rgb + 1.200*rgb);//目标像素点Z值
if (rgb == -16777216) //基准像素点RGB值
{
   xyz = 0;
   xyz = 0;
   xyz = 0;
}
if (rgb == -16777216) //目标像素点RGB值
{
   xyz = 0;
   xyz = 0;
   xyz = 0;
}
}

/**
* 获得基准像素点和目标像素点的LAB值
*/
public static void setLAB()
{
double x,y,z;
x = xyz / 95.047;
y = xyz / 100.000;
z = xyz / 108.883;
if(x>0.008856)
{
   x = Math.pow(x, 1.0/3.0);
}else
{
   x = (7.787*x) + (16/116);
}
if(y>0.008856)
{
   y = Math.pow(y, 1.0/3.0);
}else
{
   y = (7.787*y) + (16/116);
}
if(z>0.008856)
{
   z = Math.pow(z, 1.0/3.0);
}else
{
   z = (7.787*z) + (16/116);
}
lab = 116*Math.pow(y, 1.0/3.0) - 16;//基准像素点L值
lab = 500*(Math.pow(x, 1.0/3.0) - Math.pow(y, 1.0/3.0));//基准像素点A值
lab = 200*(Math.pow(y, 1.0/3.0) - Math.pow(z, 1.0/3.0));//基准像素点B值
x = xyz / 95.047;
y = xyz / 100.000;
z = xyz / 108.883;
if(x>0.008856)
{
   x = Math.pow(x, 1.0/3.0);
}else
{
   x = (7.787*x) + (16/116);
}
if(y>0.008856)
{
   y = Math.pow(y, 1.0/3.0);
}else
{
   y = (7.787*y) + (16/116);
}
if(z>0.008856)
{
   z = Math.pow(z, 1.0/3.0);
}else
{
   z = (7.787*z) + (16/116);
}
lab = 116*Math.pow(y, 1.0/3.0) - 16;//目标像素点L值
lab = 500*(Math.pow(x, 1.0/3.0) - Math.pow(y, 1.0/3.0));//目标像素点A值
lab = 200*(Math.pow(y, 1.0/3.0) - Math.pow(z, 1.0/3.0));//目标像素点B值
}

/**
* 获得基准像素点和目标像素点的差值
*/
public static void setDeltaE()
{
delta = lab - lab;//deltaL
delta = lab - lab;//deltaA
delta = lab - lab;//deltaB
delta = Math.pow((Math.pow(delta, 2) + Math.pow(delta, 2) + Math.pow(delta, 2)), 0.5);//deltaE
}
}

dreamever 发表于 2010-2-5 11:43:55

如果图片比较采用逐点比较的话,效率提升的空间不大,试想,对于一个1440 *900的显示器,它要比较的象素点不会少于1296000,而且通过LAB的方式还要经过比较复杂的换算。
一个变通的方法是可以隔点取样,例如每隔两个或者三个象素比较一次,这样可以减少比较次数,并且肉眼上不会有太大的差异,可是间隔太大不能太大,我这边如果间隔的象素超过8个,就会有测试上的误差。
另外,楼主的代码里对双精度的类型没有做任何转换,我觉得这可能需要考虑一下,我一般都是用Double.valueof(),或者BigDecimal对象来转换一下,不然运算和比较结果时会有问题

dennyqiang 发表于 2010-2-22 23:37:09

RFT自带有图片验证点,不知道能不能将其提取出来使用。我估计是可以考虑的,而且网络上应该有相应的JAR包下载吧,没有自己写过,所以没怎么去,所以没有去研究。
页: [1]
查看完整版本: 求教一个可靠性高,且性能好的图片验证方法