【问题标题】:Matching images from file with Sikuli将文件中的图像与 Sikuli 匹配
【发布时间】:2018-02-03 22:27:50
【问题描述】:

当我在寻找一个库以在更大的图像中查找给定图像的匹配项(均从文件加载)时,我刚刚发现了 Sikuli。 默认情况下,Sikuli 仅支持从文件加载搜索到的图像,但依赖于专有类 Screen 截取屏幕截图作为搜索的基础......我希望能够使用图像文件。

寻找解决方案已将我带到this question,但当您考虑到我之前没有使用 Sikuli 的经验并且available documentation 对我的需求没有特别帮助时,答案有点模糊。

有没有人有关于如何自定义实现 Screen、ScreenRegion、ImageScreen 和 ImageScreenLocation 的示例?即使是指向这些类的更详细文档的链接也会有很大帮助。

我想要的只是在另一个图像文件中获取图像匹配的坐标,所以如果有另一个库可以帮助完成这项任务,我非常乐意了解它!

【问题讨论】:

  • 您想检查一个图像是否存在于另一个图像中?您可以自己编写代码,而无需使用任何外部包。除非两个图像的图像质量不同,否则会更难。
  • 是的,我想在更大的图像中找到图像的坐标。最终目标是为不同尺寸/分辨率的匹配提供灵活性。
  • Carlo 看看下面我的回答。
  • 也许您可以使用find() 查找第一个图像(区域),然后在第一个图像上搜索另一个查找。我想我做了你所做的,但是在 python 中。不知道这是否也适用于 Sikuli/Java。 Image_One = ("AAA.png")Image_Two = ("BBB.png")oneRegion = find(Image_One)。然后在图像 1 中搜索第二个区域 if oneRegion.exists(Image_Two):

标签: java image match sikuli


【解决方案1】:

你可以用这样的方式自己实现它:

class MyImage{
    private BufferedImage img;
    private int imgWidth;
    private int imgHeight;

    public MyImage(String imagePath){       
        try{
            img = ImageIO.read(getClass().getResource(imagePath));
        }catch(IOException ioe){System.out.println("Unable to open file");}
        init();
    }

    public MyImage(BufferedImage img){
        this.img = img;
        init();
    }

    private void init(){
        imgWidth = img.getWidth;
        imgHeight = img.getHeight();
    }

    public boolean equals(BufferedImage img){
        //Your algorithm for image comparison (See below desc for your choices)
    }

    public boolean contains(BufferedImage subImage){
        int subWidth = subImage.getWidth();
        int subHeight = subImage.getHeight();
        if(subWidth > imgWidth || subHeight > imgHeight)
            throw new IllegalArgumentException("SubImage is larger than main image");

        for(int x=0; x<(imgHeight-subHeight); x++)
            for(int y=0; y<(imgWidth-subWidth); y++){
                BufferedImage cmpImage = img.getSumbimage(x, y, subWidth, subHeight);
                if(subImage.equals(cmpImage))
                    return true;
            }
        return false;
    }
}

contains 方法将从主图像中获取子图像并与给定的子图像进行比较。如果不一样,它将移动到下一个像素,直到它穿过整个图像。除了逐像素移动之外,可能还有其他更有效的方法,但这应该可行。

比较两张图片的相似度

您至少有 2 个选项:

  1. 使用一对嵌套循环逐像素扫描以比较每个像素的 RGB 值。 (就像你如何比较两个 int 二维数组的相似性)

  2. 应该可以为两张图片生成一个哈希值,然后只比较哈希值。

【讨论】:

    【解决方案2】:

    啊……Sikuli 对此也有答案……你只是看起来不够近。 :) 答案:FINDER 类

    Pattern searchImage = new Pattern("abc.png").similar((float)0.9);
    String ScreenImage = "xyz.png"; //In this case, the image you want to search
    Finder objFinder = null;
    Match objMatch = null;
    objFinder = new Finder(ScreenImage);
    objFinder.find(searchImage); //searchImage is the image you want to search within ScreenImage
    int counter = 0;
    while(objFinder.hasNext())
    {
        objMatch = objFinder.next(); //objMatch gives you the matching region.
        counter++;
    }
    if(counter!=0)
    System.out.println("Match Found!");
    

    【讨论】:

    • 阿吉,你能告诉我这个解决方案是否支持不同比例的匹配吗?我提到的 OpenCV 解决方案使用 Imgproc.matchTemplate,仅在 ScreenImage 中查找大小完全相同的子图像。无论 ScreenImage 大小/比例如何,我都希望能够通过查找一般模式来使其更强大。
    • 嗨 Marcel,Sikuli 不允许这样做。 Sikuli 实际上仅在内部使用 openCV 的匹配模板功能来识别图像。但是,我相信我已经在某处读到,如果您的图像被缩放、旋转等,openCV 有一个解决方案。不幸的是,我自己并没有亲自尝试过。对不起。但是,是的,Sikuli 无法做到这一点。
    • 不使用图像文件的路径,您可以使用 Screen 对象实例(您之前已设置)并执行...。objFinder = new Finder(screen.capture() );
    【解决方案3】:

    最后我放弃了 Sikuli 并使用了纯 OpenCV in my Android project:Imgproc.matchTemplate() 方法成功了,给了我一个包含所有像素的矩阵,其中包含“分数”,就像它的起点一样我的子图像。

    【讨论】:

      【解决方案4】:

      使用 Sikuli,您可以检查另一个图像中是否存在图像。 在此示例代码中,图片是从文件中加载的。 此代码告诉我们第二张图片是否是第一张图片的一部分。

      public static void main(String[] argv){
          String img1Path = "/test/img1.png";
          String img2Path = "/test/img2.png";
          if ( findPictureRegion(img1Path, img2Path) == null )
              System.out.println("Picture 2 was not found in picture 1");
          else
              System.out.println("Picture 2 is in picture 1");
      }
      
      public static ScreenRegion findPictureRegion(String refPictureName, String targetPictureName2){
          Target target = new ImageTarget(new File(targetPictureName2));
          target.setMinScore(0.5); // Precision of recognization from 0 to 1.
          BufferedImage refPicture = loadPicture(refPictureName);
          ScreenRegion screenRegion = new StaticImageScreenRegion(refPicture);
          return screenRegion.find(target);
      }
      
      public static BufferedImage loadPicture(String pictureFullPath){
          try {
              return ImageIO.read(new File(pictureFullPath));
          } catch (IOException e) {
              e.printStackTrace();
              return null;
          }
      }
      

      为了使用 Sikuli 包,我在 Maven 中添加了这个依赖项:

          <!-- SIKULI libraries -->
          <dependency>
              <groupId>org.sikuli</groupId>
              <artifactId>sikuli-api</artifactId>
              <version>1.1.0</version>
          </dependency>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-11
        • 2014-10-01
        • 2019-03-12
        • 1970-01-01
        • 2012-05-06
        • 1970-01-01
        • 1970-01-01
        • 2015-10-28
        相关资源
        最近更新 更多