OpenCV 圖像直方圖

目錄

一、什么是圖像直方圖?

關鍵概念:BINS(區間)

二、直方圖的核心作用

三、OpenCV 計算直方圖:calcHist 函數詳解

1. 函數語法與參數解析

2. 基礎實戰:計算灰度圖直方圖

代碼實現

結果分析

3. 進階實戰:計算彩色圖直方圖

代碼實現

結果分析

4. 高級實戰:用掩模(mask)計算局部直方圖

代碼實現

關鍵說明

四、直方圖均衡化:提升圖像對比度

1. OpenCV 實現直方圖均衡化

代碼實現

結果分析

五、常見問題與解決方案


在計算機視覺領域,圖像直方圖是分析圖像像素分布的核心工具,無論是圖像增強、對比度調整,還是目標檢測中的特征提取,都離不開它的身影。本文將從直方圖的基本概念入手,結合數學原理與 OpenCV 代碼實例,帶你全面掌握圖像直方圖的理論與實踐,最后還會拓展直方圖均衡化等進階應用,助力你解決實際項目中的問題。


一、什么是圖像直方圖?

圖像直方圖是圖像像素灰度級別分布的圖形化表達,它以 “像素灰度值” 為橫軸,以 “該灰度值對應的像素數量” 為縱軸,直觀地呈現圖像的明暗分布特征。

舉個簡單例子:一張純黑圖像的直方圖,只會在灰度值 0 的位置出現一個峰值;而一張高對比度圖像的直方圖,像素會集中在灰度值較低(暗部)和較高(亮部)的區域,中間灰度區域像素較少。

關鍵概念:BINS(區間)

默認情況下,直方圖會統計 0-255 每個灰度值的像素數量,此時需要 256 個 “區間” 來展示,這 256 個區間就稱為BINS(對應 OpenCV 中calcHist函數的histSize參數)。

但在實際場景中,我們常不需要細分到單個灰度值。例如,將 0-255 劃分為 16 個區間(每個區間包含 16 個灰度值:0-15、16-31、…、240-255),此時histSize=16,只需 16 個 BINS 就能概覽圖像的灰度分布,既簡化計算,又能突出整體特征。


二、直方圖的核心作用

  1. 圖像明暗分析:通過直方圖峰值位置判斷圖像偏暗(峰值靠左)、偏亮(峰值靠右)或正常(峰值居中)。
  2. 圖像增強依據:針對對比度低的圖像(直方圖集中在狹窄區間),可通過直方圖均衡化擴展灰度范圍,提升對比度。
  3. 場景變換檢測:在視頻處理中,通過對比相鄰幀直方圖的差異,可檢測場景是否切換(如從室內到室外,直方圖會顯著變化)。
  4. 目標特征提取:在目標檢測(如車牌識別、人臉識別)中,直方圖可作為紋理特征的一部分,輔助區分目標與背景。

三、OpenCV 計算直方圖:calcHist 函數詳解

OpenCV 提供cv2.calcHist()函數計算圖像直方圖,掌握它的參數與用法是實戰的關鍵。

1. 函數語法與參數解析

cv2.calcHist(images, channels, mask, histSize, ranges)

各參數含義如下:

