opencv入门(10)--阈值与线性滤波及卷积边缘处理

10.1 引言

图像中的阈值处理是指剔除图像内像素高于阈值或者低于阈值的像素点,从而分离得到需要的特征部分。图像阈值化是图像分割中国的一种常用方法。

滤波利用原有图像的某个像素的周围像素来确定该像素的新像素值,可用来消去噪声以及图像中的不合理的像素点。滤波器主要包括线性滤波器和非线性滤波器,其中线性滤波器包括均值滤波,方框滤波和高斯滤波,非线性的主要是中值滤波。

10.2 阈值类型

下图红色表示一系列值,蓝色为阈值。将以该图介绍一下几种阈值的方式

THRESH_BINARY

阈值二值化

THRESH_BINARY_INV

阈值反二值化

THRESH_TRUNC

截断

THRESH_TOZERO

阈值取零

THRESH_TOZERO_INV

阈值反取零

THRESH_MASK

THRESH_OTSU

大津阈值法

最大类间方差,对直方图有明显波谷的图像效果较好仅支持8位单通道图,阈值寻找
THRESH_TRIANGLE对直方图只有单峰的效果好仅支持8位单通道图,阈值寻找

 10.3 阈值处理cv::threshold()

  • double cv::threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
参数含义
作用将一种颜色空间的图像转换为另一种颜色空间
输入src

原图,只能是CV_8UHE CV_32F类型

dst二值化后的图像
thresh二值化的阈值
maxval二值化过程的最大值,在THRESH_BINARY和THRESH_BINARY_INV两种方法类使用
type二值化方法类型(可集合自动获取阈值)
返回值double

 代码示例:

示例1,五种基本的阈值处理。打开一个窗口显示多个图像:

void imshowMany(string windowName, vector<Mat>images, int imgCols, Size imgSize, int space)
{
	//初始坐标
	Point2i location(0, 0);
	//构造窗口大小
	Mat imgWindow((imgSize.height + space) * ((images.size() - 1) / imgCols + 1) - space,
		(imgSize.width + space) * imgCols - space, images[0].type());
	//贴图
	for (int i = 0; i < images.size(); i++)
	{
		location.x = (i%imgCols)*imgSize.width + (i%imgCols)*space;
		location.y = (i / imgCols)*imgSize.height + (i / imgCols)*space;
		images[i].copyTo(imgWindow(Rect(location,imgSize)));
	}

	//显示图像集合
	imshow(windowName, imgWindow);
}

Mat src, gray, binaryImg, binaryInvImg,truncImg,tozeroImg,tozeroInvImg;
int thresholdValue = 127;
int thresholdMax = 255;
const char* outputWin = "output";
//拉动跟踪条改变阈值
void thresholdBack(int, void*)
{
	cvtColor(src, gray, COLOR_BGR2GRAY);
	threshold(gray, binaryImg, thresholdValue, thresholdMax,THRESH_BINARY);
	threshold(gray, binaryInvImg, thresholdValue, thresholdMax, THRESH_BINARY_INV);
	threshold(gray, truncImg, thresholdValue, thresholdMax, THRESH_TRUNC);
	threshold(gray, tozeroImg, thresholdValue, thresholdMax, THRESH_TOZERO);
	threshold(gray, tozeroInvImg, thresholdValue, thresholdMax, THRESH_TOZERO_INV);

	vector<Mat> images{ gray, binaryImg, binaryInvImg,truncImg,tozeroImg,tozeroInvImg};
	Size imgSize = gray.size();
	imshowMany(outputWin, images, 3, imgSize, 10);
}
int main(int argc, char** argv)
{
	src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	namedWindow(outputWin, WINDOW_AUTOSIZE);
	createTrackbar("thresholdValue:",outputWin,&thresholdValue,thresholdMax, thresholdBack);
	thresholdBack(0,0);


	waitKey(0);
	return 0;
}

 示例2:通过THRESH_OTSU和THRESH_TRIANGLE自动查找阈值

