版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SummerCloudXT/article/details/82628941
先说下思路:
因为是大图中寻找小图,所以小图必须是大图的一部分,那么对应的他们具有相同的像素点,所以为了一遍就可以搜出来,从小图中抽取若干个像素点(本次DEMO只选区了5个),从大图中找到像素与第一个点满足的,然后直接进行对比第二个点。。。到N个。都符合,说明就找到了,然后为了进行验证,对图片进行了相似度运算。
看下结果,开始还想做优化,但是看了下用的时间82毫秒,最后加上验证才1秒,貌似挺快的。就算了
话不多说,上代码:
SearchPixelPosition核心类
public class SearchPixelPosition {
//需要找的图片宽度
private int targetWidth;
//需要找的图片高度
private int targetHeight;
/**
* 对大图进行所有像素点寻找,知道满足5个点,返回之后到的坐标值
* @param path
* @param tagert
* @return
*/
public ResultBean getAllRGB(String path, String tagert) {
// int[] rgb = new int[3];
File file = new File(path);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
}
int width = bi.getWidth();
int height = bi.getHeight();
int minx = bi.getMinX();
int miny = bi.getMinY();
System.out.println("width=" + width + ",height=" + height + ".");
System.out.println("minx=" + minx + ",miniy=" + miny + ".");
ArrayList<PositionBean> setTarget5RGB = setTarget5RGB(tagert);
// System.out.println(setTarget5RGB.get(0).x+" "+setTarget5RGB.get(0).y+"
// "+setTarget5RGB.get(0).pxrgb);
// System.out.println(setTarget5RGB.get(1).x+" "+setTarget5RGB.get(1).y+"
// "+setTarget5RGB.get(1).pxrgb);
// System.out.println(setTarget5RGB.get(2).x+" "+setTarget5RGB.get(2).y+"
// "+setTarget5RGB.get(2).pxrgb);
// System.out.println(setTarget5RGB.get(3).x+" "+setTarget5RGB.get(3).y+"
// "+setTarget5RGB.get(3).pxrgb);
// System.out.println(setTarget5RGB.get(4).x+" "+setTarget5RGB.get(4).y+"
// "+setTarget5RGB.get(4).pxrgb);
long start = System.currentTimeMillis();
for (int i = minx; i < width; i++) {
for (int j = miny; j < height; j++) {
int pixel = bi.getRGB(i, j);
// rgb[0] = (pixel & 0xff0000) >> 16;
// rgb[1] = (pixel & 0xff00) >> 8;
// rgb[2] = (pixel & 0xff);
//依次对比5个点。
if (setTarget5RGB != null) {
PositionBean p1 = setTarget5RGB.get(0);
if (pixel == p1.pxrgb) {
int other = 0;
PositionBean p2 = setTarget5RGB.get(1);
int pixel2 = bi.getRGB(i + (p2.x - p1.x), j);
if (pixel2 == p2.pxrgb) {
other++;
PositionBean p3 = setTarget5RGB.get(2);
int pixel3 = bi.getRGB(i + (p3.x - p1.x), j + (p3.y - p1.y));
if (pixel3 == p3.pxrgb) {
other++;
PositionBean p4 = setTarget5RGB.get(3);
int pixel4 = bi.getRGB(i, j + (p4.y - p1.y));
if (pixel4 == p4.pxrgb) {
other++;
PositionBean p5 = setTarget5RGB.get(4);
int pixel5 = bi.getRGB(i + (p5.x - p1.x), j + (p5.y - p1.y));
if (pixel5 == p5.pxrgb) {
other++;
}
}
}
}
if (other == 4) {
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start));
System.out.println("找到了===》》》》横坐标" + i + "纵坐标" + j);
ResultBean resultBean = new ResultBean();
resultBean.width = targetWidth;
resultBean.height = targetHeight;
resultBean.x = i - p1.x;
resultBean.y = j - p1.y;
return resultBean;
}
}
}
}
}
long end = System.currentTimeMillis();
System.out.println("搜索坐标耗时:" + (end - start));
return null;
}
/**
* 分别取小图的四个角落和中心点的像素,作为搜图依据
*
* @param src
* @return
* @throws Exception
*/
private ArrayList<PositionBean> get5PointForTager(String src) throws Exception {
ArrayList<PositionBean> searchXYList = new ArrayList<>();
File file = new File(src);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
}
int width = bi.getWidth();
int height = bi.getHeight();
targetWidth = width;
targetHeight = height;
if (width >= 10 && height >= 10) {
int px1 = (int) (width * 0.25);
int py1 = (int) (height * 0.25);
int px2 = (int) (width * 0.75);
int py2 = (int) (height * 0.25);
int px3 = (int) (width * 0.5);
int py3 = (int) (height * 0.5);
int px4 = (int) (width * 0.25);
int py4 = (int) (height * 0.75);
int px5 = (int) (width * 0.75);
int py5 = (int) (height * 0.75);
searchXYList.add(new PositionBean(px1, py1));
searchXYList.add(new PositionBean(px2, py2));
searchXYList.add(new PositionBean(px3, py3));
searchXYList.add(new PositionBean(px4, py4));
searchXYList.add(new PositionBean(px5, py5));
} else {
throw new Exception("不支持10px以内的搜索");
}
return searchXYList;
}
/**
* 设置5个点的像素值 和对应的坐标
* @param src
* @return
*/
private ArrayList<PositionBean> setTarget5RGB(String src) {
File file = new File(src);
BufferedImage bi = null;
try {
bi = ImageIO.read(file);
} catch (Exception e) {
e.printStackTrace();
}
try {
ArrayList<PositionBean> get5PointForTager = get5PointForTager(src);
for (int i = 0; i < get5PointForTager.size(); i++) {
PositionBean positionBean = get5PointForTager.get(i);
positionBean.pxrgb = bi.getRGB(positionBean.x, positionBean.y);
}
return get5PointForTager;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
看下调用
public class MainInTest {
public static void main(String[] args) {
String src = "/Users/mac_py/Desktop/cocl.png";
String dest = "/Users/mac_py/Desktop/cocl-n-y.png";
String target = "/Users/mac_py/Desktop/cocl-n.png";
long start = System.currentTimeMillis();
try {
// ScalImage.zoomImage(src, dest,320,180);
// SnippingImage.saveImageWithSize(568,850,240,106,src,"/Users/mac_py/Desktop/cocl-n.png");
// SnippingImage.saveImageWithSize(71,106,30,13,src,"/Users/mac_py/Desktop/cocl-n-s-y.png");
// ScalImage.zoomImage(src, dest,30,13);
// SearchPixelPosition.getAllRGB(src);
SearchPixelPosition searchPixelPosition = new SearchPixelPosition();
ResultBean result = searchPixelPosition.getAllRGB(src, target);
if (result != null) {
SnippingImage.saveImageWithSize(result.x, result.y, result.width, result.height, src,
"/Users/mac_py/Desktop/cocl-ai.png");
ImagePHash p = new ImagePHash();
System.out.println("进行相似度计算");
String image1 = p.getHash(new FileInputStream(new File(target)));
String image2 = p.getHash(new FileInputStream(new File("/Users/mac_py/Desktop/cocl-ai.png")));
System.out.println("相似度为" + (p.distance(image1, image2)==0?"相似度100%":"不相似"));
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("总共耗时:" + (end - start));
}
}
相似度计算核心类 ImagePHash
/*
* 汉明距离越大表明图片差异越大,如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。
*/
public class ImagePHash {
private int size = 32;
private int smallerSize = 8;
public ImagePHash() {
initCoefficients();
}
public ImagePHash(int size, int smallerSize) {
this.size = size;
this.smallerSize = smallerSize;
initCoefficients();
}
public int distance(String s1, String s2) {
int counter = 0;
for (int k = 0; k < s1.length(); k++) {
if (s1.charAt(k) != s2.charAt(k)) {
counter++;
}
}
return counter;
}
/**
* 返回图片二进制流的字符串
* @param is 输入流
* @return
* @throws Exception
*/
public String getHash(InputStream is) throws Exception {
BufferedImage img = ImageIO.read(is);
/*
* 简化图片尺寸
*/
img = resize(img, size, size);
/*
* 减少图片颜色
*/
img = grayscale(img);
double[][] vals = new double[size][size];
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
vals[x][y] = getBlue(img, x, y);
}
}
/*
* 计算DTC 采用32*32尺寸
*/
long start = System.currentTimeMillis();
double[][] dctVals = applyDCT(vals);
System.out.println("DCT: " + (System.currentTimeMillis() - start));
/*
* 计算平均值DTC
*/
double total = 0;
for (int x = 0; x < smallerSize; x++) {
for (int y = 0; y < smallerSize; y++) {
total += dctVals[x][y];
}
}
total -= dctVals[0][0];
double avg = total / (double) ((smallerSize * smallerSize) - 1);
/*
* 计算hash值
*/
String hash = "";
for (int x = 0; x < smallerSize; x++) {
for (int y = 0; y < smallerSize; y++) {
if (x != 0 && y != 0) {
hash += (dctVals[x][y] > avg ? "1" : "0");
}
}
}
return hash;
}
private BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
private ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
private BufferedImage grayscale(BufferedImage img) {
colorConvert.filter(img, img);
return img;
}
private static int getBlue(BufferedImage img, int x, int y) {
return (img.getRGB(x, y)) & 0xff;
}
private double[] c;
private void initCoefficients() {
c = new double[size];
for (int i = 1; i < size; i++) {
c[i] = 1;
}
c[0] = 1 / Math.sqrt(2.0);
}
private double[][] applyDCT(double[][] f) {
int N = size;
double[][] F = new double[N][N];
for (int u = 0; u < N; u++) {
for (int v = 0; v < N; v++) {
double sum = 0.0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI)
* Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) * (f[i][j]);
}
}
sum *= ((c[u] * c[v]) / 4.0);
F[u][v] = sum;
}
}
return F;
}
public static void main(String[] args) {
ImagePHash p = new ImagePHash();
String image1;
String image2;
try {
image1 = p.getHash(new FileInputStream(new File("/Users/mac_py/Desktop/cocl-n-sc.png")));
image2 = p.getHash(new FileInputStream(new File("/Users/mac_py/Desktop/cocl-n-s-y.png")));
System.out.println("得分为 " + p.distance(image1, image2));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}