參數說明
images輸入圖像,格式需為uint8float32,必須用中括號[]包裹(如[img]
channels通道索引,灰度圖傳[0];彩色圖(BGR 格式)傳[0](B)、[1](G)、[2](R)
mask掩模圖像,統計整幅圖像直方圖傳None;統計局部區域傳自定義掩模
histSizeBINS 數量,需用中括號包裹(如[256]表示 256 個區間,[16]表示 16 個區間)
ranges像素值范圍,通常為[0, 256](包含 0,不包含 256,覆蓋所有灰度值)

2. 基礎實戰:計算灰度圖直方圖

以一張手機圖像(phone.png)為例,先將其轉為灰度圖,再計算并繪制直方圖。

代碼實現

import cv2
import matplotlib.pyplot as plt
import numpy as np# 1. 讀取灰度圖
phone_gray = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)
# 2. 方法1:用matplotlib直接繪制(需先將圖像轉為一維數組)
# ravel()函數:將二維灰度圖轉為一維像素數組
pixel_array = phone_gray.ravel()
# 繪制直方圖(bins=256,即每個灰度值一個區間)
plt.figure(figsize=(10, 4))
plt.hist(pixel_array, bins=256, color='gray', alpha=0.7)
plt.title('Gray Image Histogram (bins=256)')
plt.xlabel('Gray Level (0-255)')
plt.ylabel('Pixel Count')
plt.show()# 3. 方法2:用OpenCV的calcHist計算(bins=16,簡化展示)
phone_hist = cv2.calcHist(images=[phone_gray], channels=[0], mask=None, histSize=[16], ranges=[0, 256])
# 繪制calcHist結果(曲線圖)
plt.figure(figsize=(10, 4))
plt.plot(phone_hist, color='black', linewidth=2)
plt.title('Gray Image Histogram (bins=16)')
plt.xlabel('BINS (16 intervals)')
plt.ylabel('Pixel Count')
plt.xticks(range(16), [f'{i*16}-{i*16+15}' for i in range(16)], rotation=45)
plt.show()

結果分析

  • bins=256時,直方圖能清晰看到每個灰度值的像素分布,適合精細分析;
  • bins=16時,直方圖更簡潔,可快速判斷圖像整體明暗(如峰值集中在哪個區間)。

3. 進階實戰:計算彩色圖直方圖

彩色圖像(BGR 格式)需分別計算 B、G、R 三個通道的直方圖,通過對比各通道分布,可分析圖像的色彩偏向(如紅色通道峰值高,說明圖像偏紅)。

代碼實現

# 讀取彩色圖像(OpenCV默認BGR格式)
phone_color = cv2.imread('phone.png')
# 定義三個通道的顏色(B、G、R)
colors = ('blue', 'green', 'red')
# 分別計算并繪制三個通道的直方圖
plt.figure(figsize=(10, 4))
for i, color in enumerate(colors):# 計算當前通道的直方圖hist = cv2.calcHist(images=[phone_color], channels=[i], mask=None, histSize=[256], ranges=[0, 256])# 繪制曲線plt.plot(hist, color=color, label=f'{color.upper()} Channel')plt.title('Color Image Histogram (BGR)')
plt.xlabel('Gray Level (0-255)')
plt.ylabel('Pixel Count')
plt.legend()
plt.show()

結果分析

  • 若藍色通道(blue)的直方圖峰值較高,說明圖像中藍色區域較多(如天空、藍色物體);
  • 若紅色通道(red)峰值靠左,說明紅色區域偏暗(如暗紅色的物體)。

4. 高級實戰:用掩模(mask)計算局部直方圖

掩模(mask)是一張與原圖像尺寸相同的二值圖像(像素值為 0 或 255),它能 “篩選” 出原圖像中需要分析的區域(掩模中 255 的區域會被統計,0 的區域會被忽略)。

代碼實現

# 1. 讀取灰度圖并顯示
phone_gray = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Original Gray Image', phone_gray)
cv2.waitKey(0)# 2. 創建掩模:只保留圖像中間區域(50:350行,100:470列)
# 初始化掩模為全黑(0)
mask = np.zeros(phone_gray.shape[:2], dtype=np.uint8)
# 將中間區域設為白色(255)
mask[50:350, 100:470] = 255
cv2.imshow('Mask (White = Target Area)', mask)
cv2.waitKey(0)# 3. 用bitwise_and獲取掩模篩選后的圖像(可選,直觀查看篩選效果)
masked_image = cv2.bitwise_and(phone_gray, phone_gray, mask=mask)
cv2.imshow('Masked Image (Only Target Area)', masked_image)
cv2.waitKey(0)# 4. 計算局部直方圖(僅統計掩模中255的區域)
masked_hist = cv2.calcHist(images=[phone_gray], channels=[0], mask=mask, histSize=[256], ranges=[0, 256])
# 繪制局部直方圖
plt.figure(figsize=(10, 4))
plt.plot(masked_hist, color='black', linewidth=2)
plt.title('Local Histogram (Masked Area)')
plt.xlabel('Gray Level (0-255)')
plt.ylabel('Pixel Count')
plt.show()# 關閉所有窗口
cv2.destroyAllWindows()

