JAVA图像相似度识别器
日前,在天猫、淘宝、百度等各大网站上都早已出现了以图搜图功能,其主要通过输入的图片与现有图片进行相似度匹配,然后显示出图片相似度较高的商品或者网页,这是一件非常神奇的事,其实,我们也可以自制一个简易的图相相似度识别器来实现后期的以图搜图功能。
一、思路分析
先展示效果图:
实验一:
实验二:
实验三:
实验四 :
由上述四组实验可知,当加载的两张图像为同一张图片时(其中一张做了处理),显示出的相似度较高;当加载的图像为不同图片时,显示出的相似度较低。
该代码的编写思路如下:
将加载的图像宽度和高度方向平均 8 等分,即整幅图像分成 64 个区域,将整幅图像灰度化,算出平均灰度值,再计算出每个区域的平均灰度值,若该区域的平均灰度值大于整幅图像的平均灰度值,则记为 1,若该区域的平均灰度值小于整幅图像的平均灰度值,则记为 0,最后按一定顺序把每个区域的 0 或 1 字符串连起来,我们把他称之为该图像的指纹,判断两幅图像的相似度时,对比两幅图像的指纹相似度即可。
二、代码
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class ImagePad extends JFrame{
ImageListener imagelistener = new ImageListener ();
String[] btnstrs = new String[] {"加载图片","开始匹配"};
public void addButton(JFrame jf, ActionListener al){
Dimension dimension = new Dimension (120, 40);
for (int i = 0; i < btnstrs.length; i++) {
JButton btn = new JButton (btnstrs[i]);
btn.setBackground (Color.WHITE);
btn.setPreferredSize (dimension);
btn.addActionListener (al);
jf.add(btn);
}
}
ImagePad(){
setTitle ("相似度判别");
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setSize (1540,900);
setLocationRelativeTo (null);
setLayout (new FlowLayout ());
addButton(this,imagelistener);
setVisible (true);
imagelistener.setGraphics (this.getGraphics ());
}
public static void main(String[] args){
new ImagePad ();
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ImageListener implements ActionListener{
private Graphics g = null;
ImageUtils imageUtils;
int[][] readImagePixArray1;
int[][] readImagePixArray2;
// set
public void setGraphics(Graphics g){
this.g = g;
}
public ImageListener(){
imageUtils = new ImageUtils();
readImagePixArray1 = imageUtils.readImagePix ("E:/image/10.png");
readImagePixArray2 = imageUtils.readImagePix ("E:/image/00.png");
}
@Override
public void actionPerformed(ActionEvent e){
// 先获取按钮上的字符串 用来判断调用什么代码
String btnstr = e.getActionCommand ();
if (btnstr.equals ("加载图片")) {
imageUtils.drawImage_1 (g,readImagePixArray1);
imageUtils.zhiwen (readImagePixArray1);
imageUtils.drawImage_2 (g,readImagePixArray2);
imageUtils.zhiwen (readImagePixArray2);
}else if (btnstr.equals("开始匹配")) {
imageUtils.xiangsidu();
}
}
}
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImageUtils{
int[] average1 = new int[65];
int[] average2 = new int[65];
boolean b = false;
public int[][] readImagePix(String path){
// 文件对象
File file = new File (path);
BufferedImage readimg = null;
try {
readimg = ImageIO.read (file);
} catch (IOException e) {
e.printStackTrace ();
}
int width = readimg.getWidth ();
int height = readimg.getHeight ();
int[][] imgArray = new int[width][height];
for(int i = 0; i < width; i++){
for(int j = 0; j < height; j++){
imgArray[i][j] = readimg.getRGB (i, j);
}
}
return imgArray;
}
public int getRgbGray(int numPixels){
// byte -128 127
int red = (numPixels>>16)&0xFF;
int green = (numPixels>>8)&255;
int blue = (numPixels>>0)&255;
// 灰度 -- 减少计算量 以及 更方便计算
int gray = (red + green + blue) / 3;
return gray;
}
//根据二维数组 绘制图片
public void drawImage_1(Graphics g,int[][] imgArray){
BufferedImage buffimg00 = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);
for(int i = 0; i < imgArray.length; i++){
for(int j = 0; j < imgArray[i].length; j++){
buffimg00.setRGB (i,j,imgArray[i][j]);
}
}
// 一次性绘制出来 只占一次IO
g.drawImage (buffimg00, 30, 100, null);
b = !b;
System.out.print("图像1的指纹为:");
}
public void drawImage_2(Graphics g,int[][] imgArray){
BufferedImage buffimg00 = new BufferedImage (imgArray.length, imgArray[0].length, BufferedImage.TYPE_INT_ARGB);
for(int i = 0; i < imgArray.length; i++){
for(int j = 0; j < imgArray[i].length; j++){
buffimg00.setRGB (i,j,imgArray[i][j]);
}
}
// 一次性绘制出来 只占一次IO
g.drawImage (buffimg00, 774, 100, null);
System.out.println(" ");
b = !b;
System.out.print("图像2的指纹为:");
}
public void zhiwen(int[][] imgArray){
int width = 8;
int height = 8;
int a1 = imgArray.length/width;
int b1 = imgArray[0].length/height;
int a2 = imgArray.length - a1 * (width-1);
int b2 = imgArray[0].length - b1 * (height-1);
int[][] average = new int[width][height];
int sum0 = 0;
for(int m = 0; m < width; m++){
for(int n = 0; n < height; n++){
int sum = 0;
if(m != (width-1) && n != (height-1)) {
for(int i = 0 + m*a1; i < a1 + m*a1; i++){
for(int j = 0 + n*b1; j < b1 + n*b1; j++){
int num1 = imgArray[i][j];
int gray1 = getRgbGray (num1);
sum += gray1;
}
}
average[m][n] = sum/(a1 * b1);
}
if(m == (width-1) && n != (height-1)) {
for(int i = 0 + m*a1; i < a2 + m*a1; i++){
for(int j = 0 + n*b1; j < b1 + n*b1; j++){
int num1 = imgArray[i][j];
int gray1 = getRgbGray (num1);
sum += gray1;
}
}
average[m][n] = sum/(a2 * b1);
}
if(m != (width-1) && n == (height-1)) {
for(int i = 0 + m*a1; i < a1 + m*a1; i++){
for(int j = 0 + n*b1; j < b2 + n*b1; j++){
int num1 = imgArray[i][j];
int gray1 = getRgbGray (num1);
sum += gray1;
}
}
average[m][n] = sum/(a1 * b2);
}
if(m == (width-1) && n == (height-1)) {
for(int i = 0 + m*a1; i < a2 + m*a1; i++){
for(int j = 0 + n*b1; j < b2 + n*b1; j++){
int num1 = imgArray[i][j];
int gray1 = getRgbGray (num1);
sum += gray1;
}
}
average[m][n] = sum/(a2 * b2);
}
sum0 += average[m][n];
}
}
int average0 = sum0/(width*height);
for(int n = 0; n < height; n++){
for(int m = 0; m < width; m++){
if(average[m][n] > average0)average[m][n] = 1;
else average[m][n] = 0;
if(b) {
average1[m+width*n] = average[m][n];
}else {
average2[m+width*n] = average[m][n];
}
System.out.print(average[m][n]);
}
}
}
public void xiangsidu(){
double a=0;
for(int i=0;i<64;i++) {
if(average1[i] == average2[i])a=a+1.5625;
}
System.out.println(" ");
System.out.print("两张图像的相似度为:"+a);
}
}