opencv实战从0到N (11)—— 阈值化分割

opencv实战从0到N (11)—— 阈值化分割

 

阈值化操作在图像处理中是一种常用的算法,opencv也有很多种不同的算法接口可以使用。

1、直接阈值化——cv::threshold()

阈值化操作的基本思想是,给定原图像和一个阈值,图像中每个元素与阈值之间的大小比较做出相应的二值操作。opencv3中支持这一操作的接口是cv::threshold(),具体调用方法如下:

 

double cv::threshold(

cv::InputArray src, // 输入图像

cv::OutputArray dst, // 输出图像

double thresh, // 阈值

double maxValue, // 向上最大值

int thresholdType // 阈值化操作的类型

);

 

另外,在opencv3中还支持一种特殊的阈值化操作方式,即Otsu算法。该算法的主要思想是,在进行阈值化时,考虑所有可能的阈值,分别计算低于阈值和高于阈值像素的方差,使下式最小化的值作为阈值:

但是,直接阈值化操作对于亮度分布差异较大的图像,常常无法找到一个合适的阈值。针对于上述情况,需要一种改进的阈值化算法,即自适应阈值化。

 

2、自适应阈值化——cv::adaptiveThreshold()

自适应阈值化能够根据图像不同区域亮度分布的,改变阈值,具体调用方法如下:

void cv::adaptiveThreshold(
cv::InputArray src, // 输入图像
cv::OutputArray dst, // 输出图像
double maxValue, // 向上最大值
int adaptiveMethod, // 自适应方法,平均或高斯
int thresholdType // 阈值化类型
int blockSize, // 块大小
double C // 常量
);

cv::adaptiveThreshold()支持两种自适应方法,即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。

 

测试代码如下:

void test_adaptive_threshold()
{
cv::Mat src = cv::imread("chessboard.png", cv::IMREAD_GRAYSCALE);
cv::Mat dst;


int maxVal = 255;
int blockSize = 41;
double C = 0;
cv::adaptiveThreshold(src, dst, maxVal, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, C);


cv::imshow("threshold", dst);
cv::waitKey(0);


return;
}

 

3、最大稳定极值区域——Maximally Stable Extremal Regions

 

区域特征提取MSER,出自论文J.Matas. “Robust Wide Baseline Stereo from Maximally Stable Extremal Regions”,BMVC2002

MSER = Maximally Stable Extremal Regions

目前业界认为是性能最好的仿射不变区域,MSER是当使用不同的灰度阈值对图像进行二值化时得到的最稳定的区域,特点:

1.对于图像灰度的仿射变化具有不变性

2.稳定性,区域的支持集相对灰度变化稳定

3.可以检测不同精细程度的区域

MSER提取过程

1.使用一系列灰度阈值对图像进行二值化处理

2.对于每个阈值得到的二值图像,得到相应的黑色区域与白色区域

3.在比较宽的灰度阈值范围内保持形状稳定的区域就是MSERs

4.评判标准: dA/dt

A: 二值图像区域面积,t: 灰度阈值

 

给出网上的一段代码参考:

std::vector<cv::Rect>mserGet(cv::Mat image, cv::Mat image2)
{
	cv::Mat gray, gray_neg;
	//灰度转换
	cv::cvtColor(image, gray, CV_BGR2GRAY);
	//取反值灰度
	gray_neg = 255 - gray;
	std::vector<std::vector<cv::Point> > regcontours;
	std::vector<std::vector<cv::Point> > charcontours;
	// 创建MSER对象  
	//表示灰度值的变化量,检测到的组块面积的范围,最大的变化率,最小的变换量 
	cv::Ptr<cv::MSER> mesr1 = cv::MSER::create(2, 50, 1200, 0.6, 0.3);
	//cv::Ptr<cv::MSER> mesr1 = cv::MSER::create(2, 100, 800, 0.7, 0.3);
	cv::Ptr<cv::MSER> mesr2 = cv::MSER::create(2, 2, 400, 0.1, 0.3);
	std::vector<cv::Rect> box1;
	std::vector<cv::Rect> box2;
	// MSER+ 检测  
	mesr1->detectRegions(gray, regcontours, box1);
	// MSER-操作  
	mesr2->detectRegions(gray_neg, charcontours, box2);
	cv::Mat mserMat = cv::Mat::zeros(image.size(), CV_8UC1);
	cv::Mat mserNegMat = cv::Mat::zeros(image.size(), CV_8UC1);
	for (int i = regcontours.size() - 1; i >= 0; i--)
	{
		// 根据检测区域点生成mser+结果  
		const std::vector<cv::Point>tmp = regcontours[i];
		for (int j = 0; j < tmp.size(); j++)
		{
			cv::Point p = tmp[j];
			mserMat.at<uchar>(p) = 255;
		}
	}
	for (int i = charcontours.size() - 1; i >= 0; i--)
	{
		// 根据检测区域点生成mser-结果  
		const std::vector<cv::Point>tmp = charcontours[i];
		for (int j = 0; j < tmp.size(); j++)
		{
			cv::Point p = tmp[j];
			mserNegMat.at<uchar>(p) = 255;
		}
	}
	// mser结果输出  
	cv::Mat resultMat;
	// mser+与mser-位与操作  
	resultMat = mserMat;// &mserNegMat;
	// 闭操作连接缝隙  
	cv::morphologyEx(resultMat, resultMat, cv::MORPH_CLOSE, cv::Mat::ones(1, 20, CV_8UC1));
	cv::imwrite("temp.jpg", resultMat);
	// 寻找外部轮廓  
	std::vector<std::vector<cv::Point> > contours;
	cv::findContours(resultMat, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
	// 候选区域判断输出  
	std::vector<cv::Rect> candidates;
	for (int i = 0; i < contours.size(); i++)
	{
		// 求解最小外界矩形  
		cv::Rect rect = cv::boundingRect(contours[i]);

		rectangle(image2,Rect(rect.tl().x-10, rect.tl().y - 10,rect.width+15, rect.height + 15),Scalar(255,255,255),1,8,0);
		ExtendRect(gray.cols, gray.rows, rect, 5);
		Mat srcRoi(gray, Rect(rect.tl(), rect.br()));
		Mat t;
		resize(srcRoi, t, cvSize(64, 64));
		string pth = format(".//w//%d.jpg", w_num); w_num++;

		imwrite(pth, t);
		// 宽高比例  
		//double ratio = 1. * rect.width / rect.height;
		 不符合尺寸条件判断  
		//if (rect.height > 30 && ratio > 2 && ratio < 5)
		candidates.push_back(rect);
		//drawContours(image,);
	}
	//imwrite("resault.jpg", image2);
	//imshow("resault", image2);
	return candidates;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Arthur.AI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值