在處理圖像中,二值化圖像(只含灰度值0或1)比灰度圖像和彩色圖像的計算速度最快算法
一副圖像包括目標背景噪聲等想要提取目標物體,一般是採用灰度變換的閾(yu)值化操做函數
圖像的閾值化操做就是將圖像像素點分佈規律,設定閾值進行像素點分割,進而獲得圖像的二值圖像ui
圖像閾值化的方法有:經典OTSU 固定閾值 自適應閾值 雙閾值 半閾值 操做spa
OTSU算法是在1979年提出的一種尋找圖像閾值的最大類間方差算法code
OTSU算法的步驟:blog
(1) 統計灰度級中每一個像素在整幅圖像中的個數string
(2) 計算每一個像素在整幅圖像的機率分佈it
(3) 對灰度級進行遍歷搜索,計算當前灰度值下前景背景類間機率io
(4) 經過目標函數計算出類內與類間方差下對應的閾值opencv
#include <stdio.h> #include <string> #include "opencv2/highgui/highgui.hpp" #include "opencv2/opencv.hpp" using namespace std; using namespace cv; // 大均法函數實現 int OTSU(cv::Mat srcImage) { int nCols = srcImage.cols; int nRows = srcImage.rows; int threshold = 0; // 初始化統計參數 int nSumPix[256]; float nProDis[256]; for (int i = 0; i < 256; i++) { nSumPix[i] = 0; nProDis[i] = 0; } // 統計灰度級中每一個像素在整幅圖像中的個數 int temp; for (int i = 0; i < nRows; i++) { for (int j = 0; j < nCols; j++) { temp = srcImage.at<uchar>(i, j); if((temp < 256) && (temp >= 0)) nSumPix[temp]++; } } // 計算每一個灰度級佔圖像中的機率分佈 for (int i = 0; i < 256; i++) { nProDis[i] = (float)nSumPix[i] / (nCols * nRows); } // 遍歷灰度級 [0, 255],計算出最大類間方差下的閾值 float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp; double delta_max = 0.0; for (int i = 0; i < 256; i++) { // 初始化相關參數 w0 = w1 = u0_temp = u1_temp = u0 = u1 =delta_temp = 0; for (int j = 0; j < 256; j++) { // 背景部分 if (j <= i) { // 當前 i 爲分割閾值,第一類總的機率 w0 += nProDis[j]; u0_temp += j * nProDis[j]; } // 前景部分 else { // 當前 i 爲分割閾值,第一類總的機率 w1 += nProDis[j]; u1_temp += j * nProDis[j]; } } // 分別計算各種的平均灰度 u0 = u0_temp / w0; u1 = u1_temp / w1; delta_temp = (float)(w0 * w1 * pow((u0 - u1), 2)); // 依次找到最大類間方差下的閾值 if(delta_temp > delta_max) { delta_max = delta_temp; threshold = i; } } return threshold; } int main() { // 圖像讀取及判斷 cv::Mat srcImage = cv::imread("a.jpg"); if(!srcImage.data) return 1; // 灰度轉換 cv::Mat srcGray; cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY); cv::imshow("srcGray", srcGray); // 調用OTSU二值化算法獲得閾值 int ostuThreshold = OTSU(srcGray); std::cout << ostuThreshold << std::endl; // 定義輸出結果圖像 cv::Mat otsuResultImage = cv::Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1); // 利用獲得的閾值實現二值化操做 for (int i = 0; i < srcGray.rows; i++) { for (int j = 0; j < srcGray.cols; j++) { // 知足大於閾值ostuThreshold置於255 if (srcGray.at<uchar>(i, j) > ostuThreshold) otsuResultImage.at<uchar>(i, j) = 255; else otsuResultImage.at<uchar>(i, j) = 0; } } cv::imshow("otsuResultImage", otsuResultImage); cv::waitKey(0); return 0; }
opencv提供了閾值化函數threshold(),用在單通道圖像(多通道轉單通道)中固定閾值化處理,獲得二值化灰度圖像
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
- src
源圖像
- dst
輸出圖像
- thresh
表示閾值設置
- maxval
表示預設最大值
- type
表示閾值化處理的類型
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" int main() { // 讀取源圖像及判斷 cv::Mat srcImage = cv::imread("a.jpg"); if (!srcImage.data) return 1; // 轉化爲灰度圖像 cv::Mat srcGray; cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY); cv::imshow("srcGray", srcGray); cv::Mat dstImage; // 初始化閾值參數 int thresh = 130; //初始化閾值處理的類型 /* 0:二進制閾值 1:反二進制閾值 2:截斷閾值 3:0閾值 4:反0閾值 */ int threshType = 0; // 預設最大值 const int maxVal = 255; // 固定閾值化操做 cv::threshold(srcGray, dstImage, thresh, maxVal, threshType); cv::imshow("stdImage", dstImage); cv::waitKey(0); return 0; }
OpenCV提供了自適應閾值化函數adaptiveThreshold()
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" int main() { // 圖像讀取及判斷 cv::Mat srcImage = cv::imread("a.jpg"); if (!srcImage.data) return -1; // 灰度轉換 cv::Mat srcGray; cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY); cv::imshow("srcGray", srcGray); cv::Mat dstImage; // 初始化自適應閾值參數 int blockSize = 5; int constValue = 10; const int maxVal = 255; // 自適應閾值算法 int adaptiveMethod = 0; int thresholdType = 1; // 圖像自適應閾值操做 cv::adaptiveThreshold(srcGray, dstImage, maxVal, adaptiveMethod, thresholdType, blockSize, constValue); cv::imshow("dstImage", dstImage); cv::waitKey(0); return 0; }