[英]How to recognize an image in another image?
因此,我對Java還是很陌生,所以我不確定執行此操作的方法是否是一個好主意,但基本上,我正在嘗試檢查另一個圖像中的一個圖像實例。 因此,為了測試是否可行,我有一個200x148 jpg
,從中獲取字節,然后從窗口的屏幕截圖中獲取字節,並從中獲取字節,然后進行比較。
現在,由於通常第一張圖片不會出現在該屏幕截圖中,因此我在我的照片應用中將其打開,並在程序休眠時將其放入(在截屏之前)。 是的,我可以通過查看屏幕快照來確認第一張圖像在屏幕截圖中。 但是,當我比較字符串時(檢查帶有圖像1的所有字節數據的String是否位於具有圖像2的所有字節數據的String中),結果為負。
到目前為止,我正在嘗試使用以下代碼:
public static void main(String[] args) throws IOException, HeadlessException, AWTException, InterruptedException {
// Get the first image
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(ImageIO.read(new File("profile.jpg")), "jpg", baos);
byte[] bytes = baos.toByteArray();
String bytes1S = "";
for (int i = 0; i < bytes.length; i++) {
bytes1S += bytes[i];
}
// Give yourself enough time to open the other image
TimeUnit.SECONDS.sleep(6);
// Take the screenshot
BufferedImage image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "jpg", new File("screenshot.jpg"));
baos = new ByteArrayOutputStream();
ImageIO.write(ImageIO.read(new File("screenshot.jpg")), "jpg", baos);
byte[] bytes2 = baos.toByteArray();
String bytes2S = "";
for (int i = 0; i < bytes2.length; i++) {
bytes2S += bytes2[i];
}
// Check if the second String of bytes contains the first String of bytes.
if (bytes2S.contains(bytes1S))
System.out.println("Yes");
else
System.out.println("No");
}
作為參考,這是第一張圖片,以及它拍攝的屏幕截圖:
它為何未檢測到屏幕快照中的第一張圖像,其背后的原因是什么?是否有更好的方法(最好沒有其他庫)來執行此操作?
蠻力方法是簡單地將兩個圖像都加載為BufferedImage
對象,然后逐像素瀏覽“主”圖像,然后查看是否可以在其中找到“子圖像”。
我已經實現了一段時間,並將下面的代碼發布為MCVE。
但請注意 :將圖像另存為JPG文件時,它們將被壓縮,並且這種壓縮是有損的 。 這意味着即使像素在屏幕上相等,像素也不會具有完全相同的顏色。 在下面的示例中,使用“閾值”定義了像素的不同程度,以實用的方式解決了這一問題。 但這有點武斷,也不是那么可靠。 (更強大的解決方案將需要更多的努力)。
我強烈建議將圖像另存為PNG文件。 他們使用無損壓縮。 因此,對於PNG文件,您可以在下面的代碼中設置threshold=0
。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.function.IntBinaryOperator;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FindImageInImage
{
public static void main(String[] args) throws Exception
{
BufferedImage mainImage =
ImageIO.read(new URL("https://i.stack.imgur.com/rEouF.jpg"));
BufferedImage subImage =
ImageIO.read(new URL("https://i.stack.imgur.com/wISyn.jpg"));
int threshold = 100;
Point location = findImageLocation(
mainImage, subImage, threshold);
System.out.println("At " + location);
SwingUtilities.invokeLater(() -> showIt(mainImage, subImage, location));
}
private static void showIt(
BufferedImage mainImage, BufferedImage subImage, Point location)
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JPanel()
{
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(mainImage, 0, 0, null);
if (location != null)
{
g.setColor(Color.RED);
g.drawRect(location.x, location.y,
subImage.getWidth(), subImage.getHeight());
}
}
});
f.setSize(1500, 800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
static Point findImageLocation(
BufferedImage mainImage,
BufferedImage subImage,
int threshold)
{
return findImageLocation(mainImage, subImage, (rgb0, rgb1) ->
{
int difference = computeDifference(rgb0, rgb1);
if (difference > threshold)
{
return 1;
}
return 0;
});
}
private static int computeDifference(int rgb0, int rgb1)
{
int r0 = (rgb0 & 0x00FF0000) >> 16;
int g0 = (rgb0 & 0x0000FF00) >> 8;
int b0 = (rgb0 & 0x000000FF);
int r1 = (rgb1 & 0x00FF0000) >> 16;
int g1 = (rgb1 & 0x0000FF00) >> 8;
int b1 = (rgb1 & 0x000000FF);
int dr = Math.abs(r0 - r1);
int dg = Math.abs(g0 - g1);
int db = Math.abs(b0 - b1);
return dr + dg + db;
}
static Point findImageLocation(
BufferedImage mainImage,
BufferedImage subImage,
IntBinaryOperator rgbComparator)
{
int w = mainImage.getWidth();
int h = mainImage.getHeight();
for (int x=0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
if (isSubImageAt(mainImage, x, y, subImage, rgbComparator))
{
return new Point(x, y);
}
}
}
return null;
}
static boolean isSubImageAt(
BufferedImage mainImage, int x, int y,
BufferedImage subImage,
IntBinaryOperator rgbComparator)
{
int w = subImage.getWidth();
int h = subImage.getHeight();
if (x + w > mainImage.getWidth())
{
return false;
}
if (y + h > mainImage.getHeight())
{
return false;
}
for (int ix=0; ix < w; ix++)
{
for (int iy = 0; iy < h; iy++)
{
int mainRgb = mainImage.getRGB(x + ix, y + iy);
int subRgb = subImage.getRGB(ix, iy);
if (rgbComparator.applyAsInt(mainRgb, subRgb) != 0)
{
return false;
}
}
}
return true;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.