1. 介紹
直方圖算法(Image Histogram Algorithm) 通過統(tǒng)計圖像中各個顏色值的分布情況來提供關(guān)于圖像顏色特征的信息,它可以用來衡量兩張圖片在顏色分布上的相似度,進而可以用來進行圖像相似度的比較,因此,直方圖算法是一種常用的圖片相似度算法,通常是一個一維的數(shù)組(取決于使用通道的數(shù)量),其中每個元素表示特定顏色或強度值的像素數(shù)量。
關(guān)于直方圖算法的一些概念:
直方圖的定義
直方圖是一個二維數(shù)組,通常是一維的(取決于使用通道的數(shù)量),其中每個元素表示特定顏色或強度值的像素數(shù)量。對于彩色圖像,通常有多個通道,比如藍、綠、紅(BGR),因此可能有多個直方圖。
直方圖的統(tǒng)計
- 直方圖的統(tǒng)計是通過掃描圖像的每個像素來收集顏色信息的過程。
- 對于灰度圖像(屬于單通道),每個像素只有一個強度值,因此只有一個通道的直方圖。對于彩色圖像,每個像素有多個通道的值,所以需要分別統(tǒng)計每個通道的直方圖。
- 關(guān)于單通道更詳細的詳細實驗可見下文:討論1#關(guān)于單通道 [0]
直方圖的用途
- 直方圖可以用于多種圖像處理任務(wù),包括圖像增強、顏色校正、圖像分割、物體檢測和圖像相似性比較。
- 通過分析直方圖,可以獲得有關(guān)圖像的顏色分布、對比度、亮度等信息。
直方圖均衡化
- 直方圖均衡化是一種用于增強圖像對比度的技術(shù),它通過重新分配像素的強度值來拉伸或壓縮直方圖,以使其分布更均勻。這可以使圖像中的細節(jié)更加清晰。
直方圖相似度
- 直方圖相似度用于比較兩幅圖像的相似程度。通過計算兩個圖像的直方圖之間的差異,可以量化它們的相似性。
- 常見的直方圖相似度度量包括交叉相關(guān)性(cv2.HISTCMP_INTERSECT)、卡方距離(cv2.HISTCMP_CHISQR)、相關(guān)性(cv2.HISTCMP_CORREL)、巴氏距離(cv2.HISTCMP_BHATTACHARYYA)等。
- 對于直方圖比較方法的詳細實驗可見下文:討論2#直方圖相似度函數(shù)
顏色直方圖
- 對于彩色圖像,顏色直方圖通常分別計算每個通道的直方圖。這可以提供關(guān)于不同顏色通道的顏色分布信息,有助于顏色特征的分析。
- 對于彩色圖像直方圖的詳細實驗可見下文:討論3#彩色圖像直方圖
?文章來源:http://www.zghlxwxcb.cn/news/detail-817666.html
2. 原理
直方圖算法通過統(tǒng)計圖像中不同顏色的像素數(shù)量,并以直方圖的形式呈現(xiàn),進而進行圖像相似度的比較。
關(guān)于 bin
在一個灰度圖像中,像素值的范圍通常從黑色(0)到白色(255)之間變換。如果將圖像的像素值范圍分成 256 個 bin 格子,那么每個 bin 格子則代表一個灰度級別,其灰度值從 0 到 255。直方圖中每個 bin 格子記錄了對應(yīng)灰度級別的像素數(shù)量,通過統(tǒng)計每個 bin 格子中的像素數(shù)量,就可以了解圖像中不同灰度級別的分布情況。
即可看作有你 256 張灰色系色度卡,每一個灰度卡上都統(tǒng)計了灰度圖像中所有該色度的像素數(shù)量,這樣就可以直觀看出灰度圖像的像素在不同色度卡上的分布,然后和其它圖像加以對比分析。
?
3. 魔法
直方圖計算圖片相似度的步驟:
- 圖像預(yù)處理: 將目標圖像轉(zhuǎn)換為灰度圖像或彩色圖像,并根據(jù)需要進行尺寸調(diào)整。
- 計算直方圖: 對于灰度圖像,直方圖表示不同灰度級別的像素數(shù)量。對于彩色圖像,可以分別計算各個通道(如紅、綠、藍)的直方圖對圖像中的每個像素進行像素值的統(tǒng)計,以確定每個像素值的頻率或數(shù)量。這通常包括遍歷圖像的每個像素,并將其像素值歸類到相應(yīng)的像素值區(qū)間(通常是0到255)。最終,得到一個表示像素值頻率的直方圖。
- 直方圖比較: 對于兩張圖片的直方圖,可以使用不同的距離或相似度度量方法來進行比較。常見的度量方法包括相關(guān)性、卡方距離、巴氏距離等。
- 相似度評估: 根據(jù)直方圖比較的結(jié)果,計算出兩張圖片之間的相似度得分。
?
4. 實驗
4.1 魔法
第一步:圖像預(yù)處理
將目標圖像轉(zhuǎn)換為灰度圖像或彩色圖像,并根據(jù)需要進行尺寸調(diào)整。
1)讀取原圖: 首先讀取我們要分析的圖像。
2)圖像灰度化: 如果需要計算灰度直方圖,將彩色圖像轉(zhuǎn)換為灰度圖像。這里我們使用 [0],只考慮圖像灰度級別(亮度)信息,結(jié)果是一維數(shù)組。
第二步:計算直方圖
對于灰度圖像,直方圖表示不同灰度級別的像素數(shù)量。
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
實驗時間:2023-10-27
實例名稱:imgHistogram_v1.0.py
"""
import cv2
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/'
# 文件路徑
img_path = database_dir + 'img_data/car-101.jpg'
font_path = database_dir + 'fonts/chinese_cht.ttf'
# 讀取圖像
img = cv2.imread(img_path)
# 計算直方圖
img_hist = cv2.calcHist([img], [0], None, [256], [0, 256])
print(img_hist)
# 設(shè)置中文字體
font = FontProperties(fname=font_path, size=14)
# 繪制直方圖
plt.plot(img_hist)
plt.title('Histogram(直方圖)', fontproperties=font)
plt.xlabel('Pixel Value(像素值)', fontproperties=font)
plt.ylabel('Frequency(頻率)', fontproperties=font)
# 像素分布可視化
plt.show()
輸出打?。?55個像素亮度
[[ 25.]
[ 13.]
[ 13.]
[ 25.]
[ 39.]
......
[ 798.]
[ 779.]
[ 2034.]]
像素分布可視化效果(直方圖):
對于彩色圖像,可以分別計算各個通道(如紅、綠、藍)的直方圖。對圖像中的每個像素進行像素值的統(tǒng)計,以確定每個像素值的頻率或數(shù)量。這通常包括遍歷圖像的每個像素,并將其像素值歸類到相應(yīng)的像素值區(qū)間(通常是0到255)。最終,得到一個表示像素值頻率的直方圖。
img_hist = cv2.calcHist([img], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
注:彩色直方圖我們下后面詳說。
cv2.calcHist
函數(shù)用于計算圖像的直方圖。以下是它的主要參數(shù)和說明:
-
img
:要計算直方圖的圖像。它以方括號的形式傳遞,允許計算多個圖像的直方圖。例如,[img] 表示計算單個圖像的直方圖,[img1, img2] 表示計算兩個圖像的直方圖。 -
channels
:指定要考慮的通道。這是一個通道索引列表,用于選擇要計算直方圖的通道。在 OpenCV 中,通常情況下,通道 0 對應(yīng)于藍色(B),通道 1 對應(yīng)于綠色(G),通道2 對應(yīng)于紅色(R)。如果要考慮所有通道,可以使用 [0, 1, 2],而對于單通道,只會考慮圖像的灰度信息,而不考慮顏色信息。使用 [0] 即可表示灰色通道,也可以使用 [1] 或 [2] 表示灰色單通道。B、G、R 單通道的對比效果見下文 討論1#關(guān)于單通道 [0] -
mask
:可選參數(shù),用于指定一個掩碼圖像,以便只計算掩碼中非零元素對應(yīng)的像素值。如果不需要掩碼,可以將其設(shè)置為 None。
histSize:指定直方圖的 bin 數(shù)量,即要計算的直方圖的維度。它通常以方括號形式傳遞,例如 [256] 表示每個通道有 256 個 bin(256個色卡)。 -
ranges
:指定像素值的范圍。通常以方括號形式傳遞,例如 [0, 256] 表示單通道像素值的范圍從 0 到 255。對于彩色圖像,通常設(shè)置為 [0, 256, 0, 256, 0, 256],表示三個通道的范圍。
?
討論1:關(guān)于單通道 [0]
- 因為通道 0 對應(yīng)的是藍色(B),所以 [0] ,即使用了藍色(B)單通道的灰度圖像,因為灰度圖像中只有一個通道(單通道)。
- 所以,[1]、[2] 都可以表示單通道的灰度圖像。
- 同理,[0]、[1]、[2] 雖然都可以表示單通道的灰度圖像,但由于使用的通道分別是 0:藍色(Blue)、1:綠色(Green)、2:紅色(Red),所以,灰度圖像的亮度略有區(qū)別(會影響灰度像素亮度分布)。
效果如下(分別是BGR、RGB、B、G、R):
示圖代碼:
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
實驗時間:2023-10-27
實例名稱:imgHistogram_v1.2_rgb_split.py
"""
import cv2
import matplotlib.pyplot as plt
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/'
# 文件路徑
img_path = database_dir + 'img_data/car-101.jpg'
# 讀取圖像:默認使用BGR加載圖像
img = cv2.imread(img_path)
# 分離通道:將彩色圖像分離成各個通道(R、G、B),然后分別繪制它們的直方圖
img_b, img_g, img_r = cv2.split(img)
# 繪制子圖
plt.figure(figsize=(15, 5))
# 151:表示子圖位于一個 1x5 的網(wǎng)格中的第一個位置。如比第2張圖的位置152,即一行五列第2張圖
# 顯示各通道的圖像
plt.subplot(151)
plt.imshow(img)
plt.title('BGR (Default)')
plt.subplot(152)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('BGR TO RGB')
plt.subplot(153)
plt.imshow(cv2.cvtColor(img_b, cv2.COLOR_BGR2RGB))
plt.title('Blue Channel')
plt.subplot(154)
plt.imshow(cv2.cvtColor(img_g, cv2.COLOR_BGR2RGB))
plt.title('Green Channel')
plt.subplot(155)
plt.imshow(cv2.cvtColor(img_r, cv2.COLOR_BGR2RGB))
plt.title('Red Channel')
plt.show()
代碼對目標圖像進行 R、G、B 通道分離,讀取像素,然后分別繪制它們的直方圖。
下圖中,讀取目標圖像的方式分別是:BGR、RGB、B、G、R,繪畫出來的直方圖灰度像素分布效果如下:
可以看到,BGR 與 Blue(第1張與第3張)、RGB 與 Red(第2張與第5張)的灰度像素分布趨勢一致。
示圖代碼:
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
實驗時間:2023-10-27
實例名稱:imgHistogram_v1.3_rgb_split.py
"""
import cv2
import matplotlib.pyplot as plt
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/'
# 文件路徑
img_path = database_dir + 'img_data/car-101.jpg'
# 讀取圖像:默認使用BGR加載圖像
img = cv2.imread(img_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 分離通道:將彩色圖像分離成各個通道(R、G、B),然后分別繪制它們的直方圖
img_b, img_g, img_r = cv2.split(img)
# 計算各通道的直方圖
hist_bgr = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_rgb = cv2.calcHist([img_rgb], [0], None, [256], [0, 256])
hist_b = cv2.calcHist([img_b], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([img_g], [0], None, [256], [0, 256])
hist_r = cv2.calcHist([img_r], [0], None, [256], [0, 256])
# 繪制線圖子圖展示各通道的直方圖灰度趨勢
plt.subplot(151)
plt.plot(hist_bgr, color='orange')
plt.title('BGR Histogram')
plt.subplot(152)
plt.plot(hist_rgb, color='purple')
plt.title('RGB Histogram')
plt.subplot(153)
plt.plot(hist_b, color='b')
plt.title('Blue Histogram')
plt.subplot(154)
plt.plot(hist_g, color='g')
plt.title('Green Histogram')
plt.subplot(155)
plt.plot(hist_r, color='r')
plt.title('Red Histogram')
plt.show()
如果不好分辨,我們再加上 [0]、[1]、[2] 單通道合成一張直方圖:
可以清楚看到,合成后的直方圖,只剩下 B、G、R 三通道的灰度像素分布趨勢。
示圖代碼:
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
實驗時間:2023-10-27
實例名稱:imgHistogram_v1.4_rgb_one.py
"""
import cv2
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/'
# 文件路徑
img_path = database_dir + 'img_data/car-101.jpg'
# 字體路徑
font_path = database_dir + 'fonts/chinese_cht.ttf'
# 讀取圖像
img = cv2.imread(img_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 分離通道:將彩色圖像分離成各個通道(R、G、B),然后分別繪制它們的直方圖
img_b, img_g, img_r = cv2.split(img)
# 計算各通道的直方圖(依次為 BGR、RGB、0:藍色通道,1:綠色通道,2:紅色通道)
hist_bgr = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_rgb = cv2.calcHist([img_rgb], [0], None, [256], [0, 256])
hist_b = cv2.calcHist([img_b], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([img_g], [0], None, [256], [0, 256])
hist_r = cv2.calcHist([img_r], [0], None, [256], [0, 256])
hist_0 = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_1 = cv2.calcHist([img], [1], None, [256], [0, 256])
hist_2 = cv2.calcHist([img], [2], None, [256], [0, 256])
# 繪制多線線圖,展示各通道的直方圖灰度趨勢
plt.plot(hist_bgr, color='orange', label='BGR')
plt.plot(hist_rgb, color='purple', label='RGB')
plt.plot(hist_b, color='blue', label='Channel Blue')
plt.plot(hist_0, color='blue', label='Channel 0')
plt.plot(hist_g, color='green', label='Channel Green')
plt.plot(hist_1, color='green', label='Channel 1')
plt.plot(hist_r, color='red', label='Channel Red')
plt.plot(hist_2, color='red', label='Channel 2')
# 設(shè)置中文字體
font = FontProperties(fname=font_path, size=14)
plt.title('Histogram(直方圖)', fontproperties=font)
plt.xlabel('Pixel Value(像素值)', fontproperties=font)
plt.ylabel('Frequency(頻率)', fontproperties=font)
# 添加圖例
plt.legend()
# 顯示圖像
plt.show()
計算各通道的直方圖(依次為 BGR,RGB,0:藍色通道,1:綠色通道,2:紅色通道):
-
[0]: 使用
cv2.imread(img_path)
的 img、cv2.split(img) 中的 img_b、[0] 獲得到的灰度像素分布趨勢等同 -
[1]: 使用
cv2.split(img)
中的 img_g、[1] 獲得到的灰度像素分布趨勢等同 -
[2]: 使用
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
的 img_rgb、cv2.split(img) 中的 img_r、[2] 獲得到的灰度像素分布趨勢等同
所以,[0]、[1]、[2] 都可以表示單通道的灰度圖像,但由于使用的通道分別是 藍色(Blue)、綠色(Green)、紅色(Red),所以,灰度圖像的亮度略有區(qū)別(會影響灰度像素亮度分布),體現(xiàn)在直方圖上,則表現(xiàn)為灰度像素的分布趨勢略有差異。
第三步:直方圖比較
對于兩張圖像的直方圖比較,可以使用不同的距離或相似度度量方法來進行比較。常見的度量方法包括相關(guān)性、卡方距離、巴氏距離等。
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0
實驗時間:2023-10-27
實例名稱:imgHistogram_v2.1_graySimilarity.py
"""
import cv2
def get_calcHist(img1_path, img2_path):
# 讀取圖像
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
# 計算圖像灰度單通道直方圖
img1_hist = cv2.calcHist([img1], [0], None, [256], [0, 256])
img2_hist = cv2.calcHist([img2], [0], None, [256], [0, 256])
# 計算直方圖相似度
# cv2.HISTCMP_CORREL: 相關(guān)性比較,值越接近 1 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CORREL)
print("圖像2與圖像1的相似度(HISTCMP_CORREL/相關(guān)性):", similarity)
# 或者
# 計算直方圖的重合度
degree = 0
for i in range(len(img1_hist)):
if img1_hist[i] != img2_hist[i]:
degree = degree + (1 - abs(img1_hist[i] - img2_hist[i]) / max(img1_hist[i], img2_hist[i]))
else:
degree = degree + 1
degree = degree / len(img1_hist)
print("圖像2與圖像1的重合度:", degree)
return similarity
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/img_data/'
# 文件路徑
img1_path = database_dir + 'car-101.jpg'
img2_path = database_dir + 'car-102.jpg'
print("圖像1路徑:", img1_path)
print("圖像2路徑:", img2_path)
get_calcHist(img1_path, img2_path)
輸出打?。?/p>
圖像1路徑: ../../P0_Doc/img_data/car-101.jpg
圖像2路徑: ../../P0_Doc/img_data/car-102.jpg
圖像2與圖像1的相似度(HISTCMP_CORREL/相關(guān)性): 1.0
圖像2與圖像1的重合度: 1.0
說明:圖像2是圖像1的180度倒置圖。
cv2.compareHist
是 OpenCV
中用于比較直方圖相似度的函數(shù)。用于計算兩個直方圖之間的相關(guān)性(correlation)。img1_hist 和 img2_hist 是兩個直方圖,它們分別代表兩幅圖像的顏色分布。
直方圖的比較方法:
- cv2.HISTCMP_CORREL(相關(guān)性): 計算兩個直方圖之間的相關(guān)性。相關(guān)性的值越接近1,表示兩幅圖像的顏色分布越相似,值越接近-1表示顏色分布越不相似,值接近0表示中等相似度。但不太適用于顏色直方圖比較。
- cv2.HISTCMP_CHISQR(卡方距離): 計算卡方距離,用于比較兩個直方圖之間的差異。值越接近 0 表示顏色分布越相似。
- cv2.HISTCMP_INTERSECT(交集性): 計算兩個直方圖的交集,用于度量它們的相似度。該值越大表示相似度越高。
- cv2.HISTCMP_BHATTACHARYYA(巴氏距離): 計算兩個直方圖之間的巴氏距離。值越接近 0 表示顏色分布越相似。
?
討論2:直方圖相似度函數(shù)
使用 cv2.compareHist()
,不同的直方圖比較方法,對比結(jié)果略有差異。這里,我們使用 [0] 作為灰度通道進行測試實驗。
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0
實驗時間:2023-10-27
實例名稱:imgHistogram_v2.3_compareHist.py
"""
import cv2
import os
def get_degreeHist(img1_hist, img2_hist):
# 計算直方圖的重合度
degree = 0
for i in range(len(img1_hist)):
if img1_hist[i] != img2_hist[i]:
degree = degree + (1 - abs(img1_hist[i] - img2_hist[i]) / max(img1_hist[i], img2_hist[i]))
else:
degree = degree + 1
degree = degree / len(img1_hist)
return degree
def all_compareHist(img1_path, img2_path):
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
img1_hist = cv2.calcHist([img1], [0], None, [256], [0, 256])
img2_hist = cv2.calcHist([img2], [0], None, [256], [0, 256])
similarity = get_degreeHist(img1_hist, img2_hist)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度:", similarity)
# 計算直方圖相似度
# cv2.HISTCMP_BHATTACHARYYA: 巴氏距離比較,值越接近 0 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_BHATTACHARYYA)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_BHATTACHARYYA/巴氏距離):", similarity)
# cv2.HISTCMP_CHISQR: 卡方比較,值越接近 0 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CHISQR)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CHISQR/卡方比較):", similarity)
# cv2.HISTCMP_CORREL: 相關(guān)性比較,值越接近 1 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CORREL)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CORREL/相關(guān)性):", similarity)
# cv2.HISTCMP_INTERSECT: 直方圖交集比較,值越大表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_INTERSECT)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_INTERSECT/交集比較):", similarity)
return similarity
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/img_data/'
# 文件路徑
img1_path = database_dir + 'car-101.jpg'
img2_path = database_dir + 'car-102.jpg'
img2_path = database_dir + 'car-103.jpg'
all_compareHist(img1_path, img2_path)
輸出打?。?/p>
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度: 1.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距離): 0.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比較): 0.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CORREL/相關(guān)性): 1.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比較): 1232154.0
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度: [0.6923658]
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距離): 0.2135487778250319
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比較): 11867327.715396598
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CORREL/相關(guān)性): 0.4266303485505497
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比較): 972986.0
?
討論3:彩色圖像直方圖
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0
實驗時間:2023-10-27
實例名稱:imgHistogram_v2.4_rgb_compareHist.py
"""
import cv2
import os
def bgr_compareHist(img1_path, img2_path):
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)
img1_hist = cv2.calcHist([img1], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
img2_hist = cv2.calcHist([img2], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])
# 計算直方圖相似度
# cv2.HISTCMP_BHATTACHARYYA: 巴氏距離比較,值越接近 0 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_BHATTACHARYYA)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_BHATTACHARYYA/巴氏距離):", similarity)
# cv2.HISTCMP_CHISQR: 卡方比較,值越接近 0 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CHISQR)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CHISQR/卡方比較):", similarity)
# cv2.HISTCMP_CORREL: 相關(guān)性比較,值越接近 1 表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CORREL)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CORREL/相關(guān)性):", similarity)
# cv2.HISTCMP_INTERSECT: 直方圖交集比較,值越大表示顏色分布越相似
similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_INTERSECT)
print(f"圖像 {os.path.basename(img2_path)} 與目標圖像 {os.path.basename(img1_path)} 的相似度(HISTCMP_INTERSECT/交集比較):", similarity)
return similarity
# 目標圖像素材庫文件夾路徑
database_dir = '../../P0_Doc/img_data/'
# 文件路徑
img1_path = database_dir + 'car-101.jpg'
img2_path = database_dir + 'car-102.jpg'
img2_path = database_dir + 'car-103.jpg'
bgr_compareHist(img1_path, img2_path)
輸出打?。?/p>
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距離): 0.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比較): 0.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CORREL/相關(guān)性): 1.0
圖像 car-102.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比較): 1232154.0
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距離): 0.25780152883475765
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比較): 981578.8189641015
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_CORREL/相關(guān)性): 0.8933747646918704
圖像 car-103.jpg 與目標圖像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比較): 911172.0
對比 討論2:直方圖相似度函數(shù) 的輸出結(jié)果,可以看到,相同測試圖像,彩色直方圖的相似度 與 灰度直方圖的相似度 有一點差異,原因就是,通過單通道的灰度直方圖,可以捕捉到圖像的整體亮度和對比度信息,而不受顏色的影響。在相似圖片查找中,通常更關(guān)注圖像的結(jié)構(gòu)和紋理,因此灰度信息更具代表性。
第四步:相似度評估
根據(jù)直方圖比較的結(jié)果(似度得分),進行目標圖像相似度評估。
案例場景:圖像測試素材庫中,查找所有圖像,找出與目標圖像相似值小于等于0.5的圖像。
......
for similarity in similarities:
if (similarity[1] <= 0.5):
print(f"圖像名稱:{similarity[0]},與目標圖像 {os.path.basename(img_org_path)} 的近似值:{similarity[1]}")
?
4.2 測試
實驗場景
通過 opencv,使用直方圖算法查找目標圖像素材庫中所有符合期望值的相似圖像。
實驗素材
這里,我準備了45張素材圖像,其中14張圖像為水果,其余為不同類型的汽車,但形態(tài)不一。
實驗代碼
"""
以圖搜圖:圖像直方圖(Image Histogram)查找相似圖像的原理與實現(xiàn)
測試環(huán)境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
實驗場景:圖像測試素材庫中,查找所有圖像,找出與目標圖像相似值小于等于0.7的圖像
實驗時間:2023-10-27
實例名稱:imgHistogram_v3.2_gray_show.py
"""
import os
import time
import cv2
import matplotlib.pyplot as plt
def get_calcHist(org_img_hist, img_path):
# 讀取圖像:通過OpenCV的imread加載RGB圖像
img = cv2.imread(img_path)
# img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2GRAY)
img_hist = cv2.calcHist([img], [0], None, [256], [0, 256])
# 計算直方圖相似度
# cv2.HISTCMP_CORREL: 相關(guān)性比較,值越接近 1 表示顏色分布越相似
# cv2.HISTCMP_CHISQR: 卡方比較,值越接近 0 表示顏色分布越相似
# cv2.HISTCMP_BHATTACHARYYA: 巴氏距離比較,值越接近 0 表示顏色分布越相似
# cv2.HISTCMP_INTERSECT: 直方圖交集比較,值越大表示顏色分布越相似
similarity = cv2.compareHist(org_img_hist, img_hist, cv2.HISTCMP_BHATTACHARYYA)
return similarity
def show_similar_images(similar_images, images_per_column=3):
# 計算總共的圖片數(shù)量
num_images = len(similar_images)
# 計算所需的行數(shù)
num_rows = (num_images + images_per_column - 1) // images_per_column
# 創(chuàng)建一個子圖,每行顯示 images_per_column 張圖片
fig, axes = plt.subplots(num_rows, images_per_column, figsize=(12, 15), squeeze=False)
# 遍歷每一行
for row in range(num_rows):
# 遍歷每一列
for col in range(images_per_column):
# 計算當前圖片在列表中的索引
index = row * images_per_column + col
# 檢查索引是否越界
if index < num_images:
# 獲取當前相似圖片的路徑和相似度
image_path = similar_images[index][0]
similarity = similar_images[index][1]
# 讀取圖片并轉(zhuǎn)換顏色通道
image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)
# 在子圖中顯示圖片
axes[row, col].imshow(image)
# 設(shè)置子圖標題,包括圖片路徑和相似度
axes[row, col].set_title(f"Similar Image: {os.path.basename(image_path)} \n Similar Score: {similarity:.4f}")
# 關(guān)閉坐標軸
axes[row, col].axis('off')
# 顯示整個圖
plt.show()
# ------------------------------------------------ 測試 ------------------------------------------------
if __name__ == '__main__':
time_start = time.time()
# 指定測試圖像庫目錄
img_dir = '../../P0_Doc/img_data/'
# 指定測試圖像文件擴展名
img_suffix = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']
# 獲取當前執(zhí)行腳本所在目錄
script_dir = os.path.dirname(__file__)
# 獲取目標測試圖像的全路徑
img_org_path = os.path.join(script_dir, img_dir, 'apple-101.jpg')
# 加載要查詢的圖像
query_image = cv2.imread(img_org_path)
# query_image = cv2.cvtColor(cv2.imread(img_org_path), cv2.COLOR_BGR2GRAY)
# 計算查詢圖像的直方圖:灰度直方圖算法
img_org_hist = cv2.calcHist([query_image], [0], None, [256], [0, 256])
print(f"目標圖像:{os.path.relpath(img_org_path)}")
# 獲取測試圖像庫中所有文件
all_files = os.listdir(os.path.join(script_dir, img_dir))
# 篩選出指定后綴的圖像文件
img_files = [file for file in all_files if any(file.endswith(suffix) for suffix in img_suffix)]
# 存儲相似度值和對應(yīng)的圖像路徑
img_search_results = []
# 遍歷測試圖像庫中的每張圖像
for img_file in img_files:
# 獲取相似圖像文件路徑
img_path = os.path.join(script_dir, img_dir, img_file)
# 獲取相似圖像可識別哈希值(圖像指紋)
similarity = get_calcHist(img_org_hist, img_path)
# print(f"圖像名稱:{img_path},與目標圖像 {os.path.basename(img_org_path)} 的近似值:{similarity}")
if (similarity <= 0.7):
# 存儲相似度值和對應(yīng)的圖像路徑
img_search_results.append((os.path.relpath(img_path), similarity))
# 按相似度升序排序
img_search_results.sort(key=lambda item: item[1])
for img_similarity in img_search_results:
print(f"圖像名稱:{img_similarity[0]},與目標圖像 {os.path.basename(img_org_path)} 的相似值:{img_similarity[1]}")
time_end = time.time()
print(f"耗時:{time_end - time_start}")
# 顯示目標相似圖像
show_similar_images(img_search_results)
多圖相似查找效果顯示,實驗代碼使用的是巴氏距離比較,值越接近 0 表示顏色分布越相似:
輸出打印:
目標圖像:..\..\P0_Doc\img_data\apple-101.jpg
圖像名稱:..\..\P0_Doc\img_data\apple-101.jpg,與目標圖像 apple-101.jpg 的相似值:0.0
圖像名稱:..\..\P0_Doc\img_data\apple-104.jpg,與目標圖像 apple-101.jpg 的相似值:0.0
圖像名稱:..\..\P0_Doc\img_data\car-109.jpg,與目標圖像 apple-101.jpg 的相似值:0.6158102157213413
圖像名稱:..\..\P0_Doc\img_data\car-103.jpg,與目標圖像 apple-101.jpg 的相似值:0.662176197294615
圖像名稱:..\..\P0_Doc\img_data\car-101.jpg,與目標圖像 apple-101.jpg 的相似值:0.6813075243521007
圖像名稱:..\..\P0_Doc\img_data\car-102.jpg,與目標圖像 apple-101.jpg 的相似值:0.6813075243521007
圖像名稱:..\..\P0_Doc\img_data\Q3-09.jpg,與目標圖像 apple-101.jpg 的相似值:0.6844184531149912
圖像名稱:..\..\P0_Doc\img_data\car-108.jpg,與目標圖像 apple-101.jpg 的相似值:0.6861940450661771
圖像名稱:..\..\P0_Doc\img_data\X3-09.jpg,與目標圖像 apple-101.jpg 的相似值:0.692340714053627
圖像名稱:..\..\P0_Doc\img_data\apple-114.jpg,與目標圖像 apple-101.jpg 的相似值:0.6932278615425139
圖像名稱:..\..\P0_Doc\img_data\apple-112.jpg,與目標圖像 apple-101.jpg 的相似值:0.6959175186621991
圖像名稱:..\..\P0_Doc\img_data\pear-201.jpg,與目標圖像 apple-101.jpg 的相似值:0.6997766670329476
耗時:1.0362038612365723
?
5. 總結(jié)
總體來說,直方圖算法屬于一種傳統(tǒng)外觀相似算法,適用于一些簡單的圖像相似性比較問題,但直方圖反應(yīng)的是圖像灰度值得概率分布,并沒有圖像的空間位置信息在里面,因此,可能會出現(xiàn)誤判。比如紋理結(jié)構(gòu)相同,但明暗不同的圖像,應(yīng)該相似度很高,但實際結(jié)果是相似度很低,而紋理結(jié)構(gòu)不同,但明暗相近的圖像,相似度卻很高。
優(yōu)點
- 簡單直觀: 直方圖是一種簡單直觀的圖像表達方式,易于理解和實現(xiàn)。
- 快速計算: 直方圖的計算相對快速,特別是對于小尺寸的圖像。
- 顏色不變性: 直方圖在某種程度上對顏色的變化具有不變性,因此可以在一定程度上應(yīng)對圖像的輕微變形。
- 對光照變化有一定的魯棒性: 直方圖可以在一定程度上處理圖像的光照變化。
缺點
- 不考慮空間信息: 直方圖方法忽略了圖像的空間信息,對于圖像的排列、結(jié)構(gòu)等方面的變化較為敏感。
- 受噪聲影響: 如果圖像受到噪聲的影響,直方圖會受到一定程度的干擾。
- 灰度信息有限: 灰度直方圖只考慮了像素的灰度信息,對于顏色信息較為有限。
- 無法處理形狀變化: 直方圖方法難以處理圖像中物體的形狀變化。
?
6. 系列書簽
OpenCV書簽 #均值哈希算法的原理與相似圖片搜索實驗
OpenCV書簽 #感知哈希算法的原理與相似圖片搜索實驗
OpenCV書簽 #差值哈希算法的原理與相似圖片搜索實驗
OpenCV書簽 #直方圖算法的原理與相似圖片搜索實驗文章來源地址http://www.zghlxwxcb.cn/news/detail-817666.html
到了這里,關(guān)于OpenCV書簽 #直方圖算法的原理與相似圖片搜索實驗的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!