OpenCV2:小学篇 图像灰度变换技术-阈值化处理
一.简介
在处理图像中,二值化图像(只含灰度值0或1)比灰度图像和彩色图像的计算速度最快
一副图像包括目标背景噪声等想要提取目标物体,通常是采用灰度变换的阈(yu)值化操作
图像的阈值化操作就是将图像像素点分布规律,设定阈值进行像素点分割,进而得到图像的二值图像
图像阈值化的方法有:经典OTSU 固定阈值 自适应阈值 双阈值 半阈值 操作
二.OTSU阈值化
OTSU算法是在1979年提出的一种寻找图像阈值的最大类间方差算法
OTSU算法的步骤:
(1) 统计灰度级中每个像素在整幅图像中的个数
(2) 计算每个像素在整幅图像的概率分布
(3) 对灰度级进行遍历搜索,计算当前灰度值下前景背景类间概率
(4) 通过目标函数计算出类内与类间方差下对应的阈值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | #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
表示阈值化处理的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #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; }
五.双阈值
六.半阈值
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)