OpenCV2:小学篇 图像灰度变换技术-阈值化处理

一.简介

在处理图像中,二值化图像(只含灰度值0或1)比灰度图像和彩色图像的计算速度最快

一副图像包括目标背景噪声等想要提取目标物体,通常是采用灰度变换的阈(yu)值化操作

图像的阈值化操作就是将图像像素点分布规律,设定阈值进行像素点分割,进而得到图像的二值图像

 

图像阈值化的方法有:经典OTSU 固定阈值 自适应阈值 双阈值 半阈值 操作

 

二.OTSU阈值化

OTSU算法是在1979年提出的一种寻找图像阈值的最大类间方差算法

 

OTSU算法的步骤:

(1) 统计灰度级中每个像素在整幅图像中的个数

(2) 计算每个像素在整幅图像的概率分布

(3) 对灰度级进行遍历搜索,计算当前灰度值下前景背景类间概率

(4) 通过目标函数计算出类内与类间方差下对应的阈值

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

 

 

 

五.双阈值

 

六.半阈值

 

posted @ 2019-06-28 15:38  言午丶  阅读(679)  评论(0编辑  收藏  举报