前言
基于opencv的c++接口,实现常用的图像二值化方法,包括了最大类间方差法(OTSU)、固定化阈值以及自适应阈值。
相关的opencv接口解析
CV_EXPORTS_W double threshold( InputArray src, OutputArray dst,
double thresh, double maxval, int type );
该函数将固定级别的阈值应用于多通道阵列。该函数通常用于从灰度图像中获取双层(二进制)图像(#compare 也可用于此目的)或用于去除噪声,即过滤掉值过小或过大的像素.该函数支持几种类型的阈值。它们由类型参数确定。
此外,特殊值#THRESH_OTSU 或#THRESH_TRIANGLE 可以与上述值之一组合。在这些情况下,该函数使用 Otsu 或 Triangle 算法确定最佳阈值,并使用它代替指定的阈值。
@param src
输入数组(多通道、8 位或 32 位浮点)。
@param dst
与 src 具有相同大小和类型以及相同通道数的输出数组。
@param thresh
阈值。
@param maxval
与 #THRESH_BINARY 和 #THRESH_BINARY_INV 阈值类型一起使用的最大值。
@param type
阈值类型(请参阅#ThresholdTypes)。
@return
如果使用 Otsu 或 Triangle 方法,则计算阈值。
enum ThresholdTypes {
THRESH_BINARY = 0, //!< \f[\texttt{dst} (x,y) = \fork{\texttt{maxval}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
THRESH_BINARY_INV = 1, //!< \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{maxval}}{otherwise}\f]
THRESH_TRUNC = 2, //!< \f[\texttt{dst} (x,y) = \fork{\texttt{threshold}}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
THRESH_TOZERO = 3, //!< \f[\texttt{dst} (x,y) = \fork{\texttt{src}(x,y)}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{0}{otherwise}\f]
THRESH_TOZERO_INV = 4, //!< \f[\texttt{dst} (x,y) = \fork{0}{if \(\texttt{src}(x,y) > \texttt{thresh}\)}{\texttt{src}(x,y)}{otherwise}\f]
THRESH_MASK = 7,
THRESH_OTSU = 8, //!< flag, use Otsu algorithm to choose the optimal threshold value
THRESH_TRIANGLE = 16 //!< flag, use Triangle algorithm to choose the optimal threshold value
};
CV_EXPORTS_W void adaptiveThreshold( InputArray src, OutputArray dst,
double maxValue, int adaptiveMethod,
int thresholdType, int blockSize, double C );
对数组应用自适应阈值。该函数根据公式将灰度图像转换为二值图像:
-
THRESH_BINARY
\f[dst(x,y) = \fork{\texttt{maxValue}}{如果 (src(x,y) > T(x,y))}{0}{否则}\f] -
THRESH_BINARY_INV
\f[dst(x,y) = \fork{0}{如果 (src(x,y) > T(x,y))}{\texttt{maxValue}}{否则}\f]
其中 \f
KaTeX parse error: Undefined control sequence: \f at position 7: T(x,y)\̲f̲
是为每个像素单独计算的阈值(请参阅 AdaptiveMethod 参数)。
该函数可以就地处理图像。
@param src
源 8 位单通道图像。
@param dst
与 src 大小和类型相同的目标图像。
@param maxValue
分配给满足条件的像素的非零值
@param AdaptiveMethod
要使用的自适应阈值算法,请参阅#AdaptiveThresholdTypes。
#BORDER_REPLICATE | #BORDER_ISOLATED 用于处理边界。
@param thresholdType
阈值类型,必须是#THRESH_BINARY 或#THRESH_BINARY_INV,请参阅#ThresholdTypes。
@param blockSize
用于计算像素阈值的像素邻域的大小:3、5、7 等。
@param C
从平均值或加权平均值中减去常数。通常,它是正数,但也可能为零或负数。
enum AdaptiveThresholdTypes {
/** the threshold value \f$T(x,y)\f$ is a mean of the \f$\texttt{blockSize} \times
\texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$ minus C */
ADAPTIVE_THRESH_MEAN_C = 0,
/** the threshold value \f$T(x, y)\f$ is a weighted sum (cross-correlation with a Gaussian
window) of the \f$\texttt{blockSize} \times \texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$
minus C . The default sigma (standard deviation) is used for the specified blockSize . See
#getGaussianKernel*/
ADAPTIVE_THRESH_GAUSSIAN_C = 1
};
示例代码
binarizate.h
#pragma once
#include <iostream>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
#define PROCESS_IMG_SUCESS 0
#define PROCESS_IMG_FAIL 1
namespace ImgEnhance
{
//二值化
class Binarizate
{
public:
Binarizate() { cout << "Binarizate is being created" << endl; } // 这是构造函数声明
~Binarizate() { cout << "Binarizate is being deleted" << endl; } // 这是析构函数声明
int OTSU(cv::Mat srcImage);// 大律法函数实现
int OtsuBinarizate(cv::Mat srcImage, cv::Mat &dstImage, int maxVal, int threshType);//大律法二值化
int FixedBinarizate(cv::Mat srcImage, cv::Mat &dstImage, int thresh, int maxVal, int threshType);//固定化阈值
int AdaptiveBinarizate(cv::Mat srcImage, cv::Mat &dstImage, int maxVal, int adaptiveMethod, int thresholdType, int blockSize, int constValue);//自适应阈值化
};
}
binarizate.cpp
#include "binarizate.h"
int ImgEnhance::Binarizate::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;
}
// 统计灰度级中每个像素在整幅图像中的个数
for (int i = 0; i < nCols; i++)
{
for (int j = 0; j < nRows; j++)
{
nSumPix[(int)srcImage.at<uchar>(i, j)]++;
}
}
// 计算每个灰度级占图像中的概率分布
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 ImgEnhance::Binarizate::OtsuBinarizate(cv::Mat srcImage, cv::Mat &dstImage, int maxVal, int threshType)
{
if (!srcImage.data || srcImage.channels() != 1)
{
return 1;
}
// 初始化阈值参数
int thresh = OTSU(srcImage);
// 初始化阈值化处理的类型
/* 0: 二进制阈值 1: 反二进制阈值 2: 截断阈值
3: 0阈值 4: 反0阈值*/
//int threshType = 0;
// 预设最大值
//const int maxVal = 255;
// 固定阈值化操作
cv::threshold(srcImage, dstImage, thresh,
maxVal, threshType);
return 0;
}
int ImgEnhance::Binarizate::FixedBinarizate(cv::Mat srcImage, cv::Mat &dstImage, int thresh, int maxVal, int threshType)
{
if (!srcImage.data || srcImage.channels() != 1)
{
return 1;
}
// 初始化阈值参数
//int thresh = 130;
// 初始化阈值化处理的类型
/* 0: 二进制阈值 1: 反二进制阈值 2: 截断阈值
3: 0阈值 4: 反0阈值 8:大均法*/
//int threshType = 0;
// 预设最大值
//const int maxVal = 255;
// 固定阈值化操作
cv::threshold(srcImage, dstImage, thresh,
maxVal, threshType);
return 0;
}
int ImgEnhance::Binarizate::AdaptiveBinarizate(cv::Mat srcImage, cv::Mat &dstImage, int maxVal, int adaptiveMethod, int thresholdType, int blockSize, int constValue)
{
if (!srcImage.data || srcImage.channels() != 1)
{
return 1;
}
// 初始化自适应阈值参数
//int blockSize = 5;
//int constValue = 10;
//const int maxVal = 255;
/* 自适应阈值算法
0:ADAPTIVE_THRESH_MEAN_C
1: ADAPTIVE_THRESH_GAUSSIAN_C
阈值类型
0: THRESH_BINARY
1: THRESH_BINARY_INV */
//int adaptiveMethod = 0;
//int thresholdType = 1;
// 图像自适应阈值操作
cv::adaptiveThreshold(srcImage, dstImage, maxVal, adaptiveMethod, thresholdType, blockSize, constValue);
return 0;
}
test.cpp
#include"binarizate.h"
ImgEnhance::Binarizate ImgB;//二值化
int main()
{
// 读取源图像及判断
cv::Mat srcImage = cv::imread("flower.jpg");
if (!srcImage.data)
{
return 1;
}
/*cv::namedWindow("原始图", 0);
cv::imshow("原始图", srcImage);*/
// 转化为灰度图像
cv::Mat srcGray;
if (srcImage.channels() == 3)
{
cv::cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);
}
else
{
srcGray = srcImage.clone();
}
cv::namedWindow("灰度图", 0);
cv::imshow("灰度图", srcGray);
//最大类间方差二值化(OTSU)
Mat otsuImage;
const int maxVal = 255;
int threshType = 0;
// 初始化阈值化处理的类型
/* 0: 二进制阈值 1: 反二进制阈值 2: 截断阈值
3: 0阈值 4: 反0阈值*/
ImgB.OtsuBinarizate(srcGray, otsuImage, maxVal, threshType);
cv::namedWindow("otsu二值化图", 0);
cv::imshow("otsu二值化图", otsuImage);
//固定化阈值
Mat fixedImage;
int thresh = 100;
int threshType2 = 0;
ImgB.FixedBinarizate(srcGray, fixedImage, thresh, maxVal, threshType2);//固定化阈值
cv::namedWindow("固定阈值二值化图", 0);
cv::imshow("固定阈值二值化图", fixedImage);
//自适应阈值化
// 初始化自适应阈值参数
Mat adaptiveImage;
int blockSize = 5;
int constValue = 10;
//const int maxVal = 255;
/* 自适应阈值算法
0:ADAPTIVE_THRESH_MEAN_C
1: ADAPTIVE_THRESH_GAUSSIAN_C
阈值类型
0: THRESH_BINARY
1: THRESH_BINARY_INV */
int adaptiveMethod = ADAPTIVE_THRESH_GAUSSIAN_C;
int thresholdType = 0;
ImgB.AdaptiveBinarizate(srcGray, adaptiveImage, maxVal, adaptiveMethod, thresholdType, blockSize, constValue);
cv::namedWindow("自适应阈值-高斯二值化图", 0);
cv::imshow("自适应阈值-高斯二值化图", adaptiveImage);
cv::waitKey(0);
return 0;
}
结果展示
版权声明:本文为qq_40118285原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。