因爲最近涉及到匹配類似圖片的問題,因此在此記錄下解決辦法:差別值哈希算法 + 顏色直方圖
環境要求:Python cv2庫 math庫html
檢索類似圖片,第一個想到的就是差別值哈希算法
。這個算法的步驟是:算法
8 * 8
的尺寸大小,共64個像素的圖片。可是因爲64個像素對於我來講,損失的細節太多因此我選擇了縮放到 33 * 32
的尺寸大小256 * 256 * 256
種顏色。而且做爲一個像素相似於這樣的數值:[253 255 255] 是不利於簡單比較的,肉眼看着相似的顏色,可是它的三個顏色分佈可能相差不少。因此將它灰度化,用 256 個不一樣的灰色表示現有的圖片。因爲如今用一種灰色表示三種顏色,原來每一個像素是一個 list 如今就降維成一個數值,數值的大小仍是比較容易比較的。import cv2 # 差別值哈希算法 def dhash(image): resize_height, resized_width = 32, 33 # 縮放到(resized_width, resize_height)尺寸的大小 resized_img = cv2.resize(image, (resized_width, resize_height)) # 圖片灰度化 grey_resized_img = cv2.cvtColor(resized_img, cv2.COLOR_RGB2GRAY) # 差別值計算 hash_list = [] for row in range(resize_height): for col in range(resized_width - 1): # 每行前一個顏色強度大於後一個,值爲1,不然值爲0 if grey_resized_img[row, col] > grey_resized_img[row, col + 1]: hash_list.append('1') else: hash_list.append('0') return '' . join(hash_list) # 比較漢明距離 def hamming_distance(dhash1, dhash2): return bin(int(dhash1, base = 2) ^ int(dhash2, base = 2)).count('1') # 讀取圖片內容 img1 = cv2.imread(img1_path) # 讀取圖片內容 img2 = cv2.imread(img2_path) if hamming_distance(dhash(img1), dhash(img2)) <= 5: print('類似圖片')
因爲差別值哈希失去了太多的細節,適合比較原圖或者縮略圖。因此我再加上顏色直方圖的比較計算圖片間的接近程度,用以排除部分像素的微小差別。數組
8 * 8
的尺寸大小,共64個像素的圖片。可是因爲64個像素對於我來講,損失的細節太多因此我選擇了縮放到 32 * 32
的尺寸大小8 * 8
,8
,1
做爲數組的 key,用以統計每一個顏色的像素出現次數,而且不會出現不一樣顏色統計到了同一個 key 值下的目的。
import cv2 from math import sqrt # 顏色映射 def bgr_mapping(img_val): # 將bgr顏色分紅8個區間作映射 if img_val >= 0 and img_val <= 31: return 0 if img_val >= 32 and img_val <= 63: return 1 if img_val >= 64 and img_val <= 95: return 2 if img_val >= 96 and img_val <= 127: return 3 if img_val >= 128 and img_val <= 159: return 4 if img_val >= 160 and img_val <= 191: return 5 if img_val >= 192 and img_val <= 223: return 6 if img_val >= 224: return 7 # 顏色直方圖的數值計算 def calc_bgr_hist(image): if not image.size: return False hist = {} # 縮放尺寸減少計算量 image = cv2.resize(image, (32, 32)) for bgr_list in image: for bgr in bgr_list: # 顏色按照順序映射 maped_b = bgr_mapping(bgr[0]) maped_g = bgr_mapping(bgr[1]) maped_r = bgr_mapping(bgr[2]) # 計算像素值 index = maped_b * 8 * 8 + maped_g * 8 + maped_r hist[index] = hist.get(index, 0) + 1 return hist # 計算兩張圖片的類似度 def compare_similar_hist(h1, h2): if not h1 or not h2: return False sum1, sum2, sum_mixd = 0, 0, 0 # 像素值key的最大數不超過512,直接循環到512,遍歷取出每一個像素值 for i in range(512): # 計算出現相同像素值次數的平方和 sum1 = sum1 + (h1.get(i, 0) * h1.get(i, 0)) sum2 = sum2 + (h2.get(i, 0) * h2.get(i, 0)) # 計算兩個圖片次數乘積的和 sum_mixd = sum_mixd + (h1.get(i, 0) * h2.get(i, 0)) # 按照餘弦類似性定理計算類似度 return sum_mixd / (sqrt(sum1) * sqrt(sum2)) # 讀取圖片內容 img1 = cv2.imread(img1_path) # 讀取圖片內容 img2 = cv2.imread(img2_path) if compare_similar_hist(calc_bgr_hist(img1), calc_bgr_hist(img2)) < 0.9999: print('類似圖片')
總的來講:差別值哈希算法 + 顏色直方圖 解決了個人類似圖片匹配問題。app