一.简介
在处理图像中,二值化图像(只含灰度值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; }