關鍵說明

  • cv2.bitwise_and():通過掩模與原圖像進行 “與運算”,僅保留掩模中 255 的區域,方便直觀查看篩選效果;
  • 局部直方圖的應用場景:如分析人臉圖像中 “眼睛區域” 的灰度分布,可先用人臉檢測算法生成眼睛的掩模,再計算局部直方圖。

四、直方圖均衡化:提升圖像對比度

直方圖均衡化是基于直方圖的圖像增強技術,它通過 “拉伸” 圖像的灰度分布范圍,將集中在狹窄區間的像素分散到 0-255 全范圍,從而提升圖像對比度。

例如,一張霧天圖像(直方圖集中在中間灰度區間),經過均衡化后,暗部更暗、亮部更亮,細節更清晰。

1. OpenCV 實現直方圖均衡化

OpenCV 提供cv2.equalizeHist()函數,僅支持灰度圖(彩色圖需先轉為 YUV 格式,對亮度通道 Y 進行均衡化)。

代碼實現

import cv2
import matplotlib.pyplot as plt# 1. 讀取灰度圖(假設圖像對比度較低)
low_contrast_img = cv2.imread('low_contrast_phone.png', cv2.IMREAD_GRAYSCALE)
# 2. 計算均衡化前的直方圖
hist_before = cv2.calcHist([low_contrast_img], [0], None, [256], [0, 256])# 3. 執行直方圖均衡化
equalized_img = cv2.equalizeHist(low_contrast_img)
# 4. 計算均衡化后的直方圖
hist_after = cv2.calcHist([equalized_img], [0], None, [256], [0, 256])# 5. 對比顯示結果
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
# 原圖
axes[0, 0].imshow(low_contrast_img, cmap='gray')
axes[0, 0].set_title('Original Image (Low Contrast)')
axes[0, 0].axis('off')
# 原圖直方圖
axes[0, 1].plot(hist_before, color='black')
axes[0, 1].set_title('Histogram Before Equalization')
axes[0, 1].set_xlabel('Gray Level')
axes[0, 1].set_ylabel('Pixel Count')
# 均衡化后圖像
axes[1, 0].imshow(equalized_img, cmap='gray')
axes[1, 0].set_title('Equalized Image (High Contrast)')
axes[1, 0].axis('off')
# 均衡化后直方圖
axes[1, 1].plot(hist_after, color='black')
axes[1, 1].set_title('Histogram After Equalization')
axes[1, 1].set_xlabel('Gray Level')
axes[1, 1].set_ylabel('Pixel Count')plt.tight_layout()
plt.show()

結果分析

  • 均衡化前:直方圖集中在中間灰度區間,圖像整體發灰、對比度低;
  • 均衡化后:直方圖均勻分布在 0-255 全范圍,圖像暗部與亮部分明,細節更清晰。

五、常見問題與解決方案

  1. Q:計算彩色圖直方圖時,顏色與預期不符?
    A:OpenCV 讀取彩色圖默認是 BGR 格式,而 matplotlib 顯示時默認是 RGB 格式。若需用 matplotlib 顯示原圖,需先通過cv2.cvtColor(img, cv2.COLOR_BGR2RGB)轉換格式,但計算直方圖時無需轉換(直接用 BGR 通道即可)。

  2. Q:掩模計算局部直方圖時,結果全為 0?
    A:檢查掩模的尺寸是否與原圖像一致(如原圖像是(480, 640),掩模也需是(480, 640)),且掩模的像素值是否為0255(不能是其他值)。

  3. Q:均衡化后圖像出現 “過曝” 或 “細節丟失”?
    A:普通直方圖均衡化會全局拉伸灰度,可能導致局部細節丟失。可改用自適應直方圖均衡化cv2.createCLAHE()),它將圖像分塊處理,保留局部細節,適合明暗差異大的圖像。

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

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