int main(int argc, char** argv)
{
	src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	cvtColor(src, gray, COLOR_BGR2GRAY);
	Mat OtsuImg, TriangleImg;
	threshold(gray, OtsuImg,0, 255, THRESH_BINARY|THRESH_OTSU);
	threshold(gray, TriangleImg, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
	imshow("OtsuImg", OtsuImg);
	imshow("TriangleImg", TriangleImg);

	waitKey(0);
	return 0;
}

10.4 自定义线性滤波

10.4.1 卷积概念

卷积是卷积核(kernel)在图像中的每个像素的操作;kernel本质上是一个固定大小的矩阵数组,通常将其中心称为锚点(anchor point)。计算与卷积核重叠区域一一对应的乘积和重新赋值到与锚点重叠的像素。

H(x,y)=\sum_{i=0}^{M_i{}-1}\sum_{j=0}^{M_j{}-1}I(x+i-a_i{},y+j-a_j{})K(i,j)

Sum = 8x1+6x1+6x1+2x1+8x1+6x1+2x1+2x1+8x1 各乘积相加

New pixel = sum / (m*n) 取平均值

 卷积的作用:模糊图像,提取边缘,图像增锐化等;

10.4.2 常见算子

Robert算子

	Mat robertX, robertY;
	//x向
	Mat kernelx = (Mat_<int>(2, 2) << 1, 0, 0, -1);
	filter2D(src, robertX, -1, kernelx, Point(-1, -1),0.0);
	//y向
	Mat kernely = (Mat_<int>(2, 2) << 0, 1, -1, 0);
	filter2D(src, robertY, -1, kernely, Point(-1, -1),0.0);

 Sobel算子

 

	Mat sobelX, sobelY;
	//x向
	Mat kernelx = (Mat_<int>(3, 3) << -1, 0,1,-2,0,2,-1, 0, 1);
	filter2D(src, sobelX, -1, kernelx, Point(-1, -1),0.0);
	//y向
	Mat kernely = (Mat_<int>(3, 3) <<-1, -2, -1, 0,0,0,1,2,1);
	filter2D(src, sobelY, -1, kernely, Point(-1, -1),0.0);

拉普拉斯(Laplace)算子

	Mat Laplace;
	//x向
	Mat kernel = (Mat_<int>(3, 3) << 0, -1,0,-1,4,-1,0, -1, 0);
	filter2D(src, Laplace, -1, kernelx, Point(-1, -1),0.0);

 10.4.3 自定义渐进模糊

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	
	Mat dst;
	/// 初始化滤波器参数
	Point anchor = Point(-1, -1);
	double delta = 0;

	/// 循环 - 每隔0.5秒,用一个不同的核来对图像进行滤波
	int c;
	int ind = 0;
	while (true)
	{
		c = waitKey(500);
		/// 按'ESC'可退出程序
		if ((char)c == 27)
		{
			break;
		}

		/// 更新归一化块滤波器的核大小
		int kernelSize = 3 + 2 * (ind % 5);
		Mat kernel = Mat::ones(kernelSize, kernelSize, CV_32F) / (float)(kernelSize*kernelSize);

		/// 使用滤波器
		filter2D(src, dst, -1, kernel, anchor, delta, BORDER_DEFAULT);
		imshow("auto blur", dst);
		ind++;
	}

	waitKey(0);
	return 0;
}

10.5 卷积边缘处理

       图像通过卷积后,由于卷积核是有大小的,原图的边界像素无法被卷积操作,如3*3滤波时边缘有一个像素无法被处理,5*5滤波时有2个像素没有被处理。

10.5.1 处理卷积边缘

       在卷积操作之前对原图进行边界扩充,填充的像素值为0或RGB黑色,比如需进行3*3滤波时,给原图四周各增加1个像素的边缘,确保图像边缘可以被卷积核覆盖。opencv中默认的处理方式是:BORDER_DEFAULT(在滤波的API中已有该参数)。常用的有以下几种:

  1. BORDER_DEFAULT ——将最近的像素进行映射
  2. BORDER_CONSTANT——用指定像素值填充边缘
  3. BORDER_REPLICATE——用已知的边缘像素值填充边缘
  4. BORDER_WRAP——用另外一边的像素来补偿填充

此外,除了在卷积API中进行定义,还可以自主对图像进行边缘扩充。opencv提供了cv::copyMakeBorder给图像增加边缘。

  • double cv::copyMakeBorder(Mat src, Mat dst, int top,int bottom, int left, int right, int borderType, Scalar value)
参数含义
作用给图像增加边缘
输入src

原图

dst添加边缘后的图像
top边缘上宽度,一般上下左右一样
bottom边缘下宽度
left边缘左宽度
right边缘右宽度
borderType

边缘类型:

BORDER_DEFAULT;

BORDER_CONSTANT=0;常量

BORDER_REPLICATE=1;也就是复制最边缘像素

BORDER_REFLECT=2;对称法,以最边缘像素为轴,对称复制

BORDER_WRAP=3;用另外一边像素填充

value当使用BORDER_CONSTANT时,设置的要填充的像素值
type二值化方法类型(可集合自动获取阈值)
返回值double

10.5.2 代码示例

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);

	int top = (int)(0.05*src.rows);
	int bottom = (int)(0.05*src.rows);
	int left = (int)(0.05*src.cols);
	int right = (int)(0.05*src.cols);

	Mat DefaultImg, ConstantImg, RepalcateImg, ReflectImg, WrapImg;
	copyMakeBorder(src, DefaultImg,top,bottom,left,right,BORDER_DEFAULT,Scalar(0,0,255));
	copyMakeBorder(src, ConstantImg, top, bottom, left, right, BORDER_CONSTANT, Scalar(0, 0, 255));
	copyMakeBorder(src, RepalcateImg, top, bottom, left, right, BORDER_REPLICATE, Scalar(0, 0, 255));
	copyMakeBorder(src, ReflectImg, top, bottom, left, right, BORDER_REFLECT, Scalar(0, 0, 255));
	copyMakeBorder(src, WrapImg, top, bottom, left, right, BORDER_WRAP, Scalar(0, 0, 255));

	imshow("DefaultImg", DefaultImg); 
	imshow("ConstantImg", ConstantImg);
	imshow("RepalcateImg", RepalcateImg);
	imshow("ReflectImg", ReflectImg);
	imshow("WrapImg", WrapImg);

	waitKey(0);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值