opencv之二值化、感兴趣区域提取笔记

opencv版本: opencv3.4.1

目录

 1. 二值化(阈值化)

1.1 OTSU阈值化

1.2 固定阈值化

1.3 自适应阈值化

1.4 双阈值化

1.5. 半阈值化

2. 感兴趣区域提取


 1. 二值化(阈值化)

 计算复杂度: 二值化图像<灰度图像<彩色图像;

        一幅图像包括目标,背景及噪声,想要直接提取目标物体,需要采用灰度变换阈值化操作;常见的方法有OTSU,固定阈值,自适应阈值,双阈值及半阈值化操作;

1.1 OTSU阈值化

OTSU算法步骤:

(a) 统计灰度级中每个像素在整幅图像中的个数;

(b) 计算每个像素在整幅图像的概率分布;

(c) 对灰度级进行遍历搜索,计算当前灰度值下前景背景类间概率;

(d) 通过目标函数计算出类内与类间方差下对应的阈值;

代码实现:

int OTSU(cv::Mat srcImage )
{
	int cols = srcImage.cols;
	int rows = srcImage.rows;
	int threshold = 0;

	//初始化统计参数
	int nSumPix[256] = {0}; //每个像素在整幅图像中的个数;
	float nProDis[256] = {0};

	memset(nSumPix, 0, sizeof(nSumPix));
	memset(nProDis, 0, sizeof(nProDis));

	//统计灰度级图像中每个像素在增幅图像中的个数;
	for(int i = 0; i < cols; i++){
		for(int j = 0; j < rows; j++){
			nSumPix[(int)srcImage.at<uchar>(i,j)]++;
		}
	}

	//计算每个灰度级占图像中的概率分布
	for(int i = 0; i < 256; i++){
		nProDis[i] = (float)nSumPix[i] / (cols * rows);
	}

	//遍历灰度级[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{ //前景部分
				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;
}

1.2 固定阈值化

double threshold(InputArray _src, OutputArray _dst, double thresh, double maxval, int type)

参数1:源图像

参数2:输出图像

参数3:阈值

参数4:预设最大值;一般为255;

参数5:阈值化处理的类型,取值如下:

enum ThresholdTypes {

     //二进制阈值化;大于thresh的灰度值设定为255,低于thresh设定为0;
    THRESH_BINARY = 0,

     //反二进制阈值化;大于thresh的灰度值设定为0,低于thresh设定为255;   
    THRESH_BINARY_INV = 1, 

     //截断阈值化;大于thresh的灰度值设定为thresh,低于thresh设定为不变; 
    THRESH_TRUNC = 2, 

    //阈值化0;大于thresh的灰度值设定为不变,低于thresh设定为0; 
    THRESH_TOZERO = 3, 

    //反阈值化0;大于thresh的灰度值设定为0,低于thresh设定为不变; 
    THRESH_TOZERO_INV = 4, 
    THRESH_MASK = 7,
    THRESH_OTSU= 8, 
    THRESH_TRIANGLE = 16 
};

int main()
{
    cv::Mat srcImage = cv::imread("./lena.jpg");
	if(srcImage.empty()){
		std::cout << "imread failed" << endl;
		return -1;
	}
	
    //转为灰度图
	cv::Mat grayImage;
	cv::cvtColor(srcImage, grayImage, CV_RGB2GRAY);

	cv::Mat dstImage;
	double thresh = 100.0;
    //二值化, thresh为阈值
	cv::threshold(grayImage, dstImage, thresh, 255, THRESH_BINARY);

	cv::imwrite("./lena_threshold.jpg", dstImage);
}

1.3 自适应阈值化

void cv::adaptiveThreshold( InputArray _src, OutputArray _dst, double maxValue,
                            int method, int type, int blockSize, double delta );

参数1: 输入图像;

参数2:输出图像;

参数3:预设最大值;

参数4:自适应算法选择;取值如下:

        enum AdaptiveThresholdTypes {
            ADAPTIVE_THRESH_MEAN_C     = 0,
            ADAPTIVE_THRESH_GAUSSIAN_C = 1
        };

参数5:阈值类型,同threshold中type;

参数6:邻域块大小,用来计算区域阀值,一般选择3,5,7...

参数7:常数,是一个从均值或加权均值提取的常数;

int main()
{	
	cv::Mat srcImage = cv::imread("./lena.jpg");
	if(srcImage.empty()){
		std::cout << "imread failed" << endl;
		return -1;
	}

	//转为灰度图
	cv::Mat grayImage;
	cv::cvtColor(srcImage, grayImage, CV_RGB2GRAY);

	cv::Mat dstImage;
	cv::adaptiveThreshold(grayImage, dstImage, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 109, 0);

	cv::imwrite("./lena_adaHold.jpg", dstImage);

	return  0;
}

1.4 双阈值化

        对于图像有明显的双分界特征,我们考虑用双阈值法进行二值化操作; 预先设定好特定的阈值量thresh1,thresh2,且thresh1<thresh2; 阈值操作只需要将大于thresh1且大于thresh2的灰度值设定为max_val;其余情况设定为0;

int main()
{	
	cv::Mat srcImage = cv::imread("./lena.jpg");
	if(srcImage.empty()){
		std::cout << "imread failed" << endl;
		return -1;
	}

	//转为灰度图
	cv::Mat grayImage;
	cv::cvtColor(srcImage, grayImage, CV_RGB2GRAY);

	const int maxVal = 255;
	int low_threshold = 109;
	int high_threshold = 210;
	cv::Mat dstTempImage1, dstTempImage2, dstImage;
	
	//小阈值对源灰度图像进行阈值化操作
	cv::threshold(grayImage, dstTempImage1, low_threshold, maxVal, THRESH_BINARY);

	//大阈值对源灰度图像进行阈值化操作
	cv::threshold(grayImage, dstTempImage2, high_threshold, maxVal, THRESH_BINARY_INV);

	//矩阵与运算得到二值化结果
	cv::bitwise_and(dstTempImage1, dstTempImage2, dstImage);
	
	cv::imwrite("./lena_bitwise.jpg", dstImage);

	return  0;
}

1.5. 半阈值化

预先设定好thresh, 半阈值化操作值需要将大于thresh的灰度值设定为不变,将其余情况设定为0; 

int main()
{	
	cv::Mat srcImage = cv::imread("./lena.jpg");
	if(srcImage.empty()){
		std::cout << "imread failed" << endl;
		return -1;
	}

	//转为灰度图
	cv::Mat grayImage;
	cv::cvtColor(srcImage, grayImage, CV_RGB2GRAY);

	const int maxVal = 255;
	int low_threshold = 109;
	cv::Mat dstTempImage, dstImage;
	
	//对源灰度图像进行阈值化操作
	cv::threshold(grayImage, dstTempImage, low_threshold, maxVal, THRESH_BINARY);

	//矩阵与运算得到二值化结果
	cv::bitwise_and(grayImage, dstTempImage, dstImage);
	
	cv::imwrite("./lena_bitwise1.jpg", dstImage);

	return  0;
}

2. 感兴趣区域提取

 实际调用了copyTo函数拷贝指定区域;

int main()
{
    cv::Mat srcImage = cv::imread("./lena.jpg");
	if(srcImage.empty()){
		std::cout << "imread failed" << endl;
		return -1;
	}

	cv::Mat roiImage(srcImage.rows, srcImage.cols, CV_8UC3);

	srcImage(cv::Rect(80, 50, 300, 350)).copyTo(roiImage);

	cv::imwrite("./lena_roi.jpg", roiImage);
}

效果:

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天未及海宽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值