相關文章

Firefox Window 開發流程(四)

1 引言 在進行 Firefox 瀏覽器的二次開發、內核研究或自定義構建之前,最重要的步驟就是拉取源碼并進入 Mozilla 官方提供的開發引導模式。這不僅是所有定制工作的起點,同時也決定了后續開發環境的穩定性與可維護性。本文將從源碼獲取、工具使用、引導腳…

mybatis plus 使用wrapper輸出SQL

在MyBatis-Plus中,Wrapper對象用于構建復雜的查詢條件。雖然MyBatis-Plus本身沒有直接提供從Wrapper對象獲取完整SQL語句的方法,但你可以通過一些間接的方式來獲取生成的SQL片段。以下是如何使用MyBatis-Plus的Wrapper來獲取SQL片段的步驟:?…

第1章:操作系統和計算機網絡

1. 操作系統和計算機網絡組成目標概述1.1. 核心知識操作系統和網絡知識很龐大,大多內容枯燥無味,主功最常用的,符合2/8原則。操作系統:內核、性能、磁盤IO、內存、CPU進程、線程、文件、中斷計算機網絡:OSI七層模型、T…

day27|前端框架學習

1、驗證。前后端連接,authentication2、action,在pinia,管理狀態,處理異步操作(API/Firebase)。methods。在vue組件,處理組件內部邏輯3、滑動窗口,能有大致思路,但是自己…

單片機啟動文件——數據段重定位,BSS段清零

目錄重定位概念的引入一、數據段重定位1.作用:2.目的:3.自己模擬代碼二、BSS段清零1.作用:2.目的:3.自己模擬代碼三,實現原理重定位概念的引入 單片機中內存段的詳細介紹 在單片機中內存分為了很多不同的區域&#xf…

QT(3)

四、基本組件1. Designer設計師(掌握)Qt Designer 是 Qt 提供的可視化界面設計工具,支持通過拖拽組件快速構建 GUI 界面,生成的界面文件以 .ui格式保存(基于 XML 的標簽語言)。??核心功能??&#xff1a…

常用注解:@PostMapping、@RequestBody、@Autowired、@Service、@Mapper

1. PostMapping作用:將方法綁定到 HTTP POST 請求的特定路徑上用法:PostMapping("/login") // 綁定到 POST /login PostMapping("/employees") // 綁定到 POST /employees PostMapping("/users/{id}") …

SoC日志管理

目錄 一、汽車控制器中日志的核心類型 二、日志管理的核心環節與策略 1. 日志采集:確保“全面且不冗余” 2. 日志存儲:平衡“可靠性”與“存儲成本” 3. 日志安全:防止“篡改與泄露” 4. 日志生命周期:符合“法規與成本” 5. 日志工具與實現 三、汽車場景的特殊約束與應對 …

橫評五款開源多智能體框架,AI高手都在用哪個?下一款Manus、Cursor、Devin,誰能撐起來?

Agent 成為共識的速度非常快。但今年 Agent 的真正轉折點在于:多智能體。 從科研自動化到任務編排,從自動開淘寶店到 Vibe 一切,從 AI 瀏覽器到今天的 ChatGPT Agent,一切都是多智能體的味道。 但要真正搭建一個多智能體&#x…

GitHub每日最火火火項目(9.10)

