• OpenCV2:小学篇 图像灰度变换技术-阈值化处理


    一.简介

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

    五.双阈值

    六.半阈值

  • 相关阅读:
    token原理
    1.系统代码读取配置文件
    redis hash怎么用
    那么都数据库表,那么多不同记录。是怎样都存储在一个key-value数据库的?
    jedis操作redis全指南
    redis列表list
    jedis操作
    redis
    android raw与assets资源
    Zoie Merge Policy
  • 原文地址:https://www.cnblogs.com/k5bg/p/11103009.html
Copyright © 2020-2023  润新知