OpenCV--022: 图像滤波的边界填充

OpenCV中提供的图像滤波边沿处理方式有:

//! Various border types, image boundaries are denoted with `|`
//各种边界类型,图像边界使用“|”作为标记
//! @see borderInterpolate, copyMakeBorder
enum BorderTypes {
    //!< `iiiiii|abcdefgh|iiiiiii`  with some specified `i`
    BORDER_CONSTANT    = 0, 
    
    //!< `aaaaaa|abcdefgh|hhhhhhh`
    BORDER_REPLICATE   = 1, 
    
    //!< `fedcba|abcdefgh|hgfedcb`
    BORDER_REFLECT     = 2,
    
    //!< `cdefgh|abcdefgh|abcdefg`
    BORDER_WRAP        = 3, 
    
    //!< `gfedcb|abcdefgh|gfedcba`
    BORDER_REFLECT_101 = 4, 
    
    //!< `uvwxyz|abcdefgh|ijklmno`
    BORDER_TRANSPARENT = 5, 
    
    //!< same as BORDER_REFLECT_101
    BORDER_REFLECT101  = BORDER_REFLECT_101,
    
     //!< same as BORDER_REFLECT_101
    BORDER_DEFAULT     = BORDER_REFLECT_101, 
    
    //!< do not look outside of ROI
    BORDER_ISOLATED    = 16 
};

在这里插入图片描述

图像边沿的填充相关方法

borderInterpolate

  • 说明
    计算外推像素的源位置。

    当使用指定的外推边框模式时,该函数计算并返回与指定的外推像素对应的像素在原图中的坐标。例如,如果您在水平方向上使用cv :: BORDER_WRAP模式,而在垂直方向上使用cv :: BORDER_REFLECT_101,并要计算目标图像img中Point(-5,100)对应原图像的坐标,看起来像:

    float val = img.at<float>(borderInterpolate(100, img.rows, cv::BORDER_REFLECT_101),borderInterpolate(-5, img.cols, cv::BORDER_WRAP)); 
    

    通常,不直接调用该函数。它在滤波函数以及copyMakeBorder中使用。

  • 函数声明

     int borderInterpolate(int p, int len, int borderType);
    
  • 函数参数

    p沿一个轴的外推像素的从0开始的坐标,可能为<0或> = len
    len数组沿相应组的长度
    borderType边框类型,一个BorderTypes,除了BORDER_TRANSPARENT和BORDER_ISOLATED。当borderType == BORDER_CONSTANT时,无论p和len如何,该函数始终返回-1。
copyMakeBorder

  • 函数说明
    函数将原图像赋值到目标图像中间。被复制的原图像的上,下,左,右区域将被填充像素值。

    当src已经在dst中间时,函数支持该模式。在这种情况下,函数不会复制src本身,而只是构造边界。

    当源图像是较大图像的一部分(roi)时,函数将尝试使用roi区域之外的像素来形成边框。若要禁用此功能并始终进行边框填充,就像src不是roi一样,使用bordertype

  • 函数声明区域从左到右,

    void copyMakeBorder(InputArray src, 
                      OutputArray dst,
                      int top, 
                      int bottom, 
                      int left, 
                      int right,
                      int borderType, 
                      const Scalar& value = Scalar() );
    
  • 函数参数

    src原图像
    dst与src类型相同的目标图像,图像尺寸Size(src.cols+left+right,src.rows+top+bottom)
    top上方像素
    bottom下方像素
    left左侧像素
    right右侧像素,指定源图像矩形中每个方向上的像素数的填充行数。例如,top=1,bottom=1,left=1,right=1表示1像素宽的边框需要被建造。
    borderType边框类型
    value当borderType值等于BORDER_CONSTANT时,指定边填充的值。

在这里插入图片描述

  • 首先创建一个5×5的图像矩阵:
    Mat myImage(Size(5, 5), CV_8UC1);
    	myImage.at<uchar>(0, 0) = 1;
    	myImage.at<uchar>(0, 1) = 2;
    	myImage.at<uchar>(0, 2) = 1;
    	myImage.at<uchar>(0, 3) = 4;
    	myImage.at<uchar>(0, 4) = 3;
    
    	myImage.at<uchar>(1, 0) = 1;
    	myImage.at<uchar>(1, 1) = 3;
    	myImage.at<uchar>(1, 2) = 2;
    	myImage.at<uchar>(1, 3) = 3;
    	myImage.at<uchar>(1, 4) = 4;
    
    	myImage.at<uchar>(2, 0) = 5;
    	myImage.at<uchar>(2, 1) = 2;
    	myImage.at<uchar>(2, 2) = 6;
    	myImage.at<uchar>(2, 3) = 8;
    	myImage.at<uchar>(2, 4) = 8;
    
    	myImage.at<uchar>(3, 0) = 5;
    	myImage.at<uchar>(3, 1) = 5;
    	myImage.at<uchar>(3, 2) = 7;
    	myImage.at<uchar>(3, 3) = 0;
    	myImage.at<uchar>(3, 4) = 8;
    
    	myImage.at<uchar>(4, 0) = 5;
    	myImage.at<uchar>(4, 1) = 6;
    	myImage.at<uchar>(4, 2) = 7;
    	myImage.at<uchar>(4, 3) = 8;
    	myImage.at<uchar>(4, 4) = 9;
    	
    
    
    	Mat dstMyImage;
    	
    	cout <<endl<< "  原图像灰度值:" << endl;
    	for (int i = 0; i < 5; i++)
    	{
    		const uchar* p = myImage.ptr<uchar>(i);
    		cout << "  ";
    		for (int j = 0; j < 5; j++)
    		{
    			if (j <= 3) {
    				cout << int(p[j]) << " , ";
    			}
    			else {
    				cout << int(p[j]) << endl;
    			}
    		}
    	}
    
  • BORDER_CONSTANT = 0
    需要设置borderValue指定i的值。
    其实质就是使用指定的值“i”代替边沿像素值进行卷积核操作。
       cout << endl << endl << "  当borderTypes为BORDER_CONSTANT=0时:" << endl;	
       //当borderValue取值为2
       copyMakeBorder(myImage, dstMyImage, 3, 3, 3, 3, 0,2);
       for (int i = 0; i < dstMyImage.rows; i++)
       {
       	cout << "  ";
       	const uchar* p = dstMyImage.ptr<uchar>(i);
       	for (int j = 0; j < dstMyImage.cols; j++)
       	{
       		if (j < dstMyImage.cols - 1) {
       			cout << int(p[j]) << " , ";
       		}
       		else {
       			cout << int(p[j]) << endl;
       		}
       	}
       }
    
    在这里插入图片描述

