一.简介
在处理图像中,二值化图像(只含灰度值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;
}
三.固定阈值
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;
}
五.双阈值
六.半阈值