经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
python?OpenCV计算图片相似度的5种算法
来源:jb51  时间:2022/8/3 12:49:30  对本文有异议

原始两张图片:

代码运行结果如下。

5种算法

值哈希算法差值哈希算法感知哈希算法都是值越小,相似度越高,取值为0-64,即汉明距离中,64位的hash值有多少不同。 三直方图单通道直方图的值为0-1,值越大,相似度越高。

源代码如下:

  1. import cv2
  2. import numpy as np
  3. from PIL import Image
  4. import requests
  5. from io import BytesIO
  6. import matplotlib
  7. matplotlib.use('TkAgg')
  8. import matplotlib.pyplot as plt
  9. def aHash(img):
  10. # 均值哈希算法
  11. # 缩放为8*8
  12. img = cv2.resize(img, (8, 8))
  13. # 转换为灰度图
  14. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  15. # s为像素和初值为0,hash_str为hash值初值为''
  16. s = 0
  17. hash_str = ''
  18. # 遍历累加求像素和
  19. for i in range(8):
  20. for j in range(8):
  21. s = s+gray[i, j]
  22. # 求平均灰度
  23. avg = s/64
  24. # 灰度大于平均值为1相反为0生成图片的hash值
  25. for i in range(8):
  26. for j in range(8):
  27. if gray[i, j] > avg:
  28. hash_str = hash_str+'1'
  29. else:
  30. hash_str = hash_str+'0'
  31. return hash_str
  32. def dHash(img):
  33. # 差值哈希算法
  34. # 缩放8*8
  35. img = cv2.resize(img, (9, 8))
  36. # 转换灰度图
  37. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  38. hash_str = ''
  39. # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
  40. for i in range(8):
  41. for j in range(8):
  42. if gray[i, j] > gray[i, j+1]:
  43. hash_str = hash_str+'1'
  44. else:
  45. hash_str = hash_str+'0'
  46. return hash_str
  47. def pHash(img):
  48. # 感知哈希算法
  49. # 缩放32*32
  50. img = cv2.resize(img, (32, 32)) # , interpolation=cv2.INTER_CUBIC
  51. # 转换为灰度图
  52. gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  53. # 将灰度图转为浮点型,再进行dct变换
  54. dct = cv2.dct(np.float32(gray))
  55. # opencv实现的掩码操作
  56. dct_roi = dct[0:8, 0:8]
  57. hash = []
  58. avreage = np.mean(dct_roi)
  59. for i in range(dct_roi.shape[0]):
  60. for j in range(dct_roi.shape[1]):
  61. if dct_roi[i, j] > avreage:
  62. hash.append(1)
  63. else:
  64. hash.append(0)
  65. return hash
  66. def calculate(image1, image2):
  67. # 灰度直方图算法
  68. # 计算单通道的直方图的相似值
  69. hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
  70. hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
  71. # 计算直方图的重合度
  72. degree = 0
  73. for i in range(len(hist1)):
  74. if hist1[i] != hist2[i]:
  75. degree = degree + (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
  76. else:
  77. degree = degree + 1
  78. degree = degree / len(hist1)
  79. return degree
  80. def classify_hist_with_split(image1, image2, size=(256, 256)):
  81. # RGB每个通道的直方图相似度
  82. # 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
  83. image1 = cv2.resize(image1, size)
  84. image2 = cv2.resize(image2, size)
  85. sub_image1 = cv2.split(image1)
  86. sub_image2 = cv2.split(image2)
  87. sub_data = 0
  88. for im1, im2 in zip(sub_image1, sub_image2):
  89. sub_data += calculate(im1, im2)
  90. sub_data = sub_data / 3
  91. return sub_data
  92. def cmpHash(hash1, hash2):
  93. # Hash值对比
  94. # 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
  95. # 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
  96. # 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
  97. n = 0
  98. # hash长度不同则返回-1代表传参出错
  99. if len(hash1) != len(hash2):
  100. return -1
  101. # 遍历判断
  102. for i in range(len(hash1)):
  103. # 不相等则n计数+1,n最终为相似度
  104. if hash1[i] != hash2[i]:
  105. n = n + 1
  106. return n
  107. def getImageByUrl(url):
  108. # 根据图片url 获取图片对象
  109. html = requests.get(url, verify=False)
  110. image = Image.open(BytesIO(html.content))
  111. return image
  112. def PILImageToCV():
  113. # PIL Image转换成OpenCV格式
  114. path = "/Users/waldenz/Documents/Work/doc/TestImages/t3.png"
  115. img = Image.open(path)
  116. plt.subplot(121)
  117. plt.imshow(img)
  118. print(isinstance(img, np.ndarray))
  119. img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
  120. print(isinstance(img, np.ndarray))
  121. plt.subplot(122)
  122. plt.imshow(img)
  123. plt.show()
  124. def CVImageToPIL():
  125. # OpenCV图片转换为PIL image
  126. path = "/Users/waldenz/Documents/Work/doc/TestImages/t3.png"
  127. img = cv2.imread(path)
  128. # cv2.imshow("OpenCV",img)
  129. plt.subplot(121)
  130. plt.imshow(img)
  131. img2 = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
  132. plt.subplot(122)
  133. plt.imshow(img2)
  134. plt.show()
  135. def bytes_to_cvimage(filebytes):
  136. # 图片字节流转换为cv image
  137. image = Image.open(filebytes)
  138. img = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
  139. return img
  140. def runAllImageSimilaryFun(para1, para2):
  141. # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
  142. # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
  143. # t1,t2 14;19;10; 0.70;0.75
  144. # t1,t3 39 33 18 0.58 0.49
  145. # s1,s2 7 23 11 0.83 0.86 挺相似的图片
  146. # c1,c2 11 29 17 0.30 0.31
  147. if para1.startswith("http"):
  148. # 根据链接下载图片,并转换为opencv格式
  149. img1 = getImageByUrl(para1)
  150. img1 = cv2.cvtColor(np.asarray(img1), cv2.COLOR_RGB2BGR)
  151. img2 = getImageByUrl(para2)
  152. img2 = cv2.cvtColor(np.asarray(img2), cv2.COLOR_RGB2BGR)
  153. else:
  154. # 通过imread方法直接读取物理路径
  155. img1 = cv2.imread(para1)
  156. img2 = cv2.imread(para2)
  157. hash1 = aHash(img1)
  158. hash2 = aHash(img2)
  159. n1 = cmpHash(hash1, hash2)
  160. print('均值哈希算法相似度aHash:', n1)
  161. hash1 = dHash(img1)
  162. hash2 = dHash(img2)
  163. n2 = cmpHash(hash1, hash2)
  164. print('差值哈希算法相似度dHash:', n2)
  165. hash1 = pHash(img1)
  166. hash2 = pHash(img2)
  167. n3 = cmpHash(hash1, hash2)
  168. print('感知哈希算法相似度pHash:', n3)
  169. n4 = classify_hist_with_split(img1, img2)
  170. print('三直方图算法相似度:', n4)
  171. n5 = calculate(img1, img2)
  172. print("单通道的直方图", n5)
  173. print("%d %d %d %.2f %.2f " % (n1, n2, n3, round(n4[0], 2), n5[0]))
  174. print("%.2f %.2f %.2f %.2f %.2f " % (1-float(n1/64), 1 -
  175. float(n2/64), 1-float(n3/64), round(n4[0], 2), n5[0]))
  176. plt.subplot(121)
  177. plt.imshow(Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)))
  178. plt.subplot(122)
  179. plt.imshow(Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)))
  180. plt.show()
  181. if __name__ == "__main__":
  182. p1="https://ww3.sinaimg.cn/bmiddle/007INInDly1g336j2zziwj30su0g848w.jpg"
  183. p2="https://ww2.sinaimg.cn/bmiddle/007INInDly1g336j10d32j30vd0hnam6.jpg"
  184. runAllImageSimilaryFun(p1,p2)

以下为测试了一些图片的相似度值。

五个值分别代表 均值哈希算法相似度、差值哈希算法相似度、感知哈希算法相似度、三直方算法相似度、单通道直方图相似度 

参考文章:

https://www.cnblogs.com/dcb3688/p/4610660.html

https://blog.csdn.net/haofan_/article/details/77097473

https://blog.csdn.net/feimengjuan/article/details/51279629

到此这篇关于python OpenCV计算图片相似度的5种算法的文章就介绍到这了,更多相关OpenCV计算图片相似度内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号