android opencv中图像分割,opencv在android平台下的开发【4】-图像滤波详解

前言

在上一篇opencv-android-图像平滑处理文章中,简单介绍了几种图像平滑,也就是图像模糊的方法,使用了几个简单的滤波器,这都属于图像的滤波操作。

opencv针对图像的处理提供了imgproc模块,比如图像滤波、几何变换,特征识别等等,本文针对opencv的图像滤波做一个全面的分析。

滤波方法一览

opencv的图像滤波中主要有以下方法,用于对2D图像执行线性/非线性的滤波操作。bilateralFilter:对图像使用双边滤波

blur:使用归一化块滤波器模糊图像

boxFilter:使用箱式滤波器模糊图像

buildPyramid:构建影像高斯金字塔

dilate:使用指定的 structuring element 膨胀图像

erode:使用指定的 structuring element 腐蚀图像

filter2D:使用 kernel 对图像进行卷积

GaussianBlur:使用高斯滤波器模糊图像

getDerivKernels:返回用于计算空间图像导数(spatial image derivatives)的滤波系数

getGaborKernel:返回 Gabor 滤波系数

getGaussianKernel:返回高斯滤波系数

getStructuringElement:返回指定大小和形状的形态学操作的structuring element

Laplacian:计算图像的拉普拉斯算子

medianBlur:使用中值滤波模糊图像

morphologyDefaultBorderValue:为图像膨胀和腐蚀返回“magic”边界值。可以为膨胀操作自动转换为 Scalar::all(-DBL_MAX)。

morphologyEx:执行增强的形态学变换

pyrDown:模糊图像并向下采样

pyrMeanShiftFiltering:执行图像meanshift分割的初始步骤

pyrUp:向上采样,然后模糊图像

Scharr:使用 Scharr 算子计算图像的 X-或者Y-的一阶导数

sepFilter2D:对图像应用可分离的线性滤波器。

Sobel:使用Sobel算子计算图像的一阶、二阶、三阶、混合导数

spatialGradient:使用Sobel算子计算图像X和Y的一阶连续偏导

sqrBoxFilter:计算与滤波器重叠的像素值的归一化平方和

对上述方法根据功能做简单的分类。图像模糊相关:blur、bilateralFilter、boxFilter、GaussianBlur、medianBlur、sqrBoxFilter。

形态学运算相关:dilate、erode、morphologyDefaultBorderValue、morphologyEx

图像金字塔相关:buildPyramid、pyrDown、pyrUp、pyrMeanShiftFiltering

卷积相关:filter2D、sepFilter2D

核/结构元素相关:getDerivKernels、getGaborKernel、getGaussianKernel、getStructuringElement

算子:Laplacian

导数:Scharr、Sobel、spatialGradient

源图像(一般为矩形)中每个位置(x,y)的像素的邻域像素都会被用来计算其结果像素值。使用线性滤波器时,结果像素值时邻域像素的加权和;使用形态学操作时,结果像素值时邻域像素的最大值或者最小值。计算的结果存储在输出图像相应的位置(x,y),输出图像和源图像的大小相同,而且下面这些方法都支持多通道数组,每个通道都会独立处理,所以输出图像和源图像具有相同的通道数。

另外,与简单的算术方法不同,上述方法需要外推一些不存在的像素的值。例如使用高斯3X3滤波器平滑图像,每一行最左侧的像素计算时需要用到左侧的像素值,但是其左侧没有像素了,所以可以另不存在的像素都是零,或者让其与最左侧的像素相同,opencv可以指定外推方法。

方法详解

bilateralFilter

方法声明:

c++void cv::bilateralFilter    (   InputArray      src,

OutputArray    dst,                                     int    d,                                     double     sigmaColor,                                     double     sigmaSpace,                                     int    borderType = BORDER_DEFAULT

)

javapublic static void bilateralFilter(Mat src, Mat dst, int d, double sigmaColor, double sigmaSpace)

{

bilateralFilter_1(src.nativeObj, dst.nativeObj, d, sigmaColor, sigmaSpace);

return;

}

private static native void bilateralFilter_0(long src_nativeObj, long dst_nativeObj, int d, double sigmaColor, double sigmaSpace, int borderType);

private static native void bilateralFilter_1(long src_nativeObj, long dst_nativeObj, int d, double sigmaColor, double sigmaSpace);

给图像应用双边滤波,可以在保留边界的同时很好的减少噪声,但是执行速度比其他滤波器要慢。

该过滤器不是原地工作的。

Sigma 值:简单的话,可以将两个sigma值设为相同。当值比较小(<10)时,看起来没什么效果;当比较大(>150)时,效果比较强,图像看起来像动画片。

Filter size(d):比较大(d>5)时,计算比较慢。所以在实时应用场景下,推荐使用d=5;在离线应用强力过滤噪声时可以将d=9 。src:数据类型为 8-bit 或者 floating-point 的 1-channel(1通道)或者3-channel(3通道)的源图像。

dst:和源图像具有相同大小和类型的目标图像。

d:滤波时像素邻域的直径,非正值,由 sigmaSpace 计算得出。

sigmaColor:颜色空间的滤波 sigma。参数值越大,意味着像素邻域中相距越远的颜色也会融入进来,从而产生更大的半等颜色。

sigmaSpace:坐标空间的滤波 sigma。参数值越大,表示更远的像素之间,只要颜色足够接近(参看sigmaColor),也会彼此影响。当 d=0时,表示邻域的大小忽略sigmaSpace,否则d与sigmaSpace成正比。

borderType:图像边界外像素值的外推模式。

blur

方法声明:

c++void cv::blur   (   InputArray      src,

OutputArray   dst,

Size      ksize,

Point     anchor = Point(-1,-1),    int     borderType = BORDER_DEFAULT

)

