圖像直方圖
那么,圖像直方圖到底是什么?
圖片
圖像的構(gòu)成是由像素點(diǎn)構(gòu)成的,每個(gè)像素點(diǎn)的值代表著該點(diǎn)的顏色(灰度圖或者彩色圖)。所謂直方圖就是對(duì)圖像的中的這些像素點(diǎn)的值進(jìn)行統(tǒng)計(jì),得到一個(gè)統(tǒng)一的整體的灰度概念。直方圖表示圖像中顏色的分布。可以將其可視化為圖表(或曲線圖),以直觀地了解強(qiáng)度(像素值)分布。直方圖的好處就在于可以清晰了解圖像的整體灰度分布,這對(duì)于計(jì)算機(jī)視覺處理圖片有關(guān)重要。
一般情況下直方圖都是灰度圖像,直方圖x軸是灰度值(一般0~255),y軸就是圖像中每一個(gè)灰度級(jí)對(duì)應(yīng)的像素點(diǎn)的個(gè)數(shù)。
灰度空間圖片直方圖
如何獲取圖片直方圖
圖片直方圖的獲取,opencv已經(jīng)幫我們集成了函數(shù),當(dāng)然numpy也同樣可以 獲取
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
#numpy方法讀取-np.histogram()
#hist_np,bins = np.histogram(img.ravel(),256,[0,256])
#numpy的另一種方法讀取-np.bincount()
#hist_np1 = np.bincount(img.ravel(),minlength=256)
cv2.imshow("gray", img)
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(hist)
plt.show()
代碼截圖
cv2.calcHist(),該函數(shù)傳遞5個(gè)參數(shù):
- image輸入圖像,此參數(shù)是一個(gè)list 對(duì)象
- channels::傳入圖像的通道,如果是灰度圖像,只有一個(gè)通道,值為0,如果是彩色圖像(B G R),那么值為0,1,2,中選擇一個(gè),對(duì)應(yīng)著BGR各個(gè)通道。同樣為list 對(duì)象。
- mask:掩膜圖像。如果統(tǒng)計(jì)整幅圖,那么為none。主要是如果要統(tǒng)計(jì)部分圖的直方圖,就得構(gòu)造相應(yīng)的掩膜圖像來(lái)計(jì)算。
- histSize:灰度級(jí)的個(gè)數(shù),比如[256],或者三個(gè)通道的[32,32,32]
- ranges:像素值的范圍,通常[0,256],通常,這是[0, 256]針對(duì)每個(gè)通道的,但是如果您使用的顏色空間不是RGB(例如HSV),則范圍可能會(huì)有所不同。
以上展示了圖片在灰度值中的顏色直方圖,當(dāng)然,我們的圖片是R G B的三色圖片,我們也可以分別展示圖片在R G B 空間內(nèi)的圖片直方圖。
彩色空間圖片直方圖
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
cv2.imshow("image", image)
chans = cv2.split(image)
colors = ("b", "g", "r")
plt.figure()
plt.title("'Flattened' Color Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
features = []
for (chan, color) in zip(chans, colors):
hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
features.extend(hist)
plt.plot(hist, color = color)
plt.xlim([0, 256])
plt.show()
代碼截圖
chans = cv2.split(image)函數(shù)把圖片分別分割成 R G B 三色空間
分別把三色空間的 R G B 空間傳入cv2.calcHist([chan], [0], None, [256], [0, 256])函數(shù)來(lái)生成不同空間內(nèi)的顏色圖片直方圖,最后把圖片顯示出來(lái)
圖片mask參數(shù)
cv2.calcHist函數(shù)可以接受mask 來(lái)進(jìn)行圖片直方圖的顯示,默認(rèn)計(jì)算圖片的所有區(qū)域,但是有時(shí)候我們不需要圖片的所有區(qū)域,我們可以使用mask來(lái)扣自己需要的圖片區(qū)域,進(jìn)而可以進(jìn)行自己想要圖片區(qū)域的直方圖
mask 圖片直方圖
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
mask = np.zeros(img.shape[:2],np.uint8)
mask[100:500,100:500] = 255
mask_img = cv2.bitwise_and(img,img,mask=mask)
hist = cv2.calcHist([img], [0], mask, [256], [0, 256])
cv2.imshow("mask", mask_img)
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")
plt.plot(hist)
plt.show()
代碼截圖
首先我們獲取圖片的尺寸img.shape[:2],有了圖片的尺寸
我們可以標(biāo)注自己需要的圖片區(qū)域mask[100:500,100:500] = 255
使用cv2.bitwise_and 函數(shù)把原來(lái)圖片中的需要的局部區(qū)域提取出來(lái),我們可以show一下,看看是否是自己需要的區(qū)域
有了mask的區(qū)域,使用cv2.calcHist([img], [0], mask, [256], [0, 256])函數(shù),傳遞mask 參數(shù),進(jìn)而可以實(shí)現(xiàn)mask圖片的直方圖顯示。
圖片直方圖均衡化
這種方法通常用來(lái)增加許多圖像的全局對(duì)比度,尤其是當(dāng)圖像的有用數(shù)據(jù)的對(duì)比度相當(dāng)接近的時(shí)候。通過(guò)這種方法,亮度可以更好地在直方圖上分布。這樣就可以用于增強(qiáng)局部的對(duì)比度而不影響整體的對(duì)比度,直方圖均衡化通過(guò)有效地?cái)U(kuò)展常用的亮度來(lái)實(shí)現(xiàn)這種功能。
這種方法對(duì)于背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來(lái)X光圖像中更好的骨骼結(jié)構(gòu)顯示以及曝光過(guò)度或者曝光不足照片中更好的細(xì)節(jié)。這種方法的一個(gè)主要優(yōu)勢(shì)是它是一個(gè)相當(dāng)直觀的技術(shù)并且是可逆操作,如果已知均衡化函數(shù),那么就可以恢復(fù)原始的直方圖,并且計(jì)算量也不大。這種方法的一個(gè)缺點(diǎn)是它對(duì)處理的數(shù)據(jù)不加選擇,它可能會(huì)增加背景噪聲的對(duì)比度并且降低有用信號(hào)的對(duì)比度。
圖片直方圖均衡化
有兩個(gè)問(wèn)題比較難懂,一是為什么要選用累積分布函數(shù),二是為什么使用累積分布函數(shù)處理后像素值會(huì)均勻分布。
直方圖均衡化包括三個(gè)步驟:
- 統(tǒng)計(jì)直方圖中每個(gè)灰度級(jí)出現(xiàn)的次數(shù);
- 計(jì)算累計(jì)歸一化直方圖;
- 重新計(jì)算像素點(diǎn)的像素值;
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
res = cv2.equalizeHist(img)
cv2.imshow('img',img)
cv2.imshow('res',res)
cv2.waitKey(0)
代碼截圖
opencv 使用此函數(shù)res = cv2.equalizeHist(img),對(duì)圖片進(jìn)行均衡化進(jìn)行處理,此函數(shù)是opencv全局化操作,這個(gè)操作在我們需要局部調(diào)整時(shí)不太適用,同理mask參數(shù),opencv存在一種局部化處理的函數(shù)cv2.createCLAHE(),此函數(shù)接受一個(gè)局部尺寸參數(shù)數(shù)據(jù)
局部化處理
from matplotlib import pyplot as plt
import numpy as np
import cv2
image = cv2.imread("1.jpg")
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#res = cv2.equalizeHist(img)
cla = cv2.createCLAHE(clipLimit=2,tileGridSize=(10,10))
res = cla.Apply(img)
cv2.imshow('img',img)
cv2.imshow('res',res)
cv2.waitKey(0)
代碼截圖
總結(jié)
圖片直方圖在相識(shí)圖片搜索引擎中起到了至關(guān)重要的作用,如何使用圖片直方圖來(lái)進(jìn)行相識(shí)圖片的搜索,我們下期分享,幫你打造一款屬于自己的相識(shí)圖片搜索引擎。