51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2558|回复: 2
打印 上一主题 下一主题

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

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 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[2][3]; //XYZ
public static int rgb [][] = new int[2][4];        //RGB
public static double lab [][] = new double[2][3]; //LAB
public static ColorModel cm = ColorModel.getRGBdefault();
public static double delta [] = new double[4]; //delta
/**
  * Script Name   : <b>IdentifyByAberration</b>
  * Generated     : <b>2010-2-3 上午10:57:56</b>
  * Description   : Functional Test Script
  * Original Host : WinNT Version 5.1  Build 2600 (S)
  *
  * @since  2010/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[ctrlWidth * ctrlHeight];
  int[] FormPixels = new int[formWidth * formHeight];
  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[y * ctrlWidth + x],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[3] > _MODELER_CHRABE)
  {   
   return false;   
  }else{
   return true;
  }
}

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

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

/**
  * 获得基准像素点和目标像素点的LAB值
  */
public static void setLAB()
{
  double x,y,z;
  x = xyz[0][0] / 95.047;
  y = xyz[0][1] / 100.000;
  z = xyz[0][2] / 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[0][0] = 116*Math.pow(y, 1.0/3.0) - 16;//基准像素点L值
  lab[0][1] = 500*(Math.pow(x, 1.0/3.0) - Math.pow(y, 1.0/3.0));//基准像素点A值
  lab[0][2] = 200*(Math.pow(y, 1.0/3.0) - Math.pow(z, 1.0/3.0));//基准像素点B值
  x = xyz[1][0] / 95.047;
  y = xyz[1][1] / 100.000;
  z = xyz[1][2] / 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[1][0] = 116*Math.pow(y, 1.0/3.0) - 16;//目标像素点L值
  lab[1][1] = 500*(Math.pow(x, 1.0/3.0) - Math.pow(y, 1.0/3.0));//目标像素点A值
  lab[1][2] = 200*(Math.pow(y, 1.0/3.0) - Math.pow(z, 1.0/3.0));//目标像素点B值
}

/**
  * 获得基准像素点和目标像素点的差值
  */
public static void setDeltaE()
{
  delta[0] = lab[0][0] - lab[1][0];//deltaL
  delta[1] = lab[0][1] - lab[1][1];//deltaA
  delta[2] = lab[0][2] - lab[1][2];//deltaB
  delta[3] = Math.pow((Math.pow(delta[0], 2) + Math.pow(delta[1], 2) + Math.pow(delta[2], 2)), 0.5);//deltaE
}
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

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

使用道具 举报

该用户从未签到

3#
发表于 2010-2-22 23:37:09 | 只看该作者
RFT自带有图片验证点,不知道能不能将其提取出来使用。我估计是可以考虑的,而且网络上应该有相应的JAR包下载吧,没有自己写过,所以没怎么去,所以没有去研究。
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-10-5 07:24 , Processed in 0.089574 second(s), 28 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表