1. Physical-Intelligence / openpi 項目名稱:openpi項目介紹:基于 Python 開發,聚焦于物理智能領域,為相關研究與應用提供支持。Python 在科學計算、人工智能等領域有著廣泛且成熟的生態,借助其豐富的庫(如…

2025年滲透測試面試題總結-61(題目+回答)

安全領域各種資源,學習文檔,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具,歡迎關注。 目錄 2. 提交過什么漏洞 3. 常用漏洞掃描工具 4. OWASP TOP 10 2021核心變化 5. MySQL寫WebShell權限要求 6.…

高可用消息隊列線程池設計與實現:從源碼解析到最佳實踐

前言在現代分布式系統中,消息隊列處理是核心組件之一。今天我們將深入解析一個高性能、高可用的消息隊列線程池實現——FindMessageQueue,并探討如何將其優化應用于實際項目中。一、核心架構設計1.1 整體架構圖┌───────────────────…

Android App瘦身方法介紹

第一章 安裝包構成深度剖析1.1 APK文件結構解剖APK文件本質是一個ZIP壓縮包,通過unzip -l app.apk命令可查看其內部結構:Archive: app.apkLength Method Size Cmpr Date Time CRC-32 Name -------- ------ ------- ---- ---------- -…

深入淺出遷移學習:從理論到實踐

1. 引言:為什么需要遷移學習?在深度學習爆發的這十年里,我們見證了模型性能的飛速提升 ——ResNet 在圖像分類上突破人類視覺極限,BERT 在 NLP 任務上刷新基準,GPT 系列更是開啟了大語言模型時代。但這些亮眼成果的背后…

嵌入式人別再瞎折騰了!這8個開源項目,解決按鍵/隊列/物聯網所有痛點,小白也能抄作業

嵌入式人別再瞎折騰了!這8個開源項目,解決按鍵/隊列/物聯網所有痛點,小白也能抄作業 你是不是也有過這樣的崩潰時刻:想做個按鍵控制,結果長按、連擊、組合鍵的邏輯寫了200行if-else,最后還時不時串鍵&#…

C++篇(7)string類的模擬實現

一、string的成員變量string和數據結構中的順序表類似,本質上可以理解成字符順序表,其成員變量仍然是_str,_size和_capacity。但是,C標準庫里面也有一個string,和我們要自己實現的string類沖突了,該如何解決…

【直接套模板】如何用 Web of Science 精準檢索文獻?

在文獻檢索的時候遇到一些問題,單獨使用關鍵詞檢索出來的文章數量太多,如果是多加一些限定詞,又什么都檢索不到:比如我明明知道某篇論文已經發表,但在 Web of Science (WoS) 里卻檢索不到。這其實和檢索式的寫法密切相…

HTTP 協議:從原理到應用的深度剖析

一、什么是HTTP協議?HTTP協議,全稱 Hyper Text Transfer Protocol(超?本傳輸協議)的縮寫,是?于服務器與客戶端瀏覽器之間傳輸超?本數據(?字、圖?、視頻、?頻)的應?層協議。它規定了客戶端…

【算法--鏈表】138.隨機鏈表的復制--通俗講解

算法通俗講解推薦閱讀 【算法–鏈表】83.刪除排序鏈表中的重復元素–通俗講解 【算法–鏈表】刪除排序鏈表中的重復元素 II–通俗講解 【算法–鏈表】86.分割鏈表–通俗講解 【算法】92.翻轉鏈表Ⅱ–通俗講解 【算法–鏈表】109.有序鏈表轉換二叉搜索樹–通俗講解 【算法–鏈表…

為什么現在企業注重數據可視化?一文講清可視化數據圖表怎么做

目錄 一、企業注重數據可視化的原因 1.提升數據理解效率 2.發現數據中的規律和趨勢 3.促進企業內部溝通與協作 4.增強決策的科學性 5.提升企業競爭力 二、可視化數據圖表的基本概念 1.常見的可視化圖表類型 2.可視化圖表的構成要素 3.可視化圖表的設計原則 三、制作…