Android 以图找图功能

      到2016年的最后一个月了,总得写点什么或者记录点什么。恩,就记录一下,我当时做以图找图,这个功能的过程和结果吧。以图找图简而言之就是确认小图是否属于大图的一部分。

 这个方法不是百分百能找到的,也可能找到错误的图片,如果2个大图和小图的相似度很高的话。

1.序

    刚开始做这个功能的时候,我一直在往误区上找,认为这是Android的项目,然后一直在找android方面的东西,也确实找到了,但这方面根本没有相关的DEMO(其实也是因为个人有点懒,有现成的,总是想直接用。)

   然后想到了其实可以从java方面图片,这样就发现很多都是通过像素点进行查找的,但原理上是没错的就是查找的过程就有点慢了。在电脑上运行当然很快,但放在android上就很慢了,毕竟你需要对比每个像素点。

  最后是通过计算哈希值的方法,来进行图片的查找。虽然也需要一块一块的查(就是根据原图片的大小,然后在目标图片上查找),然后得出结论是否是属于目标图片的。

2.代码

 

        /** 小图是否属于大图
	 * @param mubiao 目标图片(小图)地址
	 * @param yuantu 源图片(大图)地址
	 * @return
	 * @throws IOException
	 */
	private static boolean FindImg(String mubiao, String yuantu) throws IOException{
		boolean isFind = false;
		  Bitmap yuantusource = BitmapFactory.decodeFile(yuantu, null); 
		  Bitmap mubiaosource = BitmapFactory.decodeFile(mubiao, null); 
//		  huidu("yuantu" , yuantu);
//		  huidu("mubiao" , mubiao);
		  String mubiaoHashCode;
		  String yuantuHashCode;
		  Bitmap jiequsource;
		  int width = yuantusource.getWidth();
		  int height = yuantusource.getHeight();
		  int Mwidth = mubiaosource.getWidth();
		  int Mheight = mubiaosource.getHeight();
		  mubiaoHashCode = BufproduceFingerPrint(mubiaosource);
              //通过循环来查找图片(就是从左上到右下)
             for(int i=0;i<width-Mwidth;i++){
			  for(int j= 0;j<height-Mheight;j++){
				  jiequsource = Bitmap.createBitmap(yuantusource, i, j, Mwidth, Mheight, 
                       null,  false);
				  yuantuHashCode = BufproduceFingerPrint(jiequsource);
				  int difference = hammingDistance(mubiaoHashCode, yuantuHashCode);
				  if(difference == 0 ){
                    String.valueOf(j));
//					  LogInfo.ceshi("找到2:x="+ i + "y=" + j);
					  isFind = true;
					  break;
				  }  else{
//					  LogInfo.ceshi("没找到2:x="+ i + "y=" + j);
//					  ToastUtil.showToast(context, "正在查找中···");
				  }
			  }	 
		  } 
		  
		  if(isFind){
			  return true;
		  }else{
			  return false;
		  }
	  }

    /**
	  * 处理图片
	  * @param source
	  * @return
	  */
	public static String BufproduceFingerPrint(Bitmap source) {
//	    BufferedImage source = ImageHelper.readPNGImage(filename);// 读取文件
	    int width = 8;
	    int height = 8;
	    int pixelColor;
	    // 第一步,缩小尺寸。
	    // 将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。
	    Bitmap thumb = ImageHelper.zoomImage(source, width,height);

	    // 第二步,简化色彩。
	    // 将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。
	    int[] pixels = new int[width * height];
	    for (int i = 0; i < width; i++) {
	      for (int j = 0; j < height; j++) {
//	    	  System.out.println("i=" + i +";y=" + j);
//	    	  pixelColor = thumb.getPixel(i, j);
//	    	  R = Color.red(pixelColor);
//              G = Color.green(pixelColor);
//              B = Color.blue(pixelColor);
	        pixels[i * height + j] = ImageHelper.rgbToGray(thumb.getPixel(i, j));
	      }
	    }

	    // 第三步,计算平均值。
	    // 计算所有64个像素的灰度平均值。
	    int avgPixel = ImageHelper.average(pixels);

	    // 第四步,比较像素的灰度。
	    // 将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。
	    int[] comps = new int[width * height];
	    for (int i = 0; i < comps.length; i++) {
	      if (pixels[i] >= avgPixel) {
	        comps[i] = 1;
	      } else {
	        comps[i] = 0;
	      }
	    }

	    // 第五步,计算哈希值。
	    // 将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。
	    StringBuffer hashCode = new StringBuffer();
	    for (int i = 0; i < comps.length; i += 4) {
	      int result = comps[i] * (int) Math.pow(2, 3) + comps[i + 1]
	          * (int) Math.pow(2, 2) + comps[i + 2] * (int) Math.pow(2, 1)
	          + comps[i + 2];
	      hashCode.append(binaryToHex(result));
	    }

	    // 得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。
	    return hashCode.toString();
	  }
	 private static char binaryToHex(int binary) {
		    char ch = ' ';
		    switch (binary) {
		    case 0:
		      ch = '0';
		      break;
		    case 1:
		      ch = '1';
		      break;
		    case 2:
		      ch = '2';
		      break;
		    case 3:
		      ch = '3';
		      break;
		    case 4:
		      ch = '4';
		      break;
		    case 5:
		      ch = '5';
		      break;
		    case 6:
		      ch = '6';
		      break;
		    case 7:
		      ch = '7';
		      break;
		    case 8:
		      ch = '8';
		      break;
		    case 9:
		      ch = '9';
		      break;
		    case 10:
		      ch = 'a';
		      break;
		    case 11:
		      ch = 'b';
		      break;
		    case 12:
		      ch = 'c';
		      break;
		    case 13:
		      ch = 'd';
		      break;
		    case 14:
		      ch = 'e';
		      break;
		    case 15:
		      ch = 'f';
		      break;
		    default:
		      ch = ' ';
		    }
		    return ch;
		  }

   /**
	 * 2个是否相同,0为相同
	 * @param sourceHashCode
	 * @param hashCode
	 * @return
	 */
	 public static int hammingDistance(String sourceHashCode, String hashCode) {
		    int difference = 0;
		    int len = sourceHashCode.length();

		    for (int i = 0; i < len; i++) {
		      if (sourceHashCode.charAt(i) != hashCode.charAt(i)) {
		        difference++;
		      }
		    }

		    return difference;
		  }

 

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

