OpenCV2:小學篇 圖像灰度變換技術-閾值化處理

一.簡介

在處理圖像中,二值化圖像(只含灰度值0或1)比灰度圖像和彩色圖像的計算速度最快算法

一副圖像包括目標背景噪聲等想要提取目標物體,一般是採用灰度變換的閾(yu)值化操做函數

圖像的閾值化操做就是將圖像像素點分佈規律,設定閾值進行像素點分割,進而獲得圖像的二值圖像ui

 

圖像閾值化的方法有:經典OTSU 固定閾值 自適應閾值 雙閾值 半閾值 操做spa

 

二.OTSU閾值化

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;
}

 

 

 

五.雙閾值

 

六.半閾值

相關文章
相關標籤/搜索