Android 以图找图功能

    xiaoxiao2021-12-14  17

          到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.结束

     

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

      

     

        

    转载请注明原文地址: https://ju.6miu.com/read-965601.html

    最新回复(0)