【问题标题】:Generate hash from UIImage从 UIImage 生成哈希
【发布时间】:2009-11-06 01:16:50
【问题描述】:

我正在尝试比较文件系统中的两个 UIImage 以查看它们是否相同。显然,我不能使用 NSObject 的 hash 方法,因为它返回的是对象的 hash,而不是实际的图像数据。

我发现代码从字符串生成 MD5 哈希,但我还没有发现如何为 UIImage 实现它。

我应该如何对 UIImage 进行散列处理?还是我的图像比较方法完全关闭了?

【问题讨论】:

    标签: iphone cocoa-touch hash


    【解决方案1】:

    我最终使用以下代码来完成任务。请注意,这需要您导入 <CommonCrypto/CommonDigest.h>:

    unsigned char result[CC_MD5_DIGEST_LENGTH];
    NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(inImage)];
    CC_MD5([imageData bytes], [imageData length], result);
    NSString *imageHash = [NSString stringWithFormat:
                           @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                           result[0], result[1], result[2], result[3], 
                           result[4], result[5], result[6], result[7],
                           result[8], result[9], result[10], result[11],
                           result[12], result[13], result[14], result[15]
                           ];
    

    【讨论】:

    • 也许是个愚蠢的问题,但这是否需要在 App Store 提交中检查“我添加了密码学”?
    • 我不能代表所有情况,但是,当我提交我的应用程序时,我没有选中该复选框。我只是使用哈希来比较两个图像,而不是用于任何类型的数据加密。
    • 对我来说,这会在每次传递时生成不同的哈希值。使用 [imageData bytes] 作为 CC_MD5 的第一个参数似乎可以修复它。
    • 您应该使用CC_MD5_DIGEST_LENGTH 而不是16,以防值发生变化。
    • 既然您已经使用 CC_MD5_DIGEST_LENGTH 作为数组长度,您还应该更新格​​式化字符串的方式以使其具有适应性。我建议使用以下代码: NSString *imageHash = @""; for (NSInteger i = 0; i
    【解决方案2】:

    不是最优解:

    [ UIImagePNGRepresentation( uiImage1 ) isEqualToData: 
          UIImagePNGRepresentation( uiImage2 ) ];
    

    这基本上比较了 2 张图像的 PNG 编码数据。由于图像相似性是一个复杂的主题,因此可以根据最终目标的确切含义来设计更好更快的解决方案(即,您是要逐像素比较图像,还是只是近似相似性,这可以使用源的下采样版本图片等)。

    【讨论】:

    • 那么我们应该如何获得近似相似度,比如高达 90% 的相似度。我尝试了 RGB 方法,但是当您的图库中有大约 1000 张图像并且您需要与其中一张进行比较时,这是一个非常耗时的过程另一个。
    • 是的,它会是 user2924482,它将文件转换为您将传递的 uiimage 的 png 等效数据,不管它是哪种文件类型
    【解决方案3】:

    UIImage 哈希

    Swift 4.2 中使用 SHA256 算法对 UIImage 进行哈希处理的 Swift 代码。您可以使用其他算法,这些算法可能更快或生成的重复次数更少,但对于大多数用例来说,这个已经足够了。

    只需将代码放在项目中的某处并像这样使用它:yourUIImage.sha256()

    extension UIImage{
        
        public func sha256() -> String{
            if let imageData = cgImage?.dataProvider?.data as? Data {
                return hexStringFromData(input: digest(input: imageData as NSData))
            }
            return ""
        }
        
        private func digest(input : NSData) -> NSData {
            let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
            var hash = [UInt8](repeating: 0, count: digestLength)
            CC_SHA256(input.bytes, UInt32(input.length), &hash)
            return NSData(bytes: hash, length: digestLength)
        }
        
        private  func hexStringFromData(input: NSData) -> String {
            var bytes = [UInt8](repeating: 0, count: input.length)
            input.getBytes(&bytes, length: input.length)
            
            var hexString = ""
            for byte in bytes {
                hexString += String(format:"%02x", UInt8(byte))
            }
            
            return hexString
        }
    }
    

    桥接头

    顺便说一下,您需要一个导入 CommonCrypto 的桥接头。如果您没有,请按照以下步骤操作:

    1. 新建文件->头文件->另存为BridgingHeader
    2. 在 Build Settings -> Objective-C Bridging Header -> 添加ProjectName/BridgingHeader.h
    3. #import <CommonCrypto/CommonHMAC.h> 放入您的头文件中

    重复概率

    重复概率很低,但如果你有庞大的数据集,你可以相对容易地升级到 SHA512:

    重复概率大约是:

    来源:https://crypto.stackexchange.com/questions/24732/probability-of-sha256-collisions-for-certain-amount-of-hashed-values

    【讨论】:

      【解决方案4】:

      下面有更优雅的代码

      +(NSString *)MD5HexDigest:(NSData *)input {
          unsigned char result[CC_MD5_DIGEST_LENGTH];
      
          CC_MD5(input.bytes, (unsigned int)input.length, result);
          NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
          for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
              [ret appendFormat:@"%02x",result[i]];
          }
          return ret;
      }

      【讨论】:

        【解决方案5】:

        这个更新的 sn-p 应该可以工作。感谢andreas's answer 提供大纲。

        // Usage
        image.sha256
        
        // extensions
        import CommonCrypto
        
        extension UIImage {
            
            var sha256: String {
                guard let imageData = jpegData(compressionQuality: 1) else { return "" }
                return imageData.digest.hexString
            }
        }
        
        extension Data {
           
            var digest: Data {
                let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
                var hash = [UInt8](repeating: 0, count: digestLength)
                CC_SHA256(bytes, UInt32(count), &hash)
                return Data(bytes: hash, count: digestLength)
            }
        
            var hexString: String {
                let hexString = map { String(format: "%02.2hhx", $0) }.joined()
                return hexString
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2018-04-02
          • 2017-05-24
          • 1970-01-01
          • 2012-11-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-29
          • 2014-03-20
          相关资源
          最近更新 更多