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;
}
复制代码

 

 

 

五.双阈值

 

六.半阈值

 

posted @   言午丶  阅读(702)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示