有時候由於拍照時光線不均,所以影像每個區域的灰階值基準不同,這時很難找到一個閾值能適用整張影像,然後得到良好的二值化結果,這時我們可以將影像分成幾個區域,每個區域有各自的閾值,再分別將各個區域進行二值化,OpenCV用adaptiveThreshold()函式來進行此作法。


OpenCV調整閾值

void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)

  • src:輸入圖,只能輸入8位元單通道圖。
  • dst:輸出圖,尺寸大小、深度會和輸入圖相同。
  • maxValue:最大值,adaptiveThreshold會將像素分成0和maxValue。
  • adaptiveMethod:區域閾值方法:可以選擇ADAPTIVE_THRESH_MEAN_C或ADAPTIVE_THRESH_GAUSSIAN_C,兩者決定閾值的方式不同。
  • thresholdType:二值化型態:有THRESH_BINARY和THRESH_BINARY_INV兩種型態可選。
  • blockSize:區域尺寸,用幾個像素來決定閾值,只能選擇奇數像3、5、7……等。
  • C:常數,計算閾值時,要從平均或加權平均減去的數。

adaptiveMethod:

  • ADAPTIVE_THRESH_MEAN_C:閾值為blockSize*blockSize像素內的平均減去C。
  • ADAPTIVE_THRESH_GAUSSIAN_C:閾值為blockSize*blockSize像素內的高斯加權平均減去C。

thresholdType:

  • THRESH_BINARY:超過閾值的像素設為maxvalue,小於閾值的設為0。
  • THRESH_BINARY_INV:超過閾值的像素設為0,小於閾值的設為maxvalue。

以下示範adaptiveThreshold的使用,並和otsu的結果做比較:

#include <cstdio>
#include <opencv2/opencv.hpp>
using namespace cv;

int main(){
Mat src = imread("test.jpg",CV_LOAD_IMAGE_GRAYSCALE);
Mat dst1;
Mat dst2;
threshold(src, dst1, 150, 255, THRESH_BINARY|THRESH_OTSU);
adaptiveThreshold(src, dst2, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 65, 0);
imshow("origin", src);
imshow("threshold1", dst1);
imshow("threshold2", dst2);
waitKey(0);

return 0;
}