Android实现图片相似度

最近公司有一个需求,就是希望能判断用户提交的照片是否是身份证的正面或者反面。可以通过预设一张拍摄清晰的身份证正面或者反面,来对比是否相似,那么问题就转化为如何计算两张图片相似度。找到一篇阮一峰老师当年的博客 很有启发,于是根据他说的每一步用Android里的方法来实现。


第一步,缩小尺寸。

将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

Bitmap bitmap8 = ThumbnailUtils.extractThumbnail(bitmapOriginal, 8, 8);

第二步,简化色彩。

将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

    public static Bitmap convertGreyImg(Bitmap img) {        int width = img.getWidth();         //获取位图的宽        int height = img.getHeight();       //获取位图的高        int[] pixels = new int[width * height]; //通过位图的大小创建像素点数组        img.getPixels(pixels, 0, width, 0, 0, width, height);        int alpha = 0xFF << 24;        for (int i = 0; i < height; i++) {            for (int j = 0; j < width; j++) {                int original = pixels[width * i + j];                int red = ((original & 0x00FF0000) >> 16);                int green = ((original & 0x0000FF00) >> 8);                int blue = (original & 0x000000FF);                int grey = (int) ((float) red * 0.3 + (float) green * 0.59 + (float) blue * 0.11);                grey = alpha | (grey << 16) | (grey << 8) | grey;                pixels[width * i + j] = grey;            }        }        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);        result.setPixels(pixels, 0, width, 0, 0, width, height);        return result;    }

第三步,计算平均值。

计算所有64个像素的灰度平均值。

    public static int getAvg(Bitmap img) {        int width = img.getWidth();        int height = img.getHeight();        int[] pixels = new int[width * height];        img.getPixels(pixels, 0, width, 0, 0, width, height);        int avgPixel = 0;        for (int pixel : pixels) {            avgPixel += pixel;        }        return avgPixel / pixels.length;    }

第四步,比较像素的灰度。

将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

    public static String getBinary(Bitmap img, int average) {        StringBuilder sb = new StringBuilder();        int width = img.getWidth();        int height = img.getHeight();        int[] pixels = new int[width * height];        img.getPixels(pixels, 0, width, 0, 0, width, height);        for (int i = 0; i < height; i++) {            for (int j = 0; j < width; j++) {                int original = pixels[width * i + j];                if (original >= average) {                    pixels[width * i + j] = 1;                } else {                    pixels[width * i + j] = 0;                }                sb.append(pixels[width * i + j]);            }        }        return sb.toString();    }

第五步,计算哈希值。

将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

下面是得到16位16进制的字符串,作为该图片的消息指纹

    public static String binaryString2hexString(String bString) {        if (bString == null || bString.equals("") || bString.length() % 8 != 0)            return null;        StringBuilder sb = new StringBuilder();        int iTmp;        for (int i = 0; i < bString.length(); i += 4) {            iTmp = 0;            for (int j = 0; j < 4; j++) {                iTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1);            }            sb.append(Integer.toHexString(iTmp));        }        return sb.toString();    }

下面是两张图片的消息指纹比较的方法

    static void diff(String s1, String s2) {        char[] s1s = s1.toCharArray();        char[] s2s = s2.toCharArray();        int diffNum = 0;        for (int i = 0; iif (s1s[i] != s2s[i]) {                diffNum++;            }        }        System.out.println("diffNum="+diffNum);    }

至此关键代码都在这里了。


我拍照片试验了几次,以下是部分结果:

Str64->16=81000081e9ff0000  Str64->16=01800049e1ff0000  Str64->16=10000d41ebff8000  Str64->16=fdff47e80020231b  Str64->16=ffffcfb80028031b  Str64->16=ffff4fee0408031b  Str64->16=040c7104000e7fff  Str64->16=0b1b999f0300052f  Str64->16=0b1b99c101400527  

1、2、3行,4、5、6行,8、9行是大致同一个位置(手持手机,尽量保持同一个位置),第7行是其他位置,说明结果还是比较靠谱的,个人认为diff(s1, s2)方法

结果在1~5说明两张照片极其相似,6~10说明较为相似,10以上说明不相似

(相关代码在我的github上)

更多相关文章

  1. Android(安卓)滑动切换(首页展示,图片、新闻自动切换,循环切换,自动
  2. [置顶] Android中调用系统相机、系统相册来获取图片,并裁剪图片。
  3. 自定义Android带图片的按钮
  4. Android多点触控技术实战 针对图片自由缩放和移动
  5. [原] Android中怎么将图片平铺
  6. Android(安卓)主流开源框架(七)Glide 的缓存机制
  7. 如何优雅地在Android上实现iOS的图片预览
  8. Android(安卓)更改头像(图片)并上传服务器功能Demo详解
  9. android实现连连看,附源码

随机推荐

  1. 另一个div内的任意宽度的中心div
  2. css3+html5——拼接图片中icon的使用、照
  3. 认识DHTML中的“行为”组件
  4. 如何从input type = file中删除一个对象?
  5. 如何在jquery中增加itemtype的值?
  6. xml格式原样输出到html或是jsp页面
  7. 用HTML+CSS编写一个计科院网站首页的静态
  8. 布局的标记建议和一些更一般的问题
  9. IDEA SpringBoot入门与速查—HTML页与Thy
  10. sublime text3快速生成html头部信息