OpenCV 圖像預處理核心技術詳解 (C/C++)
圖像預處理是計算機視覺任務中至關重要的一步。原始圖像往往受到噪聲、光照不均、尺寸不一等多種因素的影響,直接用于后續分析(如特征提取、目標檢測、機器學習模型訓練等)可能會導致性能下降或結果不準確。預處理旨在通過一系列操作來增強圖像質量、去除噪聲、標準化圖像數據,使其更適合特定應用。
本文將詳細介紹幾種 OpenCV 中常用的圖像預處理技術,包括其 C/C++ 實現、關鍵參數解析以及使用時的注意事項。
目錄
- 灰度轉換 (Grayscale Conversion)
- 圖像縮放 (Resizing)
- 圖像平滑/模糊 (Smoothing/Blurring)
- 高斯模糊 (Gaussian Blur)
- 中值模糊 (Median Blur)
- 雙邊濾波 (Bilateral Filter)
- 閾值化處理 (Thresholding)
- 簡單閾值 (Simple Thresholding)
- 自適應閾值 (Adaptive Thresholding)
- 圖像歸一化 (Normalization)
- 形態學操作 (Morphological Operations)
- 腐蝕 (Erosion) 與膨脹 (Dilation)
- 開運算 (Opening) 與閉運算 (Closing)
- 直方圖均衡化 (Histogram Equalization)
- 總結與建議
1. 灰度轉換 (Grayscale Conversion)
將彩色圖像轉換為灰度圖像是最常見的預處理步驟之一。
- 目的:降低數據維度(從3通道變為1通道),減少計算量,某些算法(如Canny邊緣檢測)通常在灰度圖上操作。
- OpenCV 函數:
cv::cvtColor()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp> // 包含 cvtColorint main() {cv::Mat src = cv::imread("input.jpg", cv::IMREAD_COLOR);if (src.empty()) {std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}cv::Mat gray;cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 注意OpenCV默認加載為BGRcv::imshow("Original", src);cv::imshow("Grayscale", gray);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::cvtColor
):
src
: 輸入圖像 (彩色圖像)。dst
: 輸出圖像 (灰度圖像)。code
: 顏色空間轉換代碼。cv::COLOR_BGR2GRAY
: 從 BGR (OpenCV 默認的彩色圖像通道順序) 轉換為灰度。cv::COLOR_RGB2GRAY
: 從 RGB 轉換為灰度 (如果你的圖像源是 RGB)。cv::COLOR_BGR2HSV
: 轉換為 HSV 顏色空間等。
注意事項:
- 確保輸入圖像確實是彩色圖像。對已經是灰度的圖像進行此操作通常不會報錯,但無意義。
- OpenCV 使用
cv::imread()
加載圖像時,默認通道順序是 BGR。如果你的圖像數據來自其他源(例如某些庫或傳感器可能輸出 RGB),請注意選擇正確的轉換代碼。
2. 圖像縮放 (Resizing)
調整圖像的尺寸以滿足特定算法的輸入要求或減少計算量。
- 目的:統一輸入尺寸,構建圖像金字塔,加速處理。
- OpenCV 函數:
cv::resize()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp> // 包含 resizeint main() {cv::Mat src = cv::imread("input.jpg");if (src.empty()) {std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}cv::Mat resized_abs, resized_rel;cv::Size new_size(300, 200); // 目標絕對尺寸:寬300, 高200// 方法1: 指定目標尺寸cv::resize(src, resized_abs, new_size, 0, 0, cv::INTER_LINEAR);// 方法2: 指定縮放因子double scale_x = 0.5;double scale_y = 0.5;cv::resize(src, resized_rel, cv::Size(), scale_x, scale_y, cv::INTER_LINEAR);cv::imshow("Original", src);cv::imshow("Resized (Absolute)", resized_abs);cv::imshow("Resized (Relative)", resized_rel);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::resize
):
src
: 輸入圖像。dst
: 輸出圖像。dsize
: 輸出圖像的目標尺寸 (cv::Size(width, height)
)。如果設置為cv::Size()
(即cv::Size(0,0)
),則尺寸將通過fx
和fy
計算。fx
: 沿水平軸的縮放因子。如果dsize
非零,則此參數無效。fy
: 沿垂直軸的縮放因子。如果dsize
非零,則此參數無效。interpolation
: 插值方法。cv::INTER_NEAREST
: 最近鄰插值。速度最快,但效果可能較差,有馬賽克感。cv::INTER_LINEAR
: 雙線性插值 (默認)。速度和效果的良好折中,常用于放大。cv::INTER_CUBIC
: 雙三次插值。效果較好,尤其在放大時,但計算量更大。cv::INTER_AREA
: 基于區域的重采樣。在縮小圖像時效果較好,可以避免波紋。放大時類似最近鄰。cv::INTER_LANCZOS4
: Lanczos 插值 (8x8鄰域)。效果最好,但計算量最大。
注意事項:
- 插值方法選擇:
- 縮小圖像時,
cv::INTER_AREA
通常是最佳選擇,以避免信息丟失和摩爾紋。 - 放大圖像時,
cv::INTER_LINEAR
是一個不錯的起點,cv::INTER_CUBIC
或cv::INTER_LANCZOS4
可以提供更好的質量,但更慢。
- 縮小圖像時,
- 長寬比: 如果只指定
dsize
而不考慮原始長寬比,圖像可能會變形。如果需要保持長寬比,應先計算一個軸的縮放因子或新尺寸,然后據此計算另一個。 - 如果同時提供了
dsize
(非零) 和fx
/fy
(非零),dsize
優先。
3. 圖像平滑/模糊 (Smoothing/Blurring)
用于減少圖像噪聲,平滑圖像細節。
高斯模糊 (Gaussian Blur)
使用高斯核對圖像進行卷積,有效去除高斯噪聲。
- OpenCV 函數:
cv::GaussianBlur()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("input_noisy.jpg"); // 假設有一張帶噪聲的圖if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat blurred_gaussian;cv::Size kernel_size(5, 5); // 高斯核尺寸,必須是正奇數double sigmaX = 0; // X方向標準差,若為0,則由ksize.width計算// double sigmaY = 0; // Y方向標準差,若為0,則由ksize.height計算 (或等于sigmaX)cv::GaussianBlur(src, blurred_gaussian, kernel_size, sigmaX);cv::imshow("Original", src);cv::imshow("Gaussian Blurred", blurred_gaussian);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::GaussianBlur
):
ksize
: 高斯核的尺寸 (cv::Size(width, height)
)。寬度和高度必須是正奇數,也可以不同。sigmaX
: X 方向的高斯核標準差。sigmaY
: Y 方向的高斯核標準差。如果為0,則設置成與sigmaX
相同;如果兩者都為0,則它們從ksize.width
和ksize.height
計算得出。建議將sigmaY
設為0,讓其自動等于sigmaX
或根據ksize
計算。borderType
: 邊界處理方式,默認cv::BORDER_DEFAULT
。
注意事項 (GaussianBlur
):
ksize
越大,圖像越模糊。sigmaX
(和sigmaY
) 越大,模糊程度也越大。- 如果
sigmaX
(和sigmaY
) 設置得非常小,而ksize
較大,效果可能不佳。通常讓sigma
根據ksize
計算 (通過將sigmaX
設為0) 是個好主意,或者根據經驗值設定。 - 高斯模糊對所有方向的平滑程度相同,可能會模糊掉一些有用的邊緣信息。
中值模糊 (Median Blur)
用像素鄰域內的中值替換該像素的值,對椒鹽噪聲特別有效。
- OpenCV 函數:
cv::medianBlur()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("salt_pepper_noise.jpg"); // 假設有椒鹽噪聲圖if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat blurred_median;int ksize_median = 5; // 孔徑線性尺寸,必須是大于1的奇數cv::medianBlur(src, blurred_median, ksize_median);cv::imshow("Original", src);cv::imshow("Median Blurred", blurred_median);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::medianBlur
):
ksize
: 孔徑的線性尺寸 (例如,5 表示 5x5 的鄰域)。必須是大于1的奇數。
注意事項 (medianBlur
):
ksize
越大,平滑效果越強,但也可能丟失更多圖像細節。- 相比高斯模糊,中值模糊在去除椒鹽噪聲的同時能更好地保留邊緣。
- 計算開銷隨
ksize
增加而顯著增加。
雙邊濾波 (Bilateral Filter)
在平滑圖像的同時保持邊緣清晰。
- OpenCV 函數:
cv::bilateralFilter()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("input.jpg");if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat blurred_bilateral;int d = 9; // 濾波期間每個像素鄰域的直徑。如果非正,則從 sigmaSpace 計算。double sigmaColor = 75; // 顏色空間濾波器的 Sigma 值。較大值意味著鄰域內更遠的顏色也會混合在一起,從而產生更大區域的半相等顏色。double sigmaSpace = 75; // 坐標空間濾波器的 Sigma 值。較大值意味著更遠的像素將相互影響,只要它們的顏色足夠接近。當 d>0 時,它指定鄰域大小而不考慮 sigmaSpace。否則,d 與 sigmaSpace 成正比。cv::bilateralFilter(src, blurred_bilateral, d, sigmaColor, sigmaSpace);cv::imshow("Original", src);cv::imshow("Bilateral Filtered", blurred_bilateral);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::bilateralFilter
):
d
: 在過濾期間使用的每個像素鄰域的直徑。如果為非正數(例如 -1),則會從sigmaSpace
計算出來。通常取 5 到 9 之間的值。sigmaColor
: 顏色空間的標準差。值越大,意味著越多差異較大的顏色會被認為是相似的,從而被平均。sigmaSpace
: 坐標空間的標準差。值越大,意味著越遠的像素會相互影響(只要顏色相似)。如果d > 0
,則d
指定鄰域大小,sigmaSpace
不起作用;否則d
與sigmaSpace
成正比。
注意事項 (bilateralFilter
):
- 雙邊濾波比其他模糊方法慢得多。
- 參數
sigmaColor
和sigmaSpace
的調整對結果影響很大,需要根據具體圖像和需求進行調試。 - 如果
sigmaColor
值過大,效果接近高斯模糊;如果過小,則平滑效果不明顯。 - 如果
sigmaSpace
值過大,計算量會增加。
4. 閾值化處理 (Thresholding)
將圖像轉換為二值圖像(通常是黑白)。
簡單閾值 (Simple Thresholding)
將像素值與固定閾值進行比較。
- OpenCV 函數:
cv::threshold()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("input.jpg", cv::IMREAD_GRAYSCALE); // 閾值處理通常在灰度圖上進行if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat thresh_binary, thresh_otsu;double thresh_val = 127;double max_val = 255;// 基本二值閾值cv::threshold(src, thresh_binary, thresh_val, max_val, cv::THRESH_BINARY);// Otsu's 二值化 (自動計算閾值)// 此時,輸入的 thresh_val (這里是0) 被忽略,函數會自動計算最佳閾值double otsu_thresh = cv::threshold(src, thresh_otsu, 0, max_val, cv::THRESH_BINARY | cv::THRESH_OTSU);std::cout << "Otsu's calculated threshold: " << otsu_thresh << std::endl;cv::imshow("Original Grayscale", src);cv::imshow("Binary Threshold", thresh_binary);cv::imshow("Otsu's Threshold", thresh_otsu);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::threshold
):
src
: 輸入圖像,通常是單通道灰度圖。dst
: 輸出的二值圖像。thresh
: 閾值。maxval
: 當像素值超過(或滿足某些條件,取決于type
)閾值時賦予的新值。type
: 閾值類型:cv::THRESH_BINARY
: 如果src(x,y) > thresh
,則dst(x,y) = maxval
,否則dst(x,y) = 0
。cv::THRESH_BINARY_INV
:cv::THRESH_BINARY
的反轉。cv::THRESH_TRUNC
: 如果src(x,y) > thresh
,則dst(x,y) = thresh
,否則dst(x,y) = src(x,y)
。cv::THRESH_TOZERO
: 如果src(x,y) > thresh
,則dst(x,y) = src(x,y)
,否則dst(x,y) = 0
。cv::THRESH_TOZERO_INV
:cv::THRESH_TOZERO
的反轉。cv::THRESH_OTSU
: Otsu’s 二值化。與上述類型之一(通常是cv::THRESH_BINARY
)通過|
(位或) 組合使用。函數會自動計算一個全局最優閾值。此時thresh
參數被忽略。cv::THRESH_TRIANGLE
: Triangle 算法,也用于自動閾值確定。
注意事項 (threshold
):
- 輸入圖像應為灰度圖。
cv::THRESH_OTSU
和cv::THRESH_TRIANGLE
對于雙峰直方圖的圖像效果較好,可以自動找到合適的閾值,但對光照不均的圖像可能效果不佳。- 選擇合適的
thresh
值對于簡單閾值至關重要,通常需要實驗或基于圖像直方圖分析。
自適應閾值 (Adaptive Thresholding)
對于光照不均的圖像,使用局部閾值而非全局閾值。
- OpenCV 函數:
cv::adaptiveThreshold()
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("uneven_lighting.jpg", cv::IMREAD_GRAYSCALE); // 假設光照不均if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat adaptive_thresh_mean, adaptive_thresh_gaussian;double max_val = 255;int block_size = 11; // 鄰域大小,必須是奇數double C = 2; // 從均值或加權均值中減去的常數cv::adaptiveThreshold(src, adaptive_thresh_mean, max_val,cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY,block_size, C);cv::adaptiveThreshold(src, adaptive_thresh_gaussian, max_val,cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY,block_size, C);cv::imshow("Original Grayscale", src);cv::imshow("Adaptive Mean Threshold", adaptive_thresh_mean);cv::imshow("Adaptive Gaussian Threshold", adaptive_thresh_gaussian);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::adaptiveThreshold
):
src
: 輸入灰度圖像。dst
: 輸出二值圖像。maxValue
: 賦予超過閾值的像素的新值。adaptiveMethod
: 自適應閾值算法:cv::ADAPTIVE_THRESH_MEAN_C
: 閾值是鄰域的均值減去C
。cv::ADAPTIVE_THRESH_GAUSSIAN_C
: 閾值是鄰域的高斯加權和減去C
。
thresholdType
: 閾值類型,通常是cv::THRESH_BINARY
或cv::THRESH_BINARY_INV
。blockSize
: 用于計算閾值的像素鄰域大小,必須是奇數。C
: 從均值或加權均值中減去的常數。可以是正數、零或負數。
注意事項 (adaptiveThreshold
):
blockSize
和C
的選擇對結果影響很大,需要仔細調整。blockSize
越大,參與計算局部閾值的區域就越大,細節可能會丟失。太小則可能對噪聲敏感。cv::ADAPTIVE_THRESH_GAUSSIAN_C
通常比cv::ADAPTIVE_THRESH_MEAN_C
效果更好,因為它對中心點附近的像素賦予更大權重。
5. 圖像歸一化 (Normalization)
將像素值縮放到特定范圍,例如 [0, 1] 或 [0, 255]。
- 目的:消除由于光照和對比度不同帶來的影響,改善某些算法(如機器學習模型)的性能。
- OpenCV 函數:
cv::normalize()
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp> // 包含 normalizeint main() {// 假設我們有一個CV_32F類型的圖像(例如,某些算法的輸出)cv::Mat src = cv::Mat::zeros(100, 100, CV_32FC1);cv::randu(src, cv::Scalar::all(50), cv::Scalar::all(200)); // 填充50-200之間的隨機值cv::Mat normalized_img;double alpha = 0; // 歸一化后的最小值double beta = 255; // 歸一化后的最大值 (對于顯示,通常是255)// 對于機器學習特征,可能是1.0// 歸一化到 [alpha, beta] 范圍cv::normalize(src, normalized_img, alpha, beta, cv::NORM_MINMAX, CV_8UC1); // 輸出為CV_8UC1用于顯示// 如果只是想歸一化到 [0,1] 并且保持浮點類型cv::Mat normalized_float;cv::normalize(src, normalized_float, 0.0, 1.0, cv::NORM_MINMAX, CV_32FC1);// 顯示需要轉換到8位cv::Mat src_display, norm_display;if (src.type() != CV_8U) src.convertTo(src_display, CV_8U, 255.0/(200-50), -50.0 * 255.0/(200-50)); // 手動調整范圍以便顯示else src.copyTo(src_display);normalized_img.copyTo(norm_display); // normalized_img 已經是 CV_8UC1cv::imshow("Original (scaled for display)", src_display);cv::imshow("Normalized to [0, 255]", norm_display);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::normalize
):
src
: 輸入數組。dst
: 輸出數組,與src
大小相同。alpha
: 范圍歸一化的下界。beta
: 范圍歸一化的上界 (對于cv::NORM_MINMAX
) 或范數值 (對于其他類型)。norm_type
: 歸一化類型:cv::NORM_MINMAX
: 將值線性縮放到[alpha, beta]
范圍。cv::NORM_INF
,cv::NORM_L1
,cv::NORM_L2
: 按指定范數進行歸一化 (通常beta
用作目標范數值)。
dtype
: 當為負數時,輸出數組dst
的類型與src
相同;否則,它與src
的通道數相同,但深度為dtype
。例如,可以將 CV_32F 歸一化為 CV_8U。mask
: 可選的操作掩碼。
注意事項 (normalize
):
- 最常用的歸一化類型是
cv::NORM_MINMAX
。 - 如果
dtype
設置為輸出特定類型(如CV_8U
),則會進行類型轉換和可能的截斷/縮放。 - 在進行某些特征描述子計算或將圖像輸入到神經網絡之前,歸一化非常重要。
6. 形態學操作 (Morphological Operations)
基于形狀改變圖像結構的非線性操作,常用于噪聲去除、物體分離/連接、尋找區域等。
- 核心元素: 結構元素 (Kernel/Structuring Element),它定義了操作的鄰域形狀。
- 使用
cv::getStructuringElement(shape, ksize, anchor)
創建。shape
:cv::MORPH_RECT
(矩形),cv::MORPH_ELLIPSE
(橢圓),cv::MORPH_CROSS
(十字形)。ksize
: 結構元素的尺寸。anchor
: 錨點位置,默認在中心。
- 使用
腐蝕 (Erosion) 與膨脹 (Dilation)
- 腐蝕 (
cv::erode
): “收縮” 或 “細化” 圖像中的亮區(前景)。去除小的噪點。 - 膨脹 (
cv::dilate
): “擴張” 或 “加粗” 圖像中的亮區。連接斷開的部分,填充孔洞。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("binary_image.png", cv::IMREAD_GRAYSCALE); // 最好是二值圖或灰度圖if (src.empty()) { /* ... error handling ... */ return -1; }// 確保是二值圖像 (例如,經過閾值化處理)cv::threshold(src, src, 127, 255, cv::THRESH_BINARY);cv::Mat eroded, dilated;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));// int iterations = 1; // 操作迭代次數cv::erode(src, eroded, kernel);cv::dilate(src, dilated, kernel);cv::imshow("Original Binary", src);cv::imshow("Eroded", eroded);cv::imshow("Dilated", dilated);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::erode
, cv::dilate
):
src
: 輸入圖像。dst
: 輸出圖像。kernel
: 結構元素。如果為cv::Mat()
,則使用 3x3 矩形核。anchor
: 錨點位置,默認cv::Point(-1,-1)
表示在核中心。iterations
: 操作迭代次數。次數越多,效果越明顯。borderType
,borderValue
: 邊界處理。
開運算 (Opening) 與閉運算 (Closing)
通過組合腐蝕和膨脹實現更復雜的操作。使用 cv::morphologyEx()
。
- 開運算 (
cv::MORPH_OPEN
): 先腐蝕后膨脹。用于去除小的噪點(暗背景上的亮噪點),平滑物體輪廓,斷開細小連接。 - 閉運算 (
cv::MORPH_CLOSE
): 先膨脹后腐蝕。用于填充物體內的小孔洞,連接鄰近物體,平滑輪廓。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("noisy_binary.png", cv::IMREAD_GRAYSCALE);if (src.empty()) { /* ... error handling ... */ return -1; }cv::threshold(src, src, 127, 255, cv::THRESH_BINARY);cv::Mat opened, closed;cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7));cv::morphologyEx(src, opened, cv::MORPH_OPEN, kernel);cv::morphologyEx(src, closed, cv::MORPH_CLOSE, kernel);cv::imshow("Original Binary", src);cv::imshow("Opened", opened);cv::imshow("Closed", closed);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析 (cv::morphologyEx
):
op
: 形態學操作類型:cv::MORPH_OPEN
,cv::MORPH_CLOSE
cv::MORPH_GRADIENT
: 膨脹圖與腐蝕圖之差,可得到物體輪廓。cv::MORPH_TOPHAT
: 原圖與開運算結果之差。cv::MORPH_BLACKHAT
: 閉運算結果與原圖之差。
- 其他參數與
erode
/dilate
類似。
注意事項 (形態學操作):
- 通常在二值圖像上操作效果最直觀,但也可用于灰度圖像。
- 結構元素
kernel
的形狀和大小對結果影響極大。矩形核適用于處理具有水平和垂直邊緣的結構;橢圓或圓形核更通用。 iterations
參數可以增強效果,但多次小核操作不完全等同于一次大核操作。
7. 直方圖均衡化 (Histogram Equalization)
增強圖像對比度,尤其對那些像素值集中在某個狹窄范圍內的圖像有效。
- 目的:擴展圖像的像素強度分布,使其更均勻地覆蓋整個強度范圍。
- OpenCV 函數:
cv::equalizeHist()
: 全局直方圖均衡化。cv::CLAHE
: 對比度受限的自適應直方圖均衡化 (Contrast Limited Adaptive Histogram Equalization)。
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>int main() {cv::Mat src = cv::imread("low_contrast.jpg", cv::IMREAD_GRAYSCALE); // 假設低對比度圖if (src.empty()) { /* ... error handling ... */ return -1; }cv::Mat equalized_global;cv::equalizeHist(src, equalized_global);cv::Mat equalized_clahe;// 創建 CLAHE 對象// double clipLimit = 2.0; // 對比度限制閾值// cv::Size tileGridSize(8, 8); // 將圖像劃分為的小塊數量cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();clahe->setClipLimit(2.0);clahe->setTileGridSize(cv::Size(8, 8));clahe->apply(src, equalized_clahe);cv::imshow("Original Grayscale", src);cv::imshow("Global Histogram Equalization", equalized_global);cv::imshow("CLAHE", equalized_clahe);cv::waitKey(0);cv::destroyAllWindows();return 0;
}
參數解析:
-
cv::equalizeHist(src, dst)
:src
: 輸入8位單通道圖像 (灰度圖)。dst
: 輸出均衡化后的圖像。
-
cv::createCLAHE(clipLimit, tileGridSize)
:clipLimit
: 對比度限制。較高的值允許更大的對比度。如果噪聲是問題,可以減小它。默認40.0。tileGridSize
: 將圖像分割成的小塊(tile)的網格尺寸。例如cv::Size(8,8)
表示 8x8 的小塊。在每個小塊內進行直方圖均衡化。
注意事項:
cv::equalizeHist()
是全局操作,可能會導致某些區域的對比度過度增強,并放大噪聲。CLAHE
是局部操作,將圖像分成小塊,在每個小塊內進行直方圖均衡化,然后通過雙線性插值拼接,通常效果更好,能有效限制對比度放大,減少噪聲。CLAHE
的clipLimit
和tileGridSize
參數需要根據圖像內容調整。- 這些操作通常用于灰度圖像。若要用于彩色圖像,可以先轉換到如 HSV 或 Lab 等顏色空間,對亮度通道 (V 或 L) 進行均衡化,然后再轉換回 BGR。
8. 總結與建議
圖像預處理是一個實驗性很強的過程,沒有萬能的方法。
- 理解你的數據: 分析圖像的特點(噪聲類型、光照條件、尺寸變化等)。
- 明確你的目標: 預處理的目的是服務于后續任務。不同的任務可能需要不同的預處理組合。
- 參數調整: 大多數預處理函數的參數對結果影響顯著,需要耐心調試和比較。
- 順序問題: 預處理步驟的順序也很重要。例如,通常先去噪再進行邊緣檢測或閾值化。
- 可視化: 始終可視化每一步預處理的結果,以便直觀判斷效果。
- 適度原則: 過度的預處理可能會丟失有用信息。
從這些基礎操作開始,你可以構建復雜的預處理流水線來應對各種計算機視覺挑戰。祝你在 OpenCV 的學習和應用中取得成功!