javapublic static void blur(Mat src, Mat dst, Size ksize)

{

blur_2(src.nativeObj, dst.nativeObj, ksize.width, ksize.height);

return;

}

private static native void blur_0(long src_nativeObj, long dst_nativeObj, double ksize_width, double ksize_height, double anchor_x, double anchor_y, int borderType);

private static native void blur_1(long src_nativeObj, long dst_nativeObj, double ksize_width, double ksize_height, double anchor_x, double anchor_y);

private static native void blur_2(long src_nativeObj, long dst_nativeObj, double ksize_width, double ksize_height);

使用归一化块滤波器模糊图像,方法平滑图像使用的kernel如下:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

调用方法blur(src, dst, ksize, anchor, borderType)等价于调用方法boxFilter(src, dst, src.type(), anchor, true, borderType)src:输入图像,可以有任意数量的通道,各通道会被独立的处理,但是 depth 要求为 CV_8U,CV_16U,CV_16S,CV_32F,CV_64F。

dest:输出图像,和输入图像有一样的大小和类型。

ksize:模糊核(kernel)大小。

anchor:锚点,默认是Point(-1,-1),表示锚点位于核的中心。

borderType:图像边界外像素值的外推模式。

boxFilter

方法声明:

c++void cv::boxFilter  (   InputArray      src,

OutputArray      dst,                               int      ddepth,

Size     ksize,

Point    anchor = Point(-1,-1),    bool    normalize = true,    int     borderType = BORDER_DEFAULT

)

java//

// C++:  void cv::boxFilter(Mat src, Mat& dst, int ddepth, Size ksize, Point anchor = Point(-1,-1), bool normalize = true, int borderType = BORDER_DEFAULT)

//

//javadoc: boxFilter(src, dst, ddepth, ksize, anchor, normalize, borderType)

public static void boxFilter(Mat src, Mat dst, int ddepth, Size ksize, Point anchor, boolean normalize, int borderType)

{

boxFilter_0(src.nativeObj, dst.nativeObj, ddepth, ksize.width, ksize.height, anchor.x, anchor.y, normalize, borderType);

return;

}    //javadoc: boxFilter(src, dst, ddepth, ksize, anchor, normalize)

public static void boxFilter(Mat src, Mat dst, int ddepth, Size ksize, Point anchor, boolean normalize)

{

boxFilter_1(src.nativeObj, dst.nativeObj, ddepth, ksize.width, ksize.height, anchor.x, anchor.y, normalize);

return;

}    //javadoc: boxFilter(src, dst, ddepth, ksize, anchor)

public static void boxFilter(Mat src, Mat dst, int ddepth, Size ksize, Point anchor)

{

boxFilter_2(src.nativeObj, dst.nativeObj, ddepth, ksize.width, ksize.height, anchor.x, anchor.y);

return;

}    //javadoc: boxFilter(src, dst, ddepth, ksize)

public static void boxFilter(Mat src, Mat dst, int ddepth, Size ksize)

{

boxFilter_3(src.nativeObj, dst.nativeObj, ddepth, ksize.width, ksize.height);

return;

}

// C++:  void cv::boxFilter(Mat src, Mat& dst, int ddepth, Size ksize, Point anchor = Point(-1,-1), bool normalize = true, int borderType = BORDER_DEFAULT)

private static native void boxFilter_0(long src_nativeObj, long dst_nativeObj, int ddepth, double ksize_width, double ksize_height, double anchor_x, double anchor_y, boolean normalize, int borderType);

private static native void boxFilter_1(long src_nativeObj, long dst_nativeObj, int ddepth, double ksize_width, double ksize_height, double anchor_x, double anchor_y, boolean normalize);

private static native void boxFilter_2(long src_nativeObj, long dst_nativeObj, int ddepth, double ksize_width, double ksize_height, double anchor_x, double anchor_y);

private static native void boxFilter_3(long src_nativeObj, long dst_nativeObj, int ddepth, double ksize_width, double ksize_height);

使用 box 滤波器模糊图像,使用的核如下:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

非归一化的box滤波器在计算像素邻域的各种积分特性很有用,例如图像导数的协方差矩阵(用于密集光流算法等)。如果计算可变大小窗口里的像素总和,需要使用积分。src:输入图像。

dst:输入图像,核输入图像有相同的大小和类型。

ddepth:输出图像的depth(值为-1表示使用src.depth())。

ksize:模糊核(kernel)大小。

anchor:锚点,默认是Point(-1,-1),表示锚点位于核的中心。

mormalize:标识,指定kernel是否按其区域归一化。

borderType:图像边界外像素值的外推模式。

buildPyramid

只有C++的实现,暂未提供其他语言接口。

方法声明:

c++void cv::buildPyramid   (   InputArray      src,

OutputArrayOfArrays   dst,                                  int   maxlevel,                                  int   borderType = BORDER_DEFAULT

)

该方法构造一个图像矢量,并通过从 dst[0] == src 开始递归地将 pyrDown(向下采样)应用与先前构建地金字塔图层来构建图像的高斯金字塔。src:源图像。需要满足 pyrDown(向下采样)支持类型地校验。

dst:由 maxlevel+1 个和源图像具有相同类型的图像构成的目标图像矢量,dst[0] 和源图像相同,dst[1]是下一个金字塔图层(经过平滑处理和尺寸缩小)。

maxlevel:金字塔最大层级,非负值,从0开始。

borderType:图像边界外像素值的外推模式。

dilate

方法声明:

c++void cv::dilate     (   InputArray      src,

OutputArray     dst,

InputArray      kernel,

Point   anchor = Point(-1,-1),    int     iterations = 1,    int     borderType = BORDER_CONSTANT,        const Scalar &      borderValue = morphologyDefaultBorderValue()

)

