鸿蒙图片相似性对比
图片相似度对比方法概述
图片相似度对比是计算机视觉中的一个重要任务,主要用于判断两张图片在内容上的相似程度。以下是几种常见的图片相似度对比方法及其实现思路:
1. 基于像素的直接比较
最直接的方法是逐像素比较两张图片的差异,常用的指标有均方误差 (MSE) 和结构相似性指数 (SSIM)。
2. 基于特征提取的方法
使用图像特征描述符 (如 SIFT、SURF 或 ORB) 提取关键点和特征向量,然后比较特征向量的相似度.
3. 基于哈希的方法
通过计算图像的哈希值 (如感知哈希 pHash、平均哈希 aHash 等) 来快速比较图片相似度。
4. 基于深度学习的方法
使用预训练的卷积神经网络 (如 ResNet、VGG 等) 提取图像特征向量,然后计算向量间的余弦相似度。
选择合适的方法
- 像素方法:简单直接,但对图像变换 (如旋转、缩放) 敏感。
- 特征方法:对图像变换有较好的鲁棒性,计算量较大。
- 哈希方法:计算速度快,适合快速筛选,但精度较低。
- 深度学习方法:精度高,对各种变化都有很好的鲁棒性,但计算资源需求大。
鸿蒙基于Hash值相似性对比
图片压缩
async imageCompressionToSize(pixelMap: image.PixelMap, targetSize: number) {let infor = await pixelMap.getImageInfo()if (infor.size.height > 2000) {pixelMap.scaleSync(0.5, 0.5)}let value = await this.imageCompression(pixelMap, 90)// AmLog.debugOut("imageDataSize:" + value.buffer.byteLength)if (value.buffer.byteLength <= targetSize) {return value} else {while (value.buffer.byteLength/1024 > targetSize && value.quality > 10){try {value = await this.imageCompression(pixelMap, value.quality - 10)}catch (e) {break}}}let uint = new Uint8Array(value.buffer)let str = StrUtil.unit8ArrayToStr(uint)let md5 = await new Md5Util().doMd(str)value.md5 = md5return value}//压缩图片async imageCompression(pixelMap: image.PixelMap,quality:number) : Promise<ImageComValue>{let packOption: image.PackingOption = {format: "image/jpeg",quality: quality}let packer = image.createImagePacker()let buffer = await packer.packToData(pixelMap, packOption)// AmLog.debugOut(quality + "压缩imageDataSize:" + buffer.byteLength)let imageSource = image.createImageSource(buffer)const decodeOptions:image.DecodingOptions = {desiredPixelFormat: image.PixelMapFormat.RGBA_8888}let pixelMap1 = await imageSource.createPixelMap(decodeOptions)packer.release()return {pixMap: pixelMap1,quality,buffer}}
计算哈希值
async getImageHash(imageSource: image.ImageSource): Promise<string> {let packOption: image.PackingOption = {format: "image/jpeg",quality: 80};const decodeOptions:image.DecodingOptions = {desiredSize: { width: this.imageSizeValue, height: this.imageSizeValue }, // 调整为像素大小desiredPixelFormat: image.PixelMapFormat.RGBA_8888}let pixelMap = await imageSource.createPixelMap(decodeOptions)this.imageSizeValue/imageLength)// 转换为灰度图并计算DCT变换(此处简化处理)// 创建图像打包器实例const imagePackerApi = image.createImagePacker();const pixelBuffer1:ArrayBuffer = await imagePackerApi.packToData(pixelMap,packOption)const pixels :Uint8Array = StrUtil.bufferToUint8Array(pixelBuffer1)//灰度计算let grayValues:number[] = []for (let i = 0; i < this.imageSizeValue * this.imageSizeValue; i++) {const idx = i * 4;if (idx + 2 >= pixels.byteLength) {grayValues.push(0)continue}// 简化的灰度计算grayValues.push( Math.floor((pixels[idx] * 0.299) + (pixels[idx + 1] * 0.587) + (pixels[idx + 2] * 0.114)))}//简化版DCT(离散余弦变换)这里使用简化版DCT实现,实际应用中应使用更高效的算法let dctPixels = this.simpleDCT(grayValues, this.imageSizeValue)// 计算均值const sum = dctPixels.reduce((acc, val,index) => {// 检查是否有NaN值if (isNaN(val)) {// AmLog.debugOut(`发现NaN值在位置:`+ index)return acc}return acc + val;}, 0);const mean = sum / dctPixels.length// 生成哈希值let hash = '';for (let i = 0; i < dctPixels.length; i++) {if (isNaN(dctPixels[i])) {continue}hash += dctPixels[i] >= mean ? '1' : '0';}return hash;}
哈希值对比
//比较图片相似度async compareImagesByHashPath(path1: string, path2: string): Promise<number> {const hash1 = await this.getImageHashByPath(path1);const hash2 = await this.getImageHashByPath(path2);// 计算汉明距离let diff = 0;for (let i = 0; i < hash1.length; i++) {if (hash1[i] !== hash2[i]) diff++;}// 计算相似度(汉明距离越小越相似)return (1 - diff / hash1.length) * 100;}//通过hash值对比图片相似度compareImagesByHash(hash1: string, hash2: string): number {// 计算汉明距离let diff = 0;for (let i = 0; i < hash1.length; i++) {if (hash1[i] === hash2[i]) diff++;}// 计算相似度(汉明距离越小越相似)return diff / hash1.length * 100;}
性能与精度平衡
imageSizeValue的选取
哈希尺寸 | 基础尺寸 | 内存占用 | 计算时间 | 适用场景 |
---|---|---|---|---|
8×8 | 32×32 | 低 | 快 | 快速筛选 |
16×16 | 48×48 | 中 | 中 | 常规比较 |
16×64 | 96×96 | 高 | 慢 | 高精度匹配 |