使用OpenCV,Python进行图像哈希(差分哈希 dHash)处理
使用OpenCV,Phthon進行圖像哈希處理的一個重要應用是去除重復的圖像;
當你有多個相冊的圖片,進行合并時,so boring,有一些圖片是重復的,肉眼來看太難刪除了。
圖像哈希可以幫助你完美的解決這個問題,找到完全相同的圖片,只保留一張,刪除其他的。
圖像哈希(也稱為感知哈希)是基于圖像的視覺內容構造哈希值的過程。我們將圖像哈希用于CBIR,近重復檢測和反向圖像搜索引擎。
1. 圖像哈希的原理
(1)檢查圖像內容
 (2)構造一個哈希值,該哈希值根據圖像的內容唯一地標識輸入圖像
圖像哈希的最重要的一個應用是:反向圖像搜索引擎。
2. 為什么md5,sha-1不起作用?
將一張圖片有250250縮放到500500,圖像沒有變化,但計算出來的md5值變了。原因在于:密碼哈希算法的本質:更改文件中的單個位將導致不同的哈希。
在圖像哈希/感知哈希情況下,我們實際上希望相似的圖像也具有相似的哈希值。 這也是根本原因。
解決辦法: 使用差分哈希(Difference Hash 簡稱dHash);
3. 差異哈希
(1)轉為灰度圖(可以更快運算,匹配相同但色彩空間稍有改變的圖像);
 (2)忽略寬高比的縮放圖像至9 * 8;
 (3)9 * 8計算相鄰行之間相鄰像素的差值,得到8 * 8;
 (4)計算哈希值(x>p(x+1) =1 : 0);
4. 差異哈希的好處
(1)如果輸入圖像只是寬高比發生變化,圖像哈希不會改變;
 (2)只是調整亮度或對比度將不會更改哈希值,或者只會對其稍有更改,以確保哈希值緊密地靠在一起;
 (3)差異哈希速度非常快;
5. 對比差異哈希的值
- 使用漢明距離對比倆個哈希的值;
- 漢明距離為零的兩個哈希值意味著兩個哈希值是相同的(因為沒有不同的位),并且兩個圖像是相同的/在感知上也相似。
6. 應用差異哈希解決實際問題
問題:整理照片常遇到的問題,文件夾haystack,文件夾needle中有許多子目錄,包含很多照片。
 目標:判斷needle中有哪些目錄的哪些照片沒有 在haystack;
# python hash_and_search.py --haystack haystack --needles needles# 導入必要的包
from imutils import paths
import argparse
import time
import sys
import cv2
import os# 差分Hash算法(相鄰列的相鄰像素相減  由9*8 相減得到 8*8 64位哈希值)
def dhash(image, hashSize=8):# 縮放圖像,多增加一列,以后續進行水平梯度計算resized = cv2.resize(image, (hashSize + 1, hashSize))# 水平方向,計算相鄰的行之間的差值diff = resized[:, 1:] > resized[:, :-1]# 轉換不同圖像為hashreturn sum([2 ** i for (i, v) in enumerate(diff.flatten()) if v])# 構建命令行參數
# --haystack 大文件夾
# --needle 小文件夾
# 目標: 檢查needle中的每個圖像是否在haystack中,已存在的刪除,不存在的保留
ap = argparse.ArgumentParser()
ap.add_argument("-a", "--haystack", required=True,help="dataset of images to search through (i.e., the haytack)")
ap.add_argument("-n", "--needles", required=True,help="set of images we are searching for (i.e., needles)")
args = vars(ap.parse_args())# 獲取needle、haystack文件夾總的所有圖片文件
print("[INFO] computing hashes for haystack...")
haystackPaths = list(paths.list_images(args["haystack"]))
needlePaths = list(paths.list_images(args["needles"]))# 移除文件中的\\ 或者空格
# Windows操作系統使用\分隔路徑
# 在Unix系統使用/時分隔路徑
if sys.platform != "win32":haystackPaths = [p.replace("\\", "") for p in haystackPaths]needlePaths = [p.replace("\\", "") for p in needlePaths]# 獲取needle的子目錄 初始化字典(映射文件名和hash值)
BASE_PATHS = set([p.split(os.path.sep)[-2] for p in needlePaths])
haystack = {}  # 文件名與hash值的映射字典
start = time.time()# 循環遍歷haystack路徑
for p in haystackPaths:# 從磁盤加載圖片image = cv2.imread(p)# 如果image為None,跳過...if image is None:continue# 轉換圖像為灰度圖,并計算hash值image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)imageHash = dhash(image)# 更新haystack字典l = haystack.get(imageHash, [])l.append(p)haystack[imageHash] = l# 顯示haystack字典更新的耗時,開始甲酸needle圖像的hash值
print("[INFO] processed {} images in {:.2f} seconds".format(len(haystack), time.time() - start))
print("[INFO] computing hashes for needles...")# 遍歷needle路徑的圖像
for p in needlePaths:# 加載圖片image = cv2.imread(p)# 圖像為None,跳過...if image is None:continue# 轉換為灰度圖,計算hash值image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)imageHash = dhash(image)# 獲取所有匹配該hash值的圖像matchedPaths = haystack.get(imageHash, [])# 遍歷所有匹配的圖像路徑for matchedPath in matchedPaths:# 提取圖片的子文件夾路徑b = p.split(os.path.sep)[-2]# 如果needle路徑的基本路徑包含子目錄,if b in BASE_PATHS:BASE_PATHS.remove(b)# 顯示路徑以檢查
print("[INFO] check the following directories...")
# 循環遍歷子目錄并打印照片
for b in BASE_PATHS:print("[INFO] {}".format(b))
總結
以上是生活随笔為你收集整理的使用OpenCV,Python进行图像哈希(差分哈希 dHash)处理的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Java8 新的 try-with-re
- 下一篇: Python装饰器的神奇功能:自动打印每