javapublic static void dilate(Mat src, Mat dst, Mat kernel)

{

dilate_4(src.nativeObj, dst.nativeObj, kernel.nativeObj);

return;

}

// C++:  void cv::dilate(Mat src, Mat& dst, Mat kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, Scalar borderValue = morphologyDefaultBorderValue())

private static native void dilate_0(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations, int borderType, double borderValue_val0, double borderValue_val1, double borderValue_val2, double borderValue_val3);

private static native void dilate_1(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations, int borderType);

private static native void dilate_2(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations);

private static native void dilate_3(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y);

private static native void dilate_4(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj);

使用指定的 structuring element 膨胀图像,structuring element用来确定采用最大值的像素邻域的形状。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

该方法支持就地模式。膨胀可以多次(迭代)应用。对于多通道图像,每个通道被单独处理。src:输入图像,通道数可以是任意的,但是 depth 需要是 CV_8U,CV_16U,CV_16S,CV_32F,CV64F 中的一种。

dst:输出图像,和输入图像具有相同的大小和类型。

kernel:膨胀用到的 structuring element,如果 element = Mat(),将会使用 3x3 的矩形 structuring element。 kernel 可以使用 getStructuringElement 方法创建。

anchor:锚点,默认是Point(-1,-1),表示锚点位于核的中心。

iterations:膨胀应用的次数。

borderType:图像边界外像素值的外推模式。

borderValue:当边界为常量时的边界值。

erode

方法声明

c++void cv::erode  (   InputArray      src,

OutputArray      dst,

InputArray   kernel,

Point    anchor = Point(-1,-1),    int     iterations = 1,    int     borderType = BORDER_CONSTANT,        const Scalar &      borderValue = morphologyDefaultBorderValue()

)

javapublic static void erode(Mat src, Mat dst, Mat kernel)

{

erode_4(src.nativeObj, dst.nativeObj, kernel.nativeObj);

return;

}

// C++:  void cv::erode(Mat src, Mat& dst, Mat kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, Scalar borderValue = morphologyDefaultBorderValue())

private static native void erode_0(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations, int borderType, double borderValue_val0, double borderValue_val1, double borderValue_val2, double borderValue_val3);

private static native void erode_1(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations, int borderType);

private static native void erode_2(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations);

private static native void erode_3(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj, double anchor_x, double anchor_y);

private static native void erode_4(long src_nativeObj, long dst_nativeObj, long kernel_nativeObj);

使用指定的 structuring element 腐蚀图像,structuring element用来确定采用最小值的像素邻域的形状。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

该方法支持就地模式。腐蚀可以多次(迭代)应用。对于多通道图像,每个通道被单独处理。src:输入图像,通道数可以是任意的,但是 depth 需要是 CV_8U,CV_16U,CV_16S,CV_32F,CV64F 中的一种。

dst:输出图像,和输入图像具有相同的大小和类型。

kernel:腐蚀用到的 structuring element,如果 element = Mat(),将会使用 3x3 的矩形 structuring element。 kernel 可以使用 getStructuringElement 方法创建。

anchor:锚点,默认是Point(-1,-1),表示锚点位于核的中心。

iterations:膨胀应用的次数。

borderType:图像边界外像素值的外推模式。

borderValue:当边界为常量时的边界值。

filter2D

方法声明:

c++void cv::filter2D   (   InputArray      src,

OutputArray   dst,                              int   ddepth,

InputArray    kernel,

Point     anchor = Point(-1,-1),    double      delta = 0,    int     borderType = BORDER_DEFAULT

)

javapublic static void sepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY)

{

sepFilter2D_3(src.nativeObj, dst.nativeObj, ddepth, kernelX.nativeObj, kernelY.nativeObj);

return;

}

// C++:  void cv::sepFilter2D(Mat src, Mat& dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT)

private static native void sepFilter2D_0(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj, double anchor_x, double anchor_y, double delta, int borderType);

private static native void sepFilter2D_1(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj, double anchor_x, double anchor_y, double delta);

private static native void sepFilter2D_2(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj, double anchor_x, double anchor_y);

private static native void sepFilter2D_3(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj);

使用核(kernel)对图像进行卷积。

该方法可以对图像应用任意的线性滤波器,支持就地操作,当滤波范围部分超出图像时,该方法根据指定的像素外推模式向边界外像素插入值。

该方法实际上时计算的相关性,不是卷积,也就是说,内核不是围绕锚点镜像的,如果需要真正进行卷积,则使用 flip 对内核进行反转,并设置新的锚点为 (kernel.cols - anchor.x - 1, kernel.rows - anchor.y - 1):

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

针对特别大的核(11x11,或者更大),该方法使用基于 DFT-based 的算法;对于小核使用直接算法。src:输入图像

dst:输出图像,核源图像具有相同的大小和通道数。

ddepth:输出图像需要的depth。

kernel:卷积核(或者说是相关核),单通道浮点型矩阵,如果向对不同的通道使用不同的kernel,使用split将图像分割成不同的颜色位面,并分别处理。

anchor:内核锚点,指明内核过滤点的相对位置,锚点应该位于内核中,默认值是(-1,-1),表示锚点位于核的中心。

delta:可选值,在存储到dst之前添加到过滤之后的像素值上。

borderType:图像边界外像素值的外推模式。

GaussianBlur

方法声明:

c++void cv::GaussianBlur   (   InputArray      src,

OutputArray   dst,

Size      ksize,                                  double    sigmaX,                                  double    sigmaY = 0,                                  int   borderType = BORDER_DEFAULT

)

javapublic static void GaussianBlur(Mat src, Mat dst, Size ksize, double sigmaX, double sigmaY, int borderType)

{

GaussianBlur_0(src.nativeObj, dst.nativeObj, ksize.width, ksize.height, sigmaX, sigmaY, borderType);

return;

}

// C++:  void cv::GaussianBlur(Mat src, Mat& dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT)

private static native void GaussianBlur_0(long src_nativeObj, long dst_nativeObj, double ksize_width, double ksize_height, double sigmaX, double sigmaY, int borderType);

private static native void GaussianBlur_1(long src_nativeObj, long dst_nativeObj, double ksize_width, double ksize_height, double sigmaX, double sigmaY);

private static native void GaussianBlur_2(long src_nativeObj, long dst_nativeObj, double ksize_width, double ksize_height, double sigmaX);

使用高斯滤波器模糊图像,使用高斯内核与图像做卷积,支持就地模式。src:输入图像,通道数可以是任意的,但是 depth 需要是 CV_8U,CV_16U,CV_16S,CV_32F,CV64F 中的一种。

dst:输出图像,核源图像具有相同的大小和类型。

ksize:高斯内核的大小,ksize的宽高可以不同,但是必须是正奇数。或者,也可以为零,然后通过sigma计算。

sigmaX:高斯核X方向的标准差。

sigmaY:高斯核Y方向的标准差。如果sigmaY为0,则会被设置为与sigmaX相同;如果两个sigma都是0,则通过ksize的宽和高各自进行计算。如果为了完全控制结果,而不考虑将来可能对所有这些语义进行的修改,建议指定所有的ksize、sigmaX和sigmaY。

borderType:图像边界外像素值的外推模式。

getGaborKernel()

方法声明:

c++Mat cv::getGaborKernel  (   Size    ksize,                                   double   sigma,                                   double   theta,                                   double   lambd,                                   double   gamma,                                   double   psi = CV_PI *0.5,                                   int      ktype = CV_64F

)

java//javadoc: getGaborKernel(ksize, sigma, theta, lambd, gamma, psi, ktype)

public static Mat getGaborKernel(Size ksize, double sigma, double theta, double lambd, double gamma, double psi, int ktype)

{

Mat retVal = new Mat(getGaborKernel_0(ksize.width, ksize.height, sigma, theta, lambd, gamma, psi, ktype));

return retVal;

}    //javadoc: getGaborKernel(ksize, sigma, theta, lambd, gamma, psi)

public static Mat getGaborKernel(Size ksize, double sigma, double theta, double lambd, double gamma, double psi)

{

Mat retVal = new Mat(getGaborKernel_1(ksize.width, ksize.height, sigma, theta, lambd, gamma, psi));

return retVal;

}    //javadoc: getGaborKernel(ksize, sigma, theta, lambd, gamma)

public static Mat getGaborKernel(Size ksize, double sigma, double theta, double lambd, double gamma)

{

Mat retVal = new Mat(getGaborKernel_2(ksize.width, ksize.height, sigma, theta, lambd, gamma));

return retVal;

}

// C++:  Mat cv::getGaborKernel(Size ksize, double sigma, double theta, double lambd, double gamma, double psi = CV_PI*0.5, int ktype = CV_64F)

private static native long getGaborKernel_0(double ksize_width, double ksize_height, double sigma, double theta, double lambd, double gamma, double psi, int ktype);

private static native long getGaborKernel_1(double ksize_width, double ksize_height, double sigma, double theta, double lambd, double gamma, double psi);

private static native long getGaborKernel_2(double ksize_width, double ksize_height, double sigma, double theta, double lambd, double gamma);

返回一个 Gabor 滤波器系数,详细的 gabor 滤波器参见 Gabor Filterksize:返回的滤波器大小。

sigma:高斯包络线的标准差。

theta:Gabor函数的法线到平行条纹的方向。

lambd:正弦因子的波长。

gamma:空间长宽比。

psi:相偏移。

ktype:滤波器系数的类型,可以是 CV_32F 或者 CV_64F。

getGaussianKernel()

方法声明:

c++Mat cv::getGaussianKernel   (   int     ksize,                                      double    sigma,                                      int   ktype = CV_64F

)

java//javadoc: getGaussianKernel(ksize, sigma, ktype)

public static Mat getGaussianKernel(int ksize, double sigma, int ktype)

{

Mat retVal = new Mat(getGaussianKernel_0(ksize, sigma, ktype));

return retVal;

}    //javadoc: getGaussianKernel(ksize, sigma)

public static Mat getGaussianKernel(int ksize, double sigma)

{

Mat retVal = new Mat(getGaussianKernel_1(ksize, sigma));

return retVal;

}

// C++:  Mat cv::getGaussianKernel(int ksize, double sigma, int ktype = CV_64F)

private static native long getGaussianKernel_0(int ksize, double sigma, int ktype);

private static native long getGaussianKernel_1(int ksize, double sigma);

返回一个高斯滤波器系数。

该方法计算并返回ksize×1高斯滤波器系数矩阵:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

生成的两种kernel都可以传递给 sepFilter2D,方法会自动识别 平滑kernel(对称,权重和为1),然后相应的处理。也可以使用相对高层次的高斯模糊(GaoussianBlur)。ksize:孔径大小,正奇数。

sigma:高斯标准差。如果是负数,则使用ksize进行计算 sigma = 0.3*((ksize-1)*0.5 - 1) + 0.8

ktype:滤波器系数类型,CV_32F或者CV_64F。

getStructuringElement()

方法声明:

c++Mat cv::getStructuringElement   (   int     shape,

Size      ksize,

Point     anchor = Point(-1,-1)

)

javapublic static Mat getStructuringElement(int shape, Size ksize)

{

Mat retVal = new Mat(getStructuringElement_1(shape, ksize.width, ksize.height));

return retVal;

}    // C++:  Mat cv::getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1))

private static native long getStructuringElement_0(int shape, double ksize_width, double ksize_height, double anchor_x, double anchor_y);

private static native long getStructuringElement_1(int shape, double ksize_width, double ksize_height);

为形态操作返回指定大小和形状的structuring element,进一步传递给 erode,dilate,morphologyEx。但是也可以自己构造一个任意的二进制掩码,并将其用作structuring element。shape:元素的形状,可以是MorphShape的一种。

ksize:structuring element 的大小。

anchor:element里的锚点,默认值是(-1,-1),表示锚点位于中心。需要注意的是只有交叉形状的元素的形状取决于锚点的位置,否则的话锚点只是调节形态操作的结果移动了多少。

拉普拉斯算子

方法声明:

c++void cv::Laplacian  (   InputArray      src,

OutputArray      dst,                               int      ddepth,                               int      ksize = 1,                               double   scale = 1,                               double   delta = 0,                               int      borderType = BORDER_DEFAULT

)

javapublic static void Laplacian(Mat src, Mat dst, int ddepth)

{

Laplacian_4(src.nativeObj, dst.nativeObj, ddepth);

return;

}

private static native void Laplacian_0(long src_nativeObj, long dst_nativeObj, int ddepth, int ksize, double scale, double delta, int borderType);

private static native void Laplacian_1(long src_nativeObj, long dst_nativeObj, int ddepth, int ksize, double scale, double delta);

private static native void Laplacian_2(long src_nativeObj, long dst_nativeObj, int ddepth, int ksize, double scale);

private static native void Laplacian_3(long src_nativeObj, long dst_nativeObj, int ddepth, int ksize);

private static native void Laplacian_4(long src_nativeObj, long dst_nativeObj, int ddepth);

该方法通过Sobel算子计算源图像二阶x、y导数,然后相加得出源图像的拉普拉斯算子:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

需要注意的是,当 ksize>1 时用上述公式计算拉普拉斯算子;当 ksize=1 时,拉普拉斯算子通过使用3x3的窗口对图片进行滤波得到。

AAffA0nNPuCLAAAAAElFTkSuQmCC

imagesrc:源图像。

dst:输出图像,和源图像具有相同的大小和通道数。

ddepth:输出图像的depth。

ksize:计算二阶导数滤波器的窗口大小,值必须是正奇数。

scale:可选参数,计算拉普拉斯值的缩放因子,默认没有缩放。

delta:可选参数,在计算结果存储到输出图像之前,添加到结果的delta值。

borderType:图像边界外像素值的外推模式。

中值模糊

方法声明:

c++void cv::medianBlur     (   InputArray      src,

OutputArray     dst,                                int     ksize

)

javapublic static void medianBlur(Mat src, Mat dst, int ksize)

{

medianBlur_0(src.nativeObj, dst.nativeObj, ksize);

return;

}

private static native void medianBlur_0(long src_nativeObj, long dst_nativeObj, int ksize);

使用ksize X ksize 大小的窗口的中值滤波器对图像做平滑处理,图像的各个通道单独处理。该方法支持就地操作。

中值滤波器内部使用 BORDER_REPLICATE 的外推模式复制边界像素。src:输入图像,1-,3-,4-通道;当ksize=3,或者ksize=5时,图像的depth可以是CV_8U、CV_16U、CV_32F,如果ksize更大,depth应该只用CV_8U 。

dest:输出图像,和源图像具有相同的大小和类型。

ksize:窗口线性大小,必须是大于1的奇数。

morphologyDefaultBorderValue()

方法声明

c++static Scalar cv::morphologyDefaultBorderValue()

java 中没有直接调用该方法的接口,使用膨胀、腐蚀操作时,内部自动调用c++方法对相应参数进行赋值。

返回图像膨胀和腐蚀的 magic 边界值。当膨胀时,会自动转换为 Scalar::all(-DBL_MAX)。

morphologyEx

方法声明:

c++void cv::morphologyEx   (   InputArray      src,

OutputArray   dst,                                  int   op,

InputArray    kernel,

Point     anchor = Point(-1,-1),    int     iterations = 1,    int     borderType = BORDER_CONSTANT,        const Scalar &      borderValue = morphologyDefaultBorderValue()

)

java//javadoc: morphologyEx(src, dst, op, kernel, anchor, iterations, borderType, borderValue)

public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)

{

morphologyEx_0(src.nativeObj, dst.nativeObj, op, kernel.nativeObj, anchor.x, anchor.y, iterations, borderType, borderValue.val[0], borderValue.val[1], borderValue.val[2], borderValue.val[3]);

return;

}    //javadoc: morphologyEx(src, dst, op, kernel, anchor, iterations, borderType)

public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType)

{

morphologyEx_1(src.nativeObj, dst.nativeObj, op, kernel.nativeObj, anchor.x, anchor.y, iterations, borderType);

return;

}    //javadoc: morphologyEx(src, dst, op, kernel, anchor, iterations)

public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations)

{

morphologyEx_2(src.nativeObj, dst.nativeObj, op, kernel.nativeObj, anchor.x, anchor.y, iterations);

return;

}    //javadoc: morphologyEx(src, dst, op, kernel, anchor)

public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor)

{

morphologyEx_3(src.nativeObj, dst.nativeObj, op, kernel.nativeObj, anchor.x, anchor.y);

return;

}    //javadoc: morphologyEx(src, dst, op, kernel)

public static void morphologyEx(Mat src, Mat dst, int op, Mat kernel)

{

morphologyEx_4(src.nativeObj, dst.nativeObj, op, kernel.nativeObj);

return;

}

// C++:  void cv::morphologyEx(Mat src, Mat& dst, int op, Mat kernel, Point anchor = Point(-1,-1), int iterations = 1, int borderType = BORDER_CONSTANT, Scalar borderValue = morphologyDefaultBorderValue())

private static native void morphologyEx_0(long src_nativeObj, long dst_nativeObj, int op, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations, int borderType, double borderValue_val0, double borderValue_val1, double borderValue_val2, double borderValue_val3);

private static native void morphologyEx_1(long src_nativeObj, long dst_nativeObj, int op, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations, int borderType);

private static native void morphologyEx_2(long src_nativeObj, long dst_nativeObj, int op, long kernel_nativeObj, double anchor_x, double anchor_y, int iterations);

private static native void morphologyEx_3(long src_nativeObj, long dst_nativeObj, int op, long kernel_nativeObj, double anchor_x, double anchor_y);

private static native void morphologyEx_4(long src_nativeObj, long dst_nativeObj, int op, long kernel_nativeObj);

基于膨胀、腐蚀对图像做增强形态变换。

所有操作都可以就地进行,多个通道会被独立处理。src:源图像,通道数可以是任意的,depth可以是CV_8U、CV_16U、CV_16S、CV_32F、CV_64F。

dst:输出图像,和原图像具有相同的大小和类型。

op:形态运算的类型。

kernel:Structuring element,可以通过getStructuringElement创建。

anchor:锚点位置。负值表示锚点位于kenel中心。

iterations:膨胀、腐蚀操作应用的次数。

borderType:图像边界外像素值的外推模式。

borderValue:静态边界时的边界值,默认值有特殊的含义。

需要注意的是,iteration 的值表示的是腐蚀、膨胀应用的次数,例如图像的开操作,iteration是2,等价于 erode -> erode -> dilate -> dilate,而不是 erode -> dilate -> erode -> dilate。

pyrDown()

方法声明:

c++void cv::pyrDown    (   InputArray      src,

OutputArray    dst,        const Size &    dstsize = Size(),    int     borderType = BORDER_DEFAULT

)

javapublic static void pyrDown(Mat src, Mat dst)

{

pyrDown_2(src.nativeObj, dst.nativeObj);

return;

}

private static native void pyrDown_0(long src_nativeObj, long dst_nativeObj, double dstsize_width, double dstsize_height, int borderType);

private static native void pyrDown_1(long src_nativeObj, long dst_nativeObj, double dstsize_width, double dstsize_height);

private static native void pyrDown_2(long src_nativeObj, long dst_nativeObj);

使用向下采样模糊图像。

默认情况下,输出图像的大小为 Size((src.cols+1)/2, (src.rows+1)/2)。但是如论什么时候都要满足如下条件:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

该方法为创建图像的高斯金字塔执行向下采样的步骤。

首先使用如下kernel对图像进行卷积

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

然后,舍弃偶数行和列来对图像进行下采样。src:输入图像。

dst:输出图像,大小为指定的值,类型和源图像相同。

dstsize:输出图像的大小。

borderType:图像边界外像素值的外推模式,不支持BORDER_CONSTANT 模式。

pyrMeanShiftFiltering()

方法声明:

c++void cv::pyrMeanShiftFiltering  (   InputArray      src,

OutputArray      dst,                                           double   sp,                                           double   sr,                                           int      maxLevel = 1,

TermCriteria     termcrit = TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 5, 1)

)

java//javadoc: pyrMeanShiftFiltering(src, dst, sp, sr, maxLevel, termcrit)

public static void pyrMeanShiftFiltering(Mat src, Mat dst, double sp, double sr, int maxLevel, TermCriteria termcrit)

{

pyrMeanShiftFiltering_0(src.nativeObj, dst.nativeObj, sp, sr, maxLevel, termcrit.type, termcrit.maxCount, termcrit.epsilon);

return;

}    //javadoc: pyrMeanShiftFiltering(src, dst, sp, sr, maxLevel)

public static void pyrMeanShiftFiltering(Mat src, Mat dst, double sp, double sr, int maxLevel)

{

pyrMeanShiftFiltering_1(src.nativeObj, dst.nativeObj, sp, sr, maxLevel);

return;

}    //javadoc: pyrMeanShiftFiltering(src, dst, sp, sr)

public static void pyrMeanShiftFiltering(Mat src, Mat dst, double sp, double sr)

{

pyrMeanShiftFiltering_2(src.nativeObj, dst.nativeObj, sp, sr);

return;

}

private static native void pyrMeanShiftFiltering_0(long src_nativeObj, long dst_nativeObj, double sp, double sr, int maxLevel, int termcrit_type, int termcrit_maxCount, double termcrit_epsilon);

private static native void pyrMeanShiftFiltering_1(long src_nativeObj, long dst_nativeObj, double sp, double sr, int maxLevel);

private static native void pyrMeanShiftFiltering_2(long src_nativeObj, long dst_nativeObj, double sp, double sr);

执行图像 meanshift分割的滤波阶段。

这个函数严格来说并不是图像的分割,而是图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域。(引自:Opencv均值漂移pyrMeanShiftFiltering彩色图像分割流程剖析)

能够去除局部相似的纹理,同时保留边缘等差异较大的特征。(引自:学习OpenCV2——MeanShift之图形分割)

对于每个像素(x,y),该方法迭代的进行meanshift,像素的邻域不仅考虑空间,还考虑色彩,即从 空间-色彩 的超空间中选取像素的邻域。

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

其中,可以不是 (R,G,B) 颜色空间,只要是3分量构成的颜色空间即可。

在邻域中找到平均空间值(X',Y')和平均颜色向量(R',G',B'),作为下一个迭代的邻域中心:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

迭代结束后,初始像素的颜色分量(即迭代开始的像素)设置为最终值(最后一次迭代的平均颜色):

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

在图像高斯金字塔上,当maxLevel>0时,上述过程最先从maxLevel+1图层开始。计算结束后,结果传递给大一级的图层,并只在与上层图层相比,颜色差异大于sr的像素上再次运行迭代,能够使得颜色区域的边界更加清晰。需要注意的是,在金字塔上运行的结果与对整个原始图像(即maxLevel==0时)直接运行meanshift过程得到的结果不同。src:输入图像,8-bit,3通道的图像。

dst:输出图像,和源图像具有相同的大小和格式。

sp:空间窗口半径。

sr:颜色窗口半径。

maxLevel:待分割的金字塔的最大层级。

termcrit:结束条件。

pyrUp()

方法声明:

c++void cv::pyrUp  (   InputArray      src,

OutputArray      dst,        const Size &    dstsize = Size(),    int     borderType = BORDER_DEFAULT

)

java//javadoc: pyrUp(src, dst, dstsize, borderType)

public static void pyrUp(Mat src, Mat dst, Size dstsize, int borderType)

{

pyrUp_0(src.nativeObj, dst.nativeObj, dstsize.width, dstsize.height, borderType);

return;

}    //javadoc: pyrUp(src, dst, dstsize)

public static void pyrUp(Mat src, Mat dst, Size dstsize)

{

pyrUp_1(src.nativeObj, dst.nativeObj, dstsize.width, dstsize.height);

return;

}    //javadoc: pyrUp(src, dst)

public static void pyrUp(Mat src, Mat dst)

{

pyrUp_2(src.nativeObj, dst.nativeObj);

return;

}

// C++:  void cv::pyrUp(Mat src, Mat& dst, Size dstsize = Size(), int borderType = BORDER_DEFAULT)

private static native void pyrUp_0(long src_nativeObj, long dst_nativeObj, double dstsize_width, double dstsize_height, int borderType);

private static native void pyrUp_1(long src_nativeObj, long dst_nativeObj, double dstsize_width, double dstsize_height);

private static native void pyrUp_2(long src_nativeObj, long dst_nativeObj);

对图像向上采样,然后进行模糊处理。

默认情况下,输出图像的大小为Size(src.cols\*2, (src.rows\*2)。但是,无论什么情况,都应该满足以下条件:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

该方法可以执行高斯金字塔创建的向上采样步骤,也可以用于拉普拉斯金子塔的创建。

首先通过注入0值行、0值列对源图像进行向上采样,即放大图像;然后将向下采样使用的kernel乘以4,作为新kernel对进行卷积,对放大的图像进行卷积。src:输入图像。

dst:输出图像,大小指定,类型和输入图像相同。

dstsize:输出图像的大小。

borderType:图像边界外像素值的外推模式,只支持BORDER_DEFAULT 模式。

Scharr()

方法声明:

c++void cv::Scharr     (   InputArray      src,

OutputArray     dst,                            int     ddepth,                            int     dx,                            int     dy,                            double      scale = 1,                            double      delta = 0,                            int     borderType = BORDER_DEFAULT

)

java//javadoc: Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)

public static void Scharr(Mat src, Mat dst, int ddepth, int dx, int dy, double scale, double delta, int borderType)

{

Scharr_0(src.nativeObj, dst.nativeObj, ddepth, dx, dy, scale, delta, borderType);

return;

}    //javadoc: Scharr(src, dst, ddepth, dx, dy, scale, delta)

public static void Scharr(Mat src, Mat dst, int ddepth, int dx, int dy, double scale, double delta)

{

Scharr_1(src.nativeObj, dst.nativeObj, ddepth, dx, dy, scale, delta);

return;

}    //javadoc: Scharr(src, dst, ddepth, dx, dy, scale)

public static void Scharr(Mat src, Mat dst, int ddepth, int dx, int dy, double scale)

{

Scharr_2(src.nativeObj, dst.nativeObj, ddepth, dx, dy, scale);

return;

}    //javadoc: Scharr(src, dst, ddepth, dx, dy)

public static void Scharr(Mat src, Mat dst, int ddepth, int dx, int dy)

{

Scharr_3(src.nativeObj, dst.nativeObj, ddepth, dx, dy);

return;

}

// C++:  void cv::Scharr(Mat src, Mat& dst, int ddepth, int dx, int dy, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT)

private static native void Scharr_0(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, double scale, double delta, int borderType);

private static native void Scharr_1(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, double scale, double delta);

private static native void Scharr_2(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, double scale);

private static native void Scharr_3(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy);

使用 Scharr 运算计算图像的x-或者y-的一阶导数。调用方法Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)等价于调用方法Sobel(src, dst, ddepth, dx, dy, CV_SCHARR, scale, delta, borderType)src:输入图像。

dst:输出图像,和输入图像具有相同的大小和通道数。

ddepth:输出图像的depth。

dx:x的导数阶数。

dy:y的导数阶数。

scale:可选参数,计算导数的缩放因子,默认不缩放。

delta:可选参数,计算结果保存到输出图像之前,添加到计算结果的值delta。

borderType:图像边界外像素值的外推模式。

sepFilter2D()

方法声明:

c++void cv::sepFilter2D    (   InputArray      src,

OutputArray    dst,                                 int    ddepth,

InputArray     kernelX,

InputArray     kernelY,

Point      anchor = Point(-1,-1),    double      delta = 0,    int     borderType = BORDER_DEFAULT

)

java//javadoc: sepFilter2D(src, dst, ddepth, kernelX, kernelY, anchor, delta, borderType)

public static void sepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor, double delta, int borderType)

{

sepFilter2D_0(src.nativeObj, dst.nativeObj, ddepth, kernelX.nativeObj, kernelY.nativeObj, anchor.x, anchor.y, delta, borderType);

return;

}    //javadoc: sepFilter2D(src, dst, ddepth, kernelX, kernelY, anchor, delta)

public static void sepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor, double delta)

{

sepFilter2D_1(src.nativeObj, dst.nativeObj, ddepth, kernelX.nativeObj, kernelY.nativeObj, anchor.x, anchor.y, delta);

return;

}    //javadoc: sepFilter2D(src, dst, ddepth, kernelX, kernelY, anchor)

public static void sepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor)

{

sepFilter2D_2(src.nativeObj, dst.nativeObj, ddepth, kernelX.nativeObj, kernelY.nativeObj, anchor.x, anchor.y);

return;

}    //javadoc: sepFilter2D(src, dst, ddepth, kernelX, kernelY)

public static void sepFilter2D(Mat src, Mat dst, int ddepth, Mat kernelX, Mat kernelY)

{

sepFilter2D_3(src.nativeObj, dst.nativeObj, ddepth, kernelX.nativeObj, kernelY.nativeObj);

return;

}

// C++:  void cv::sepFilter2D(Mat src, Mat& dst, int ddepth, Mat kernelX, Mat kernelY, Point anchor = Point(-1,-1), double delta = 0, int borderType = BORDER_DEFAULT)

private static native void sepFilter2D_0(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj, double anchor_x, double anchor_y, double delta, int borderType);

private static native void sepFilter2D_1(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj, double anchor_x, double anchor_y, double delta);

private static native void sepFilter2D_2(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj, double anchor_x, double anchor_y);

private static native void sepFilter2D_3(long src_nativeObj, long dst_nativeObj, int ddepth, long kernelX_nativeObj, long kernelY_nativeObj);

对图像使用可分离的线性滤波器。首先使用一维kernel(kernelX)对源图像的每一行进行过滤;然后使用一维kernel(kernelY)对结果的每一列进行过滤;最后根据delta对结果进行位移,存储在输出图像中。src:输入图像;

dst:输出图像,和输入图像具有相同的大小和通道数。

ddepth:输出图像的depth。

kernelX:对每一行进行过滤的系数。

kernelY:对每一列进行过滤的系数。

anchor:kernel锚点位置。默认值(-1,-1)表示锚点位于kernel中心。

delta:结果存储前添加的值。

borderType:图像边界外像素值的外推模式。

Sobel()

方法声明:

c++void cv::Sobel  (   InputArray      src,

OutputArray      dst,                           int      ddepth,                           int      dx,                           int      dy,                           int      ksize = 3,                           double   scale = 1,                           double   delta = 0,                           int      borderType = BORDER_DEFAULT

)

java//javadoc: Sobel(src, dst, ddepth, dx, dy, ksize, scale, delta, borderType)

public static void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType)

{

Sobel_0(src.nativeObj, dst.nativeObj, ddepth, dx, dy, ksize, scale, delta, borderType);

return;

}    //javadoc: Sobel(src, dst, ddepth, dx, dy, ksize, scale, delta)

public static void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale, double delta)

{

Sobel_1(src.nativeObj, dst.nativeObj, ddepth, dx, dy, ksize, scale, delta);

return;

}    //javadoc: Sobel(src, dst, ddepth, dx, dy, ksize, scale)

public static void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize, double scale)

{

Sobel_2(src.nativeObj, dst.nativeObj, ddepth, dx, dy, ksize, scale);

return;

}    //javadoc: Sobel(src, dst, ddepth, dx, dy, ksize)

public static void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy, int ksize)

{

Sobel_3(src.nativeObj, dst.nativeObj, ddepth, dx, dy, ksize);

return;

}    //javadoc: Sobel(src, dst, ddepth, dx, dy)

public static void Sobel(Mat src, Mat dst, int ddepth, int dx, int dy)

{

Sobel_4(src.nativeObj, dst.nativeObj, ddepth, dx, dy);

return;

}

// C++:  void cv::Sobel(Mat src, Mat& dst, int ddepth, int dx, int dy, int ksize = 3, double scale = 1, double delta = 0, int borderType = BORDER_DEFAULT)

private static native void Sobel_0(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType);

private static native void Sobel_1(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, int ksize, double scale, double delta);

private static native void Sobel_2(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, int ksize, double scale);

private static native void Sobel_3(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy, int ksize);

private static native void Sobel_4(long src_nativeObj, long dst_nativeObj, int ddepth, int dx, int dy);

使用扩展sobel运算计算图像的一阶、二阶、三阶、混合导数。

在所有情况下,只有一个除外,ksize×ksize分离内核用于计算导数。当ksize = 1,3×1或1×3内核使用(也就是说,没有进行高斯平滑)。ksize = 1只能用于x或y的二阶导数。

另外还有一个特殊值,当ksize = CV_SCHARR (-1)时,相应的3x3 Scharr滤波器可能比 3x3的sobel滤波器更准确。对于x导数和y导数的转置,Schar窗口如下:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

该方法通过将图像与适当的kernel卷积来计算图像的导数:

AAffA0nNPuCLAAAAAElFTkSuQmCC

image

Sobel算子结合了高斯平滑和微分,所以结果或多或少能抵抗噪声。

通常,函数被调用(xorder = 1, yorder = 0, ksize = 3)或(xorder = 0, yorder = 1, ksize = 3)来计算第一个x或y图像的导数。

第一种情况的kernel:

AAffA0nNPuCLAAAAAElFTkSuQmCC

作者:昵称真难选

链接:https://www.jianshu.com/p/be872569205e

你可能感兴趣的:(android,opencv中图像分割)