给定一张图片,如何从一组图片中找到与它最相近的图片呢?相信很多小伙伴跟我一样,第一想到的解决办法就是遍历比较每张图片的像素点,找到差异最小的那张图片。这种方法虽然可行,但时间复杂度高,只适用于像素点较少的图片,对于像素点较多的图片,我们需要另寻他路,即通过获取图片指纹,计算两张图片编码数的汉明距离,从而找出最相近的图片。

步骤一:将图片转为int类型的二维数组

public int[][] getpixelarray(String path){BufferedImage buffimg=null;try {buffimg=ImageIO.read(new File(path));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}int w=buffimg.getWidth();int h=buffimg.getHeight();int[][] imgarr=new int[w][h];for(int i=0;i<w;i++) {for(int j=0;j<h;j++) {imgarr[i][j]=buffimg.getRGB(i, j);}}return imgarr;}

步骤二:缩小图片,并将其转为灰度图,保存均值化灰度值

若我们将图片二维数组中的每个像素值都取相应的二进制码字符,则会得到很长的字符串,不利于计算汉明距离,所以我们需要将图片缩少,减小所得字符串长度。下面代码是将图片矩阵缩小为同等规模的8*8矩阵。将图片缩小后,我们还需要将图片转为灰度图。那如何转成灰度图呢?假设原先图片矩阵为128*128的矩阵,则我们需要将原先图片中每一个16*16的小矩阵中的256个像素点灰度值的平均值保存至8*8的矩阵中。所以当我们在原先图片矩阵中每隔16个长度取一个16*16的小矩阵时,我们都需将灰度值初始化为0,然后遍历16*16矩阵中的每个像素点的灰度值进行求和,最后取平均值并依次将其保存至8*8的矩阵中,从而得到8*8的灰度图。

    //将图片缩小 获取8*8的灰度矩阵int sw=imgarr.length/8;int sh=imgarr[0].length/8;int[][] grayarr=new int[8][8];//定义一个8*8的灰度矩阵//计算均值化灰度值 保存至灰度矩阵中for(int i=0;i<=imgarr.length-sw;i+=sw) {for(int j=0;j<=imgarr[i].length-sh;j+=sh) {int grayend=0;//在原先图片矩阵中每取一个sw*sh的矩阵都将灰度值初始化为0//遍历计算每次所取的sw*sh矩阵中的每个像素点的灰度值 进行求和并最终取平均值for(int k=0;k<sw;k++) {for(int l=0;l<sh;l++) {int rgb=imgarr[i+k][j+l];Color color=new Color(rgb);//计算灰度值int red=color.getRed();int green=color.getGreen();int blue=color.getBlue();int gray=(red+green+blue)/3;grayend+=gray;}}grayarr[i/sw][j/sh]=grayend/(sw*sh);//将均值化的灰度值保存至灰度矩阵中}}

步骤三:根据均值化灰度矩阵,获取图片相应的编码数

先遍历均值化灰度矩阵中的每个灰度值,进行求和并取平均值。然后再次遍历均值化灰度矩阵,若灰度值大于所求的平均值,则将其所对应的二进制码字符设置为‘0’,否则则将其所对应的二进制码字符设置为‘1’,从而获取图片相应的二进制码字符串。

int avergray=0;
//遍历灰度矩阵 计算灰度值的平均值
for(int i=0;i<grayarr.length;i++) {for(int j=0;j<grayarr[i].length;j++) {avergray+=grayarr[i][j];}
}
avergray=avergray/(grayarr.length*grayarr[0].length);
//再次遍历灰度矩阵 大于平均值则设置为0
for(int k=0;k<grayarr.length;k++) {for(int l=0;l<grayarr[k].length;l++) {int gray=grayarr[k][l];if(gray>avergray) {qrcodestr+="0";}else {qrcodestr+="1";}}
}

 步骤四:计算两个字符串的汉明距离

第一种方法:计算字符串a变成字符串b需要改变的最少字符数。该最少字符数即为两个字符串的汉明距离。下面提供具体实现的代码,详细的算法讲解可参考网址https://blog.csdn.net/xcxy2015/article/details/77164126?utm_source=app&app_version=5.3.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

//创建一个方法 获取两个字符串差异操作数public int Levenshtein(String str1,String str2) {int len1=str1.length();int len2=str2.length();//创建一个比字符串长度大一的二维空间int[][] dif=new int[len1+1][len2+1];for(int a=0;a<=len1;a++) {dif[a][0]=a;}for(int a=0;a<=len2;a++) {dif[0][a]=a;}//设标志 若上面值和左边值不相等 则左上角值加1 相等则加0int temp;for(int i=1;i<=len1;i++) {for(int j=1;j<=len2;j++) {if(str1.charAt(i-1)==str2.charAt(j-1)) {//上面值与左边值相等temp=0;}else {temp=1;}//上面值和左边值都加1后 取上面值、左边值、左上角值中的最小值dif[i][j]=min(dif[i-1][j]+1,dif[i][j-1]+1,dif[i-1][j-1]+temp);//调用最小值方法}}//最右下角的数值即为操作数return dif[len1][len2];} //创建最小值方法 从一组数据中获取最小的数据值private static int min(int...is) {int min=Integer.MAX_VALUE;for(int i:is) {if(min>i) {min=i;}}return min;}

第二种方法:先将汉明距离初始化为0,再遍历两个字符串,若两个字符串对应位置的字符不相等,则汉明距离加1,直至最小长度字符串遍历完得到最终的汉明距离。

int hashcodedistance=0;//初始化汉明距离
for(int i=0;i<Math.min(str1.length(),str2.length());i++){if(str1.charAt(i)!=str2.charAt(i)) {hashcodedistance++;}
}

有时图片对应的二进码字符串很长,比较次数很多,所以可将二进制码字符串先转为对应的十进制整数,再将十进制整数转为相应的十六进制码字符串,从而比较两个十六进制码字符串中不相等的字符数,减少比较次数。

步骤五:找出与给定图片指纹的最小汉明距离所对应的图片

创建一个保存键值对的泛型数组1,键为一组N张图片的图片路径,值为该N张图片所对应的编码数。再创建一个保存键值对的泛型数组2,键为该N张图片的图片路径,值为该N张图片与给定图片的汉明距离。获取泛型数组2中所有键值对中的值,将其转为数组进行排序,从而获取最小值。然后根据最小值访问其所对应的键,从而获取与给定图片最相近图片的图片路径,最后将其在窗体上绘出。

//定义一个泛型数组1 保存图片路径以及该图片所代表的二进制码字符串的键值对
static HashMap<String, String> imghashcodeMap1= new HashMap<> ();
int[][] imgarr=getpixelarray(path);//获取图片二维数组
String addimgstr=getimagestr(imgarr);//获取该图片的二进制码字符串
imghashcodeMap1.put(path, addimgstr);//将该图片的路径和二进制码字符串保存至数组1中
//定义一个泛型数组2 保存每张添加的图片路径与待匹配图片的字符操作数的键值对
HashMap<String, Integer> imghashcodeMap2= new HashMap<> ();
//遍历泛型数组1 计算每张添加图片与待配对图片的字符操作数
int difnum;//声明字符串差异操作数
for(String key : imghashcodeMap1.keySet ()){String addstr = imghashcodeMap1.get (key);//调用字符串差异操作数方法difnum=Levenshtein(addstr,imgstr);//addstr为添加图片路径 imgstr为给定图片路径imghashcodeMap2.put(key,difnum);//将添加图片路径与其所对应的字符串差异操作数保存至数组2中
}
//获取所有值 转为数组进行排序 从而获取最小的(汉明距离)
Collection<Integer> c=imghashcodeMap2.values();
Object[] obj=c.toArray();
Arrays.sort(obj);//按升序排序
//通过最小值获取其对应图片路径
String simimgpath="";//初始化图片路径
for(Entry<String, Integer> entry:imghashcodeMap2.entrySet()){if(entry.getValue().equals(obj[0])) {simimgpath=entry.getKey();//最相近图片路径}
}

项目实操:

从一组11张图片(douw0.jpg-douw10.jpg)中找到与douw13.jpg最相近的图片,并将douw13.jpg与最相近图片在窗体上绘出

 完整代码:

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileNameExtensionFilter;
public class Imagecmp2 extends JFrame {private static final long serialVersionUID = 1L;//定义一个泛型数组1 保存图片路径以及该图片所代表的二进制码字符串的键值对HashMap<String, String> imghashcodeMap1= new HashMap<> ();int[][] simimgarr= {{}};//初始化最相近图片二维数组int[][] matchimgarr= {{}};//初始化待匹配图片二维数组Graphics g=null;//创建窗体public void showUI() {setTitle("相似图片查询");setSize(800,800);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLayout(new FlowLayout());//添加窗体按钮 实现自动加图片操作JButton btn1=new JButton("添加图库");JButton btn2=new JButton("查询图片");add(btn1);add(btn2);//打开添加图片监听器btn1.addActionListener(e->{for(int i=0;i<=10;i++) {String path="D:\\图片\\Pictures\\douw"+i+".jpg";System.out.println("添加的图片为:"+path);int[][] imgarr=getpixelarray(path);//获取图片二维数组String addimgstr=getimagestr(imgarr);//获取该图片的二进制码字符串imghashcodeMap1.put(path, addimgstr);//将该图片的路径和二进制码字符串保存至数组中System.out.println("添加的图片二进制码字符串为:"+addimgstr);}});//打开待匹配图片查询按钮btn2.addActionListener(e->{//文件选择器JFileChooser jfc=new JFileChooser();FileNameExtensionFilter filefilter=new FileNameExtensionFilter("图片文件","jpg", "png", "gif");jfc.setFileFilter(filefilter);int returnvale = jfc.showOpenDialog (null);if(returnvale == JFileChooser.APPROVE_OPTION){String path = jfc.getSelectedFile ().getPath ();System.out.println("待匹配图片为:"+path);matchimgarr=getpixelarray(path);//获取待匹配图片二维数组String imgstr=getimagestr(matchimgarr);//获取待匹配图片的二进制码字符串//创建泛型数组2 保存每张添加的图片路径与待匹配图片的字符操作数的键值对HashMap<String, Integer> imghashcodeMap2= new HashMap<> ();//遍历泛型数组1 计算每张添加图片与待配对图片的字符操作数int difnum;//声明字符串差异操作数for(String key : imghashcodeMap1.keySet ()){String addstr = imghashcodeMap1.get (key);//调用字符串差异操作数方法difnum=Levenshtein(addstr,imgstr);System.out.println("待匹配图片与"+key+"的字符串操作差异数为"+difnum);imghashcodeMap2.put(key,difnum);}//获取所有值 转为数组进行排序 从而获取最小的(汉明距离)Collection<Integer> c=imghashcodeMap2.values();Object[] obj=c.toArray();Arrays.sort(obj);//按升序排序//通过最小值获取其对应图片路径String simimgpath="";//初始化图片路径for(Entry<String, Integer> entry:imghashcodeMap2.entrySet()){if(entry.getValue().equals(obj[0])) {simimgpath=entry.getKey();//最相近图片路径}}    System.out.println("与待匹配图片最相近的图片为"+simimgpath);simimgarr=getpixelarray(simimgpath);//最相近图片二维数组}//绘制待匹配图片for(int k=0;k<matchimgarr.length;k++) {for(int l=0;l<matchimgarr[0].length;l++) {int rgb=matchimgarr[k][l];Color color=new Color(rgb);g.setColor(color);g.fillRect(100+k, 100+l, 1, 1);}}//绘制最相近图片for(int k=0;k<simimgarr.length;k++) {for(int l=0;l<simimgarr[0].length;l++) {int rgb=simimgarr[k][l];Color color=new Color(rgb);g.setColor(color);g.fillRect(400+k, 100+l, 1, 1);}}   });setVisible(true);//窗体获取画笔g=getGraphics();paint(g);}//将图片转为二维数组 保存其像素点public int[][] getpixelarray(String path){BufferedImage buffimg=null;try {buffimg=ImageIO.read(new File(path));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}int w=buffimg.getWidth();int h=buffimg.getHeight();int[][] imgarr=new int[w][h];for(int i=0;i<w;i++) {for(int j=0;j<h;j++) {imgarr[i][j]=buffimg.getRGB(i, j);}}return imgarr;}//获取8*8均值化灰度矩阵  遍历灰度矩阵获取二进制码字符串并将其返回public String getimagestr(int[][] imgarr) {String qrcodestr="";//将图片缩小 获取8*8的灰度矩阵int sw=imgarr.length/8;int sh=imgarr[0].length/8;int[][] grayarr=new int[8][8];//定义一个8*8的灰度矩阵//计算均值化灰度值 保存至灰度矩阵中for(int i=0;i<=imgarr.length-sw;i+=sw) {for(int j=0;j<=imgarr[i].length-sh;j+=sh) {int grayend=0;//在原先图片矩阵中每取一个sw*sh的矩阵都将灰度值初始化为0//遍历计算每次所取的sw*sh矩阵中的每个像素点的灰度值 进行求和并最终取平均值for(int k=0;k<sw;k++) {for(int l=0;l<sh;l++) {int rgb=imgarr[i+k][j+l];Color color=new Color(rgb);//计算灰度值int red=color.getRed();int green=color.getGreen();int blue=color.getBlue();int gray=(red+green+blue)/3;grayend+=gray;}}grayarr[i/sw][j/sh]=grayend/(sw*sh);//将均值化的灰度值保存至灰度矩阵中}}int avergray=0;//遍历灰度矩阵 计算灰度值的平均值for(int i=0;i<grayarr.length;i++) {for(int j=0;j<grayarr[i].length;j++) {avergray+=grayarr[i][j];}}avergray=avergray/(grayarr.length*grayarr[0].length);//再次遍历灰度矩阵 大于平均值则设置为0for(int k=0;k<grayarr.length;k++) {for(int l=0;l<grayarr[k].length;l++) {int gray=grayarr[k][l];if(gray>avergray) {qrcodestr+="0";}else {qrcodestr+="1";}}}return qrcodestr;}//创建一个方法 获取两个字符串差异操作数public int Levenshtein(String str1,String str2) {int len1=str1.length();int len2=str2.length();//创建一个比字符串长度大一的二维空间int[][] dif=new int[len1+1][len2+1];for(int a=0;a<=len1;a++) {dif[a][0]=a;}for(int a=0;a<=len2;a++) {dif[0][a]=a;}//设标志 若上面值和左边值不相等 则左上角值加1 相等则加0int temp;for(int i=1;i<=len1;i++) {for(int j=1;j<=len2;j++) {if(str1.charAt(i-1)==str2.charAt(j-1)) {//上面值与左边值相等temp=0;}else {temp=1;}//上面值和左边值都加1后 取上面值、左边值、左上角值中的最小值dif[i][j]=min(dif[i-1][j]+1,dif[i][j-1]+1,dif[i-1][j-1]+temp);//调用最小值方法}}//最右下角的数值即为操作数return dif[len1][len2];} //创建最小值方法 从一组数据中获取最小的数据值private static int min(int...is) {int min=Integer.MAX_VALUE;for(int i:is) {if(min>i) {min=i;}}return min;}public static void main(String[]args) {Imagecmp2 imgcmp=new Imagecmp2();imgcmp.showUI();}
}

效果呈现:

图像识别,完成搜图功能相关推荐

  1. iOS开发- 以图搜图功能实现 (源码+解析)

    以图搜图这个功能相当实用, 之前在实现这个功能的时候, 有一些笔记, 今天就整合成博文, 分享给大家. 这个demo主要实现的功能包括: 自定义拍照界面 图像识别 以图搜图 信息获取(通过识别出的图像 ...

  2. 以图搜图 图像匹配_图像匹配,基于深度学习DenseNet实现以图搜图功能

    原标题:图像匹配,基于深度学习DenseNet实现以图搜图功能 度学习的发展使得在此之前以机器学习为主流算法的相关实现变得简单,而且准确率更高,效果更好,在图像检索这一块儿,目前有谷歌的以图搜图,百度 ...

  3. 以图搜图功能该如何测试

    以图搜图功能该如何测试 最近在测试以图搜图的功能,以下是一些测试思路 图片上传后,图片可以被搜索到 图片删除到回收站后图片无法被搜索到,其他图片不受影响 图片回收站恢复后可以被搜索到 图片同名被替换时 ...

  4. 计算机视觉的应用2-以图搜图功能的实现,搭载可视化的搜索界面

    大家好,我是微学AI,今天给大家带来计算机视觉的应用2-以图搜图功能实现,搭载可视化的搜索界面,以图搜图是一种网络图片搜索引擎技术,其主要功能是通过上传或输入一张图片,快速查找出相似或相同的图片或相关 ...

  5. 图像匹配,基于深度学习DenseNet实现以图搜图功能

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 度学习的发展使得在此之前以机器学习为主流算法的相关实现变得简单,而且准确率更高,效果更好,在图 ...

  6. 基于深度学习实现以图搜图功能

    前记: 深度学习的发展使得在此之前以机器学习为主流算法的相关实现变得简单,而且准确率更高,效果更好,在图像检索这一块儿,目前有谷歌的以图搜图,百度的以图搜图,而百度以图搜图的关键技术叫做"感 ...

  7. 搜索技术之--以图搜图

    以图搜图,是通过搜索图像文本或者视觉特征,为用户提供互联网上相关图形图像资料检索服务的专业搜索引擎系统,是搜索引擎的一种细分.通过输入与图片名称或内容相似的关键字来进行检索,另一种通过上传与搜索结果相 ...

  8. 实战 | 多种方法实现以图搜图

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:AI 算法与图像处理 概述 以图搜图技术是日常生活中常用 ...

  9. 7 招教你轻松搭建以图搜图系统!

    作者 | 小龙 责编 | 胡巍巍 当您听到"以图搜图"时,是否首先想到了百度.Google 等搜索引擎的以图搜图功能呢?事实上,您完全可以搭建一个属于自己的以图搜图系统:自己建立图 ...

最新文章

  1. android 购物车数量加减计算(几行代码实现效果)
  2. 代码荣辱观-以运用风格为荣,以随意编码为耻
  3. opencv笔记(3):图像镜像
  4. RPC和MQ各自适合的应用场景
  5. 人脸特征值能存放在sql server中吗_SQL运行内幕:从执行原理看调优的本质
  6. 求数组中各个元素的个数?
  7. 51nod1432 独木舟
  8. C#中的session用法
  9. cuteFTP使用教程
  10. 计算机语言中索引什么意思,index在中是什么意思
  11. 《玩儿起来吧》MATLAB 实时图像处理系列(一二三四)
  12. Python | peewee.InterfaceError
  13. c语言航标知识点,问题——阅读教学的航标
  14. java程序员面试时候经常会问的一些问题_面试JAVA程序员常遇到的一些问题了解一下...
  15. LNB电源市场现状及未来发展趋势分析
  16. win8.1安装vs2015专业版 KB2919335
  17. Copy BOM and Rounting 说明
  18. 【期末复习资料】嵌入式系统及应用
  19. 蜗牛星际能做网站服务器吗,蜗牛星际-完美运行ESXI
  20. Linux学习笔记 16(存储设备管理)

热门文章

  1. MySQL 语句大全
  2. 百度云BCC密钥对使用
  3. Nacos安装包下载及配置使用,附下载百度云连接
  4. 小虎电商浏览器:多多打单怎么手工打单
  5. 音高修正,对齐软件Synchro Arts 黑五促销
  6. 【044】OEDC数据库-经合组织公开国家数据库
  7. 平面设计计算机考试试卷分析,考试试卷分析评价系统的设计与实现..doc
  8. 盘点 | 跨平台桌面应用开发的5大主流框架
  9. 电脑测试软件pcmark,Pcmark10(电脑性能测试软件)
  10. 一起学时序分析之建立/保持时间裕量