在这里插入图片描述

  • BORDER_REPLICATE = 1
    复制最近的一行或一列像素并一直延伸至添加边缘的宽度或高度。

    这种方式也就是OpenCV中的中值滤波medianBlur采用的边界处理方式。

    cout << endl << endl << "  当borderTypes为BORDER_REPLICATE=1时:" << endl;	
    	copyMakeBorder(myImage, dstMyImage, 3, 3, 3, 3, 1);
    	for (int i = 0; i < dstMyImage.rows; i++)
    	{
    		cout << "  ";
    		const uchar* p = dstMyImage.ptr<uchar>(i);
    		for (int j = 0; j < dstMyImage.cols; j++)
    		{
    			if (j < dstMyImage.cols - 1) {
    				cout << int(p[j]) << " , ";
    			}
    			else {
    				cout << int(p[j]) << endl;
    			}
    		}
    	}
    

    在这里插入图片描述

    在这里插入图片描述

  • BORDER_REFLECT = 2
    反射复制边界

    cout << endl << endl << "  当borderTypes为BORDER_REFLECT=2时:" << endl;	
    	copyMakeBorder(myImage, dstMyImage, 3, 3, 3, 3, 2);
    	for (int i = 0; i < dstMyImage.rows; i++)
    	{
    		cout << "  ";
    		const uchar* p = dstMyImage.ptr<uchar>(i);
    		for (int j = 0; j < dstMyImage.cols; j++)
    		{
    			if (j < dstMyImage.cols - 1) {
    				cout << int(p[j]) << " , ";
    			}
    			else {
    				cout << int(p[j]) << endl;
    			}
    		}
    	}
    

    在这里插入图片描述
    在这里插入图片描述
    发现上述结果不便于查找规律,扩大边界值:

    copyMakeBorder(myImage, dstMyImage, 5, 5, 5, 5, 2);
    在这里插入图片描述

    在这里插入图片描述

  • BORDER_WRAP = 3

    cout << endl << endl << "  当borderTypes为BORDER_WRAP=3时:" << endl;	
    	copyMakeBorder(myImage, dstMyImage, 3, 3, 3, 3, 3);
    	for (int i = 0; i < dstMyImage.rows; i++)
    	{
    		cout << "  ";
    		const uchar* p = dstMyImage.ptr<uchar>(i);
    		for (int j = 0; j < dstMyImage.cols; j++)
    		{
    			if (j < dstMyImage.cols - 1) {
    				cout << int(p[j]) << " , ";
    			}
    			else {
    				cout << int(p[j]) << endl;
    			}
    		}
    	}
    

    在这里插入图片描述
    将边界填充行扩大一些看,便于观察。

    copyMakeBorder(myImage, dstMyImage, 5, 5, 5, 5, 3);
    在这里插入图片描述

在这里插入图片描述

  • BORDER_REFLECT_101 = 4
    以边界为对称轴反射复制像素,也就是以最边缘像素为轴,对称。

    这种方式也是OpenCV边界处理的默认方式:(BORDER_DEFAULT=BORDER_REFLECT_101)

    是filter2D,blur,GaussianBlur,bilateralFilter的默认处理方式,所以这种方式在边界处理中应用还是非常广泛的。

    cout << endl << endl << "  当borderTypes为BORDER_REFLECT_101=4时:" << endl;	
    copyMakeBorder(myImage, dstMyImage, 3, 3, 3, 3, 4);
    for (int i = 0; i < dstMyImage.rows; i++)
    {
    	cout << "  ";
    	const uchar* p = dstMyImage.ptr<uchar>(i);
    	for (int j = 0; j < dstMyImage.cols; j++)
    	{
    		if (j < dstMyImage.cols - 1) {
    			cout << int(p[j]) << " , ";
    		}
    		else {
    			cout << int(p[j]) << endl;
    		}
    	}
    }
    
    

    在这里插入图片描述

    将边界填充行扩大一些看,便于观察。

    copyMakeBorder(myImage, dstMyImage, 5, 5, 5, 5, 4);
    在这里插入图片描述

    在这里插入图片描述

  • BORDER_TRANSPARENT = 5

    cout << endl << endl << "  当borderTypes为BORDER_TRANSPARENT=5时:" << endl;	
    	copyMakeBorder(myImage, dstMyImage, 3, 3, 3, 3, 5);
    	for (int i = 0; i < dstMyImage.rows; i++)
    	{
    		cout << "  ";
    		const uchar* p = dstMyImage.ptr<uchar>(i);
    		for (int j = 0; j < dstMyImage.cols; j++)
    		{
    			if (j < dstMyImage.cols - 1) {
    				cout << int(p[j]) << " , ";
    			}
    			else {
    				cout << int(p[j]) << endl;
    			}
    		}
    	}
    

    在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值