public class ImageHelper {
	public static Bitmap zoomImage(Bitmap bgimage, double newWidth,  
            double newHeight) {  
    // 获取这个图片的宽和高  
    float width = bgimage.getWidth();  
    float height = bgimage.getHeight();  
    // 创建操作图片用的matrix对象  
    Matrix matrix = new Matrix();  
    // 计算宽高缩放率  
    float scaleWidth = ((float) newWidth) / width;  
    float scaleHeight = ((float) newHeight) / height;  
    // 缩放图片动作  
    matrix.postScale(scaleWidth, scaleHeight);  
    Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,  
                    (int) height, matrix, true);  
    return bitmap;  
} 
	
	private Bitmap compressImage(Bitmap image) {  
		  
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中  
        int options = 100;  
        while ( baos.toByteArray().length / 1024>100) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩         
            baos.reset();//重置baos即清空baos  
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中  
            options -= 10;//每次都减少10  
        }  
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中  
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片  
        return bitmap;  
    }  
	
	public static int rgbToGray(int pixels) {
	    // int _alpha = (pixels >> 24) & 0xFF;
	    int _red = (pixels >> 16) & 0xFF;
	    int _green = (pixels >> 8) & 0xFF;
	    int _blue = (pixels) & 0xFF;
	    return (int) (0.3 * _red + 0.59 * _green + 0.11 * _blue);
	  }
	//
	// 
	  public static int average(int[] pixels) {
	    float m = 0;
	    for (int i = 0; i < pixels.length; ++i) {
	      m += pixels[i];
	    }
	    m = m / pixels.length;
	    return (int) m;
	  }
}

 

 

 

 

 

3.结束

 

  恩,这就是以图找图的所有代码=-=恩,是通过网上方法总结出来了的=-=就这样了。

  

 

    

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值