OpenCV-Python (官方)中文教程(部分一)_Day20

22.直方圖

22.1直方圖的計算,繪制與分析

使用 OpenCV 或 Numpy 函數計算直方圖

使用 Opencv 或者 Matplotlib 函數繪制直方圖

將要學習的函數有:cv2.calcHist(),np.histogram()

什么是直方圖呢?通過直方圖你可以對整幅圖像的灰度分布有一個整體的 了解。直方圖的 x 軸是灰度值(0 到 255),y 軸是圖片中具有同一個灰度值的 點的數目。

直方圖其實就是對圖像的另一種解釋。一下圖為例,通過直方圖我們可以 對圖像的對比度,亮度,灰度分布等有一個直觀的認識。幾乎所有的圖像處理 軟件都提供了直方圖分析功能。下圖來自Cambridge in Color website,強 烈推薦你到這個網站了解更多知識。

讓我們來一起看看這幅圖片和它的直方圖吧。(要記住,直方圖是根據灰度 圖像繪制的,而不是彩色圖像)。直方圖的左邊區域像是了暗一點的像素數量, 右側顯示了亮一點的像素的數量。從這幅圖上你可以看到灰暗的區域比兩的區 域要大,而處于中間部分的像素點很少。

(1).統計直方圖

現在我們知道什么是直方圖了, 那怎樣獲得一副圖像的直方圖呢? OpenCV和Numpy 都有內置函數做這件事。在使用這些函數之前我們有 必要想了解一下直方圖相關的術語。

BINS上面的直方圖顯示了每個灰度值對應的像素數。如果像素值為 0 到 255,你就需要 256 個數來顯示上面的直方圖。但是,如果你不需要知道每一個像素值的像素點數目的,而只希望知道兩個像素值之間的像素點數目怎么辦呢?舉例來說,我們想知道像素值在 0 到 15 之間的像素點的數目,接著 是 16 到 31,....,240 到 255。我們只需要 16 個值來繪制直方圖。OpenCV Tutorials ??on ?histograms中例子所演示的內容。

那到底怎么做呢?你只需要把原來的 256 個值等分成 16 小組,取每組的總和。而這里的每一個小組就被成為 BIN。第一個例子中有 256 個 BIN,第 二個例子中有 16個 BIN。在 OpenCV ?的文檔中用 histSize ?表示 ??BINS。

DIMS表示我們收集數據的參數數目。在本例中,我們對收集到的數據只考慮一件事:灰度值。所以這里就是 1。

RANGE:就是要統計的灰度值范圍,一般來說為 [0,256],也就是說所有的灰度值

使用 OpenCV 統計直方圖 函數 cv2.calcHist 可以幫助我們統計一幅圖像的直方圖。我們一起來熟悉一下這個函數和它的參數:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

??1. images: 原圖像(圖像格式為 uint8 或 ?oat32)。當傳入函數時應該 用中括號 [] 括起來,例如:[img]。

??2. channels: 同樣需要用中括號括起來,它會告訴函數我們要統計那幅圖 像的直方圖。如果輸入圖像是灰度圖,它的值就是 [0];如果是彩色圖像 的話,傳入的參數可以是 ?[0],[1],[2] ??它們分別對應著通道 ?B,G,R。

??3. mask: 掩模圖像。要統計整幅圖像的直方圖就把它設為 None。但是如 果你想統計圖像某一部分的直方圖的話,你就需要制作一個掩模圖像,并 使用它。(后邊有例子)

??4. histSize:BIN ?的數目。也應該用中括號括起來,例如:[256]。

??5. ranges: 像素值范圍,通常為 [0,256]

讓我們從一副簡單圖像開始吧。以灰度格式加載一幅圖像并統計圖像的直方圖。

import cv2

import numpy as np

import matplotlib.pyplot as plt

# 1. 讀取圖像(灰度模式)

img = cv2.imread('home.jpg', 0) ?# 參數0表示以灰度模式讀取

# 檢查圖像是否成功加載

if img is None:

????raise FileNotFoundError("無法加載圖像,請檢查路徑")

# 2. 計算直方圖

hist = cv2.calcHist(

????[img], ??????# 輸入圖像(必須用列表包裹)

????[0], ????????# 通道索引(灰度圖是0)

????None, ???????# 掩膜(None表示整個圖像)

????[256], ??????# 直方圖大小(bin的數量)

????[0, 256] ????# 像素值范圍

)

# 3. 可視化直方圖

plt.figure(figsize=(10, 5))

plt.title("Grayscale Histogram")

plt.xlabel("Pixel Value")

plt.ylabel("Frequency")

plt.xlim([0, 256]) ?# X軸范圍

plt.plot(hist, color='black')

plt.grid(True, linestyle='--', alpha=0.7)

plt.show()

# 4. 可選:顯示原圖

cv2.imshow("Original Image", img)

cv2.waitKey(0)

cv2.destroyAllWindows()

hist ??是一個 ?256x1 ?的數組,每一個值代表了與次灰度值對應的像素點數目。

使用 Numpy 統計直方圖?Numpy 中的函數 np.histogram()?也可以幫 我們統計直方圖。你也可以嘗試一下下面的代碼:

import cv2

import numpy as np

import matplotlib.pyplot as plt

# 1. 讀取圖像(灰度模式)

img = cv2.imread('11111.png', 0) ?# 參數0表示以灰度模式讀取

# 檢查圖像是否成功加載

if img is None:

????raise FileNotFoundError("無法加載圖像,請檢查路徑")

# 2. 使用numpy計算直方圖(不需要中括號)

hist, bins = np.histogram(img.ravel(), ?# 將圖像展平為一維數組

?????????????????????????bins=256, ?????# 直方圖的bin數量

?????????????????????????range=[0, 256]) # 像素值范圍

# 3. 可視化直方圖

plt.figure(figsize=(10, 5))

plt.title("Grayscale Histogram (numpy)")

plt.xlabel("Pixel Value")

plt.ylabel("Frequency")

plt.xlim([0, 256]) ?# X軸范圍

# 注意:bins比hist多一個元素,需要調整顯示

plt.bar(bins[:-1], ???????# X軸坐標(bin的左邊界)取bins數組除最后一個元素外的所有值(因為bins比hist多一個元素)

????????hist, ????????????# Y軸高度(頻數)每個bin對應的像素頻數

????????width=1, ?????????# 柱子的寬度 設置每個柱子的寬度為1(保證柱子之間無間隙)

????????color='black', ???# 柱子填充顏色 黑色

????????edgecolor='none') # 柱子邊框顏色(無邊框)

plt.grid(True, ??????????# 啟用網格線

?????????linestyle='--', # 虛線樣式

?????????alpha=0.7) ?????# 透明度(0.7表示70%不透明)

plt.show()

# 4. 可選:顯示原圖

cv2.imshow("Original Image", img)

cv2.waitKey(0)

cv2.destroyAllWindows()

hist 與上面計算的一樣。但是這里的 bins 是 257,因為 Numpy 計算 bins 的方式為:0-0.99,1-1.99,2-2.99 等。所以最后一個范圍是 255-255.99。 為了表示它,所以在 bins 的結尾加上了 256。但是我們不需要 256,到 255 就夠了。

其 他:Numpy ???還 有 一 個 函 數 ??np.bincount(),?它 的 運 行 速 度 是 np.histgram ??的 十 倍。 所 以 對 于 一 維 直 方 圖, 我 們 最 好 使 用 這 個 函 數。 使 用 ??np.bincount???時 別 忘 了 設 置 ??minlength=256。 例 如, hist=np.bincount(img.ravel(),minlength=256)

注 意:OpenCV的函數要比 np.histgram()快40倍.所以堅持使用OpenCV 函數.

(2).繪制直方圖

有兩種方法來繪制直方圖:

1.Short Way(簡單方法):使用 Matplotlib 中的繪圖函數。

2.Long Way(復雜方法):使用 OpenCV 繪圖函數

使用 Matplotlib?中有直方圖繪制函數:matplotlib.pyplot.hist()

它可以直接統計并繪制直方圖。你應該使用函數 ?calcHist() ?或 np.histogram()

統計直方圖。

以下是關于 matplotlib.pyplot.hist()、cv2.calcHist() 和 np.histogram() 三個函數的詳細對比分析,包括它們的區別、優缺點和適用場景:

1. matplotlib.pyplot.hist()??

特點:

??一體化操作:直接統計并繪制直方圖(計算+可視化一步完成)

??接口簡單:無需手動處理 bins 和 hist 的對應關系

??可視化集成:自動添加坐標軸、標題等圖形元素

import?cv2

from?matplotlib?import?pyplot?as?plt

?

img?=?cv2.imread('drawing.png',0)?

plt.hist(img.ravel(),256,[0,256])

plt.show()

2. cv2.calcHist()??

特點:

??OpenCV專屬:針對圖像數據高度優化

??多通道支持:可同時計算多通道直方圖

??靈活掩膜:支持指定ROI區域計算

import cv2

img = cv2.imread('image.jpg', 0)

hist = cv2.calcHist([img], [0], None, [256], [0, 256])

# 需要手動繪制

plt.plot(hist, color='red')

plt.title('OpenCV Histogram')

plt.show()

3. np.histogram()??

特點:

??純計算函數:只返回統計結果,不包含繪圖

??通用性強:適用于任何數值數據(不限于圖像)

??精確控制:可自定義 bins 和 range

import numpy as np

import matplotlib.pyplot as plt

img = cv2.imread('image.jpg', 0)

hist, bins = np.histogram(img.ravel(), bins=256, range=[0, 256])

# 手動繪制(需處理bins邊界)

plt.bar(bins[:-1], hist, width=1)

plt.title('NumPy Histogram')

plt.show()

如何選擇???

??1、需要快速可視化?? → plt.hist()

plt.hist(img.ravel(), bins=256, range=[0,256], alpha=0.7)

??2、OpenCV圖像處理流程?? → cv2.calcHist()

hist = cv2.calcHist([img], [0], mask, [256], [0,256])

??3、精確控制或非圖像數據?? → np.histogram()

hist, bins = np.histogram(data, bins=50, range=[min_val, max_val])

??4、多通道圖像分析?? → cv2.calcHist() + 循環

colors = ('b','g','r')

for i, col in enumerate(colors):

????hist = cv2.calcHist([img], [i], None, [256], [0,256])

plt.plot(hist, color=col)

性能實測對比??

import?time

import?matplotlib.pyplot?as?plt

import?cv2

import?numpy?as?np

img?=?cv2.imread('drawing.png',?0)

#?測試plt.hist

t1?=?time.time()

plt.hist(img.ravel(),?bins=256)

print(f"plt.hist:?{time.time()-t1:.4f}s")

#?測試cv2.calcHist

t2?=?time.time()

hist?=?cv2.calcHist([img],?[0],?None,?[256],?[0,256])

print(f"cv2.calcHist:?{time.time()-t2:.4f}s")

#?測試np.histogram

t3?=?time.time()

hist,?bins?=?np.histogram(img.ravel(),?bins=256)

print(f"np.histogram:?{time.time()-t3:.4f}s")

典型輸出(4000x3000像素圖像):

plt.hist: 3.7026s

cv2.calcHist: 0.0060s

np.histogram: 0.0209s

或者你可以只使用 matplotlib 的繪圖功能,這在同時繪制多通道(BGR) 的直方圖,很有用。但是要告訴繪圖函數你的直方圖數據在哪里。運行 一下下面的代碼:

import cv2

from matplotlib import pyplot as plt

img = cv2.imread('drawing.png') #讀取BGR格式的彩色圖像(默認加載為3通道numpy數組)

if img is None:

????raise FileNotFoundError("無法加載圖像,請檢查路徑")

#元組存儲三個顏色符號,對應Matplotlib的繪圖顏色:

#'b': 藍色(Blue,OpenCV的通道0)

#'g': 綠色(Green,通道1)

#'r': 紅色(Red,通道2)

color = ('b', 'g', 'r')

#同時獲取索引i(0,1,2)和顏色符號col('b','g','r')

for i, col in enumerate(color):

????#[img]: 輸入圖像(必須放在列表中)[i]: 通道索引(0=Blue, 1=Green, 2=Red)

????#None: 不使用掩膜(計算全圖)[256]: 直方圖bin數量(256級)[0,256]: 像素值范圍(0~255)

????histr = cv2.calcHist([img], [i], None, [256], [0,256])

????#histr: 當前通道的直方圖數據(256維向量)color=col: 使用對應通道的顏色(藍/綠/紅)

????plt.plot(histr, color=col, label=f'{col.upper()} Channel') ?# 添加標簽

plt.title('RGB Channel Histogram')

plt.xlabel('Pixel Value')

plt.ylabel('Frequency')

plt.xlim([0, 256]) #限制X軸顯示范圍為0~256(覆蓋所有像素值)

plt.legend() ?# 顯示圖例

plt.grid(True, linestyle='--', alpha=0.5) ?# 添加網格線

plt.show()

輸出效果??

將顯示一個包含三條曲線的直方圖:

??藍色曲線??: 藍色通道的像素值分布

??綠色曲線??: 綠色通道的分布

??紅色曲線??: 紅色通道的分布

(X軸為像素值0~255,Y軸為對應像素值的出現頻率)

關鍵點總結??

??enumerate():?同時獲取索引和值,避免手動計數

??calcHist()的列表輸入: 必須用[img]和[i]傳遞參數

??通道順序:?OpenCV默認BGR,Matplotlib默認RGB,注意顏色對應關系

使用 OpenCV 自帶函數繪制直方圖比較麻煩,這里不作介 紹,有興趣可以自己研究。可以參考 OpenCV-Python2 的官方示例。

(3).使用掩模

要統計圖像某個局部區域的直方圖只需構建一副掩模圖像。將要統計的部分設置成白色,其余部分為黑色,就構成一副掩模圖像。然后把這個掩模圖像傳給函數就可以了。

import?matplotlib.pyplot?as?plt

import?cv2

import?numpy?as?np

img?=?cv2.imread('drawing.png',0)

?

#?create?a?mask

#創建與圖像尺寸相同的全黑掩膜(所有像素值為0)img.shape[:2]獲取圖像的高度和寬度(忽略通道數)

mask?=?np.zeros(img.shape[:2],?np.uint8)?

#將掩膜中y=100:300,x=100:400的矩形區域設為白色(255),該區域表示后續要分析的ROI

mask[100:300,?100:400]?=?255

#對圖像進行按位與操作,保留掩膜白色區域對應的原圖像素

#參數說明:前兩個img:輸入圖像(灰度圖),mask=mask:指定掩膜區域

#效果:非ROI區域變為黑色(0),ROI區域保留原灰度值

masked_img?=?cv2.bitwise_and(img,img,mask?=?mask)

#?Calculate?histogram?with?mask?and?without?mask

#?Check?third?argument?for?mask

#計算全局和局部直方圖

hist_full?=?cv2.calcHist([img],[0],None,[256],[0,256])

hist_mask?=?cv2.calcHist([img],[0],mask,[256],[0,256])

plt.subplot(221),?plt.imshow(img,?'gray')?

plt.subplot(222),?plt.imshow(mask,'gray')?

plt.subplot(223),?plt.imshow(masked_img,?'gray')

#默認先畫的hist_full為藍色,后畫的hist_mask為橙色

plt.subplot(224),?plt.plot(hist_full),?plt.plot(hist_mask)?

plt.xlim([0,256])

?

plt.show()

結果如下,其中藍線是整幅圖像的直方圖,橙色線是進行掩模之后的直方圖。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903578.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903578.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903578.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數電發票整理:免費實用工具如何高效解析 XML 發票數據

如今數字電子發票越來越普及,但是數電發票的整理還是頗有講究~ 今天給大家介紹一個 XML 發票閱讀器。使用它完全不收取任何費用,且無廣告干擾,對財務人員而言十分實用。 01 軟件介紹 這款軟件就是XML格式(數電票)閱讀…

深度學習正則化:原理、方法與應用深度解析

摘要 本文深入探討深度學習中的正則化技術,介紹其避免過擬合的重要性,詳細講解常見的正則化方法,如 L 1 L_1 L1?和 L 2 L_2 L2?正則化、Dropout等,并通過線性回歸案例和神經網絡訓練流程對其進行直觀闡釋。幫助讀者理解正則化原…

【爬蟲】deepseek談爬蟲工具

2025 年,隨著 Web 技術的演進和反爬機制的升級,工具生態也會進一步優化。以下是 2025 年爬蟲 & 自動化測試的前沿工具預測,結合行業趨勢和現有技術發展方向: 🚀 2025 年推薦組合(預測版) 1…

SQLMesh 測試自動化:提升數據工程效率

在現代數據工程中,確保數據模型的準確性和可靠性至關重要。SQLMesh 提供了一套強大的測試工具,用于驗證數據模型的輸出是否符合預期。本文將深入探討 SQLMesh 的測試功能,包括如何創建測試、支持的數據格式以及如何運行和調試測試。 SQLMesh …

Java學習手冊:Spring 中常用的注解

一、組件注解 Component :用于標記一個類為 Spring 管理的 Bean,是 Spring 的基本組件注解。Spring 會通過類路徑掃描自動檢測并注冊標記了 Component 的類為 Bean。Service :是 Component 的派生注解,用于標記服務層類&#xff…

前端跨域問題詳解:原因、解決方案與最佳實踐

引言 在現代Web開發中,跨域問題是前端工程師幾乎每天都會遇到的挑戰。隨著前后端分離架構的普及和微服務的發展,跨域請求變得愈發常見。本文將深入探討跨域問題的本質、各種解決方案以及在實際開發中的最佳實踐。 一、什么是跨域問題? 1.1…

[計算機網絡]物理層

文章目錄 物理層的概述與功能傳輸介質雙絞線:分類:應用領域: 同軸電纜:分類: 光纖:分類: 無線傳輸介質:無線電波微波:紅外線:激光: 物理層設備中繼器:放大器:集線器(Hub)&#xff1a…

大連理工大學選修課——機器學習筆記(9):線性判別式與邏輯回歸

線性判別式與邏輯回歸 概述 判別式方法 產生式模型需要計算輸入、輸出的聯合概率 需要知道樣本的概率分布,定義似然密度的隱式參數也稱為基于似然的分類 判別式模型直接構造判別式 g i ( x ∣ θ i ) g_i(x|\theta_i) gi?(x∣θi?),顯式定義判別式…

OpenCV 圖像處理核心技術 (第二部分)

歡迎來到 OpenCV 圖像處理的第二部分!在第一部分,我們學習了如何加載、顯示、保存圖像以及訪問像素等基礎知識。現在,我們將深入探索如何利用 OpenCV 提供的強大工具來修改和分析圖像。 圖像處理是計算機視覺領域的基石。通過對圖像進行各種…

【鴻蒙HarmonyOS】一文詳解華為的服務卡片

7.服務卡片 1.什么是卡片 Form Kit(卡片開發服務)提供一種界面展示形式,可以將應用的重要信息或操作前置到服務卡片(以下簡稱“卡片”),以達到服務直達、減少跳轉層級的體驗效果。卡片常用于嵌入到其他應…

探索目標檢測:邊界框與錨框的奧秘

筆者在2022年開始學習目標檢測的時候,對各種框的概念那是相當混淆,比如: 中文名詞:邊界框、錨框、真實框、預測框等英文名詞:BoundingBox、AnchorBox、Ground Truth等 同一個英文名詞比如BoundingBox翻譯成中文也有多個…

[原創](現代Delphi 12指南):[macOS 64bit App開發]: [1]如何使用原生NSAlert消息框 (runModal模式)

[作者] 常用網名: 豬頭三 出生日期: 1981.XX.XX 企鵝交流: 643439947 個人網站: 80x86匯編小站 編程生涯: 2001年~至今[共24年] 職業生涯: 22年 開發語言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 開發工具: Visual Studio、Delphi、XCode、…

LangChain的向量RAG與MCP在意圖識別的主要區別

LangChain的向量RAG與MCP在意圖識別實現上的區別主要體現在技術路徑、流程設計以及應用場景三個方面: 1. 技術路徑差異 LangChain向量RAG 語義相似度驅動:通過用戶輸入的原始查詢與向量化知識庫的語義匹配實現意圖識別。例如,用戶提問"…

[特殊字符] Spring Cloud 微服務配置統一管理:基于 Nacos 的最佳實踐詳解

在微服務架構中,配置文件眾多、管理復雜是常見問題。本文將手把手演示如何將配置集中托管到 Nacos,并在 Spring Cloud Alibaba 項目中實現統一配置管理 自動刷新機制。 一、為什么要使用 Nacos 統一配置? 傳統方式下,每個服務都…

2025平航杯—團隊賽

2025平航杯團隊賽 計算機取證 分析起早王的計算機檢材,起早王的計算機插入過USB序列號是什么(格式:1)分析起早王的計算機檢材,起早王的便簽里有幾條待干(格式:1)分析起早王的計算機檢材,起早王的計算機默認瀏覽器是什…

JSON-RPC 2.0 規范中文版——無狀態輕量級遠程過程調用協議

前言 JSON-RPC是一種簡單、輕量且無狀態的遠程過程調用(RPC)協議,它允許不同系統通過標準化的數據格式進行通信。自2010年由JSON-RPC工作組發布以來,已成為眾多應用中實現遠程交互的基礎協議之一。本規范主要表達了JSON-RPC 2.0版…

微控制器編程 | ISP、IAP 與 ICP 的原理與比較

注:英文引文,機翻未校。 圖片清晰度限于引文原狀。 Introduction to Programming of Microcontroller: ISP, IAP and ICP 微控制器編程介紹:ISP、IAP 和 ICP Date: 30-11-2022 1. What is Microcontroller Programming 什么是微控制器編…

Allegro23.1新功能之新型via structure創建方法操作指導

Allegro23.1新功能之新型via structure創建方法操作指導 Allegro升級到了23.1后,支持創建新型via structure 通過直接定義參數來生成 具體操作如下 打開軟件,選擇 Allegro PCB Designer

IBM WebSphere Application Server 7.0/8.5.5證書過期問題處理

證書過期錯誤日志: [3/14/16 7:22:20:332 PDT] 0000007d WSX509TrustMa E CWPKI0312E: The certificate with subject DN CNMXSYSTEMS, OUctgNodeCell01, OUctgNode01, OIBM, CUS has an end date Mon Jan 11 11:17:18 PST 2016 which is no longer valid. [3/14/…

select,poll,epoll區別聯系

selsect,poll,epoll區別聯系 目錄 一、區別 二、聯系 select、poll 和 epoll 都是在 Linux 系統中用于實現 I/O 多路復用的機制,它們的主要目的是讓程序能夠同時監控多個文件描述符,以判斷是否有事件發生,從而提高 I/O 操作的效率。 一、區…