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

注:实际操作时,采取了两种尺寸作对比(10*10,100*100)尺寸再大的话就会性能影响就会较大了,我实现了两种,目的是为了展示怎么设定不同尺寸。

2.      简化色彩:将缩小后的图像,转为64级灰度,即所有像素点总共只有64种颜色;

注:关于多少灰度级的问题,我并没有太在意,采取了一个合适的RGB to GRAY 算法就好,个人理解

3.      计算平均值:计算所有64个像素的灰度平均值;

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

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

6.      得到指纹以后,就可以对比不同的图像

GetSimilarity.h

//
//  GetSimilarity.h
//  imgsimlartest
//
//  Created by test on 16/3/3.
//  Copyright © 2016年 com.facishare.CoreTest. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef double Similarity;

@interface GetSimilarity : NSObject
- (void)setImgWithImgA:(UIImage*)imgA ImgB:(UIImage*)imgB;//设置需要对比的图片
- (void)setImgAWidthImg:(UIImage*)img;
- (void)setImgBWidthImg:(UIImage*)img;
- (Similarity)getSimilarityValue; //获取相似度
+ (Similarity)getSimilarityValueWithImgA:(UIImage*)imga ImgB:(UIImage*)imgb;//类方法
@end

GetSimilarity.m

//
//  GetSimilarity.m
//  imgsimlartest
//
//  Created by test on 16/3/3.
//  Copyright © 2016年 com.facishare.CoreTest. All rights reserved.
//

#import "GetSimilarity.h"
#define ImgSizeA 10
#define ImgSizeB 100
typedef enum workday
{
    SizeA,
    SizeB,
}GetSimilarityType;

@interface GetSimilarity()
@property (nonatomic,assign) Similarity similarity;
@property (nonatomic,strong) UIImage *imga;
@property (nonatomic,strong) UIImage *imgb;
@end

@implementation GetSimilarity
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.imga = [[UIImage alloc]init];
        self.imgb = [[UIImage alloc]init];
    }
    return self;
}

- (void)setImgWithImgA:(UIImage*)imgA ImgB:(UIImage*)imgB
{
    _imga = imgA;
    _imgb = imgB;
}

- (void)setImgAWidthImg:(UIImage*)img
{
    self.imga = img;
}

- (void)setImgBWidthImg:(UIImage*)img
{
    self.imgb = img;
}

- (Similarity)getSimilarityValue
{
    self.similarity = MAX([self getSimilarityValueWithType:SizeA], [self getSimilarityValueWithType:SizeB]);
    return self.similarity;
}
+ (Similarity)getSimilarityValueWithImgA:(UIImage *)imga ImgB:(UIImage *)imgb
{
    GetSimilarity * getSimilarity = [[GetSimilarity alloc]init];
    [getSimilarity setImgWithImgA:imga ImgB:imgb];
    return [getSimilarity getSimilarityValue];
}
- (Similarity)getSimilarityValueWithType:(GetSimilarityType)type;//
{
    int cursize = (type == SizeA ? ImgSizeA : ImgSizeB);
    int ArrSize = cursize * cursize + 1,a[ArrSize],b[ArrSize],i,j,grey,sum = 0;
    CGSize size = {cursize,cursize};
    UIImage * imga = [self reSizeImage:self.imga toSize:size];
    UIImage * imgb = [self reSizeImage:self.imgb toSize:size];//缩小图片尺寸

    a[ArrSize] = 0;
    b[ArrSize] = 0;
    CGPoint point;
    for (i = 0 ; i < cursize; i++) {//计算a的灰度
        for (j = 0; j < cursize; j++) {
            point.x = i;
            point.y = j;
            grey = ToGrey([self UIcolorToRGB:[self colorAtPixel:point img:imga]]);
            a[cursize * i + j] = grey;
            a[ArrSize] += grey;
        }
    }
    a[ArrSize] /= (ArrSize - 1);//灰度平均值
    for (i = 0 ; i < cursize; i++) {//计算b的灰度
        for (j = 0; j < cursize; j++) {
            point.x = i;
            point.y = j;
            grey = ToGrey([self UIcolorToRGB:[self colorAtPixel:point img:imgb]]);
            b[cursize * i + j] = grey;
            b[ArrSize] += grey;
        }
    }
    b[ArrSize] /= (ArrSize - 1);//灰度平均值
    for (i = 0 ; i < ArrSize ; i++)//灰度分布计算
    {
        a[i] = (a[i] < a[ArrSize] ? 0 : 1);
        b[i] = (b[i] < b[ArrSize] ? 0 : 1);
    }
    ArrSize -= 1;
    for (i = 0 ; i < ArrSize ; i++)
    {
        sum += (a[i] == b[i] ? 1 : 0);
    }

    return sum * 1.0 / ArrSize;
}

- (UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize//重新设定图片尺寸
{
    UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height));
    [image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)];
    UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return reSizeImage;
}

unsigned int ToGrey(unsigned int rgb)//RGB计算灰度
{
    unsigned int blue   = (rgb & 0x000000FF) >> 0;
    unsigned int green  = (rgb & 0x0000FF00) >> 8;
    unsigned int red    = (rgb & 0x00FF0000) >> 16;
    return ( red*38 +  green * 75 +  blue * 15 )>>7;
}

- (unsigned int)UIcolorToRGB:(UIColor*)color//UIColor转16进制RGB
{
    unsigned int RGB,R,G,B;
    RGB = R = G = B = 0x00000000;
    CGFloat r,g,b,a;
    [color getRed:&r green:&g blue:&b alpha:&a];
    R = r * 256 ;
    G = g * 256 ;
    B = b * 256 ;
    RGB = (R << 16) | (G << 8) | B ;
    return RGB;
}

- (UIColor *)colorAtPixel:(CGPoint)point img:(UIImage*)img{//获取指定point位置的RGB
    // Cancel if point is outside image coordinates
    if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, img.size.width, img.size.height), point)) { return nil; }

    NSInteger   pointX  = trunc(point.x);
    NSInteger   pointY  = trunc(point.y);
    CGImageRef  cgImage = img.CGImage;
    NSUInteger  width   = img.size.width;
    NSUInteger  height  = img.size.height;
    int bytesPerPixel   = 4;
    int bytesPerRow     = bytesPerPixel * 1;
    NSUInteger bitsPerComponent = 8;
    unsigned char pixelData[4] = { 0, 0, 0, 0 };
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGColorSpaceRelease(colorSpace);
    CGContextSetBlendMode(context, kCGBlendModeCopy);

    // Draw the pixel we are interested in onto the bitmap context
    CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
    CGContextRelease(context);
    // Convert color values [0..255] to floats [0.0..1.0]

    CGFloat red   = (CGFloat)pixelData[0] / 255.0f;
    CGFloat green = (CGFloat)pixelData[1] / 255.0f;
    CGFloat blue  = (CGFloat)pixelData[2] / 255.0f;
    CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
@end

  

iOS图片相似度比较的更多相关文章

  1. iOS,OC,图片相似度比较,图片指纹

    上周,正在忙,突然有个同学找我帮忙,说有个需求:图片相似度比较. 网上搜了一下,感觉不是很难,就写了下,这里分享给需要的小伙伴. 首先,本次采用的是OpenCV,图片哈希值: 先说一下基本思路: 1. ...

  2. 实现iOS图片等资源文件的热更新化(三):动态的资源文件夹

    简介 此文,将尝试动态从某个不确定的文件夹中加载资源文件.文章,会继续完善自定义的 imageNamed 函数,并为下一篇文章铺垫. 这么做的意义 正如我们经常所说的那样,大多数情景知道做事的意义往往 ...

  3. jquery mobile上传图片完整例子(包含ios图片横向问题处理和C#后台图片压缩)

    上传图片本身是个基本的小功能,但是到了移动端就不那么简单了,相信找到这篇文章的你一定有深深的同感. 本文实例是:在(移动端)页面中点击图片,然后选择文件,然后保存.使用Asp.net 难点一:后台获取 ...

  4. iOS 图片旋转方法

    iOS 图片旋转方法 通过 CGImage 或 CIImage 旋转特定角度 UIImage可通过CGImage或CIImage初始化,初始化方法分别为init(cgImage: CGImage, s ...

  5. iOS 图片裁剪 + 旋转

    iOS 图片裁剪 + 旋转 之前分别介绍了图片裁剪和图片旋转方法 <iOS 图片裁剪方法> 地址:http://www.cnblogs.com/silence-cnblogs/p/6490 ...

  6. js 前端图片压缩+ios图片角度旋转

    step1:读取选择的图片,并转为base64: function ImgToBase64 (e, fn) { // 图片方向角 //fn为传入的方法函数,在图片操作完成之后执行 var Orient ...

  7. iOS 图片轮播图(自动滚动)

    iOS 图片轮播图(自动滚动) #import "DDViewController.h" #define DDImageCount 5 @interface DDViewContr ...

  8. iOS图片加载到内存中占用内存情况

    我的测试结果: 图片占用内存   图片尺寸           .png文件大小 1MB              512*512          316KB 4MB              10 ...

  9. 实现iOS图片等资源文件的热更新化(五): 一个简单完整的资源热更新页面

    简介 一个简单的关于页面,有一个图片,版本号,App名称等,着重演示各个系列的文章完整集成示例. 动机与意义 这是系列文章的最后一篇.今天抽空写下,收下尾.文章本身会在第四篇的基础上,简单扩充下代码, ...

随机推荐

  1. System V共享内存介绍

    (一)简单概念 共享内存作为一种进程间通信的方式,其相较于其他进程间通信方式而言最大的优点就是数据传输速率快.其内部实现的方式采用了Linux进程地址空间中的mmap文件映射区,将文件内容直接映射到各 ...

  2. 离线安装SDK

    1.下载android-sdk_rXX-windows.zip(XX为版本号,也可以下.exe版的不过没试过) 2.下载SDK 2.1.在浏览器输入http://dl-ssl.google.com/a ...

  3. MySQL取得某一范围随机数(MySQL随机数)

    若要在i ≤ R ≤ j 这个范围得到一个随机整数R ,需要用到表达式 FLOOR(i + RAND() * (j – i + 1)). 例如, 若要在7 到 12 的范围(包括7和12)内得到一个随 ...

  4. FTP webReq.ContentType异常的处理

    FtpWebRequest webReq; webReq = (FtpWebRequest)FtpWebRequest.Create(new Uri(updateFileUrl)); FtpWebRe ...

  5. Struts2学习笔记01 之 简介及配置

    一.Struts简介 * 是轻量级的MVC框架,主要解决了请求分发的问题,重心在控制层和表现层.运用ASOP的思想,使用拦截器来扩展业务控制器 二.使用步骤: 1.引入Sturts2的相关JAR包 2 ...

  6. 关于在C#中对类中的隐藏基类方法和重写方法的理解

    最近在学习C#,在C#中的类看到重写和隐藏基类的方法这些概念.才开始感觉自己不是很理解这些概念.也区分不开这些概念.通过自己的查找资料和练习后.慢慢的理解了类中的隐藏和重写这个概念.在C#中只有在基类 ...

  7. EL表达式无法显示Model中的数据

    后台程序通过Debug都能正常返回数据并封装到Model中.而在前台通过EL表达式取值时却是原样输出,如${cart.num}... ///展现我的购物车 @RequestMapping(" ...

  8. 使用jsonp形式跨域访问实现电商平台的左侧导航栏

    电商平台有个具备的左侧商品类目的导航栏的结构. 通过jsonp跨域访问电商平台的后台管理系统商品分类.(主要实现后台Java代码) 实现基本步骤: 1.在后台管理系统中准备相应的json数据. poj ...

  9. 基于kbengine 0.4.20

    前言: v0.0.1 2015-04-10 誉小痕(shawhen2012@hotmail.com) v0.0.2 2015-04-12 誉小痕(shawhen2012@hotmail.com) ch ...

  10. centos6.5 宽带连接

    Centos默认不会建立本地连接,至少在虚拟机里是这样,自己新建一个就行了:1.cd /etc/sysconfig/network-scripts/2.vi ifcfg-eth0 DEVICE=eth ...