数学形态学中运算有 膨胀(或扩张)、腐蚀(或侵蚀)、开启、闭合、骨架抽取、极线腐蚀、击中击不中变换、Top-hat变换、颗粒分析、流域变换、形态学梯度等,其中腐蚀与扩张就是我们今天所有讲的要点。opencv中对腐蚀和扩张有相对的函数去实现,多用于图像的取噪、分割出独立的图像元素,在图像中连接相邻的元素、寻找图像中明显的极大值或极小值区、求图像的梯度。
腐蚀
腐蚀是求图片局部最小值算法,定义一个任何的形状和大小的积卷核,定义一个参考点为锚点,通常情况下积卷核为矩形或者圆形,在opencv中MorphShapes枚举中有三个形状(MORPH_RECT【矩形】、MORPH_CROSS【十字结构】、MORPH_ELLIPSE【椭圆】),可将核称为模板或掩膜。积卷核与图像进行积卷,计算核覆盖区域的像素点的最小值,并将最小值赋值给锚点,这样图像中的高亮区域就会逐渐减小。
JNIEXPORT jintArray JNICALL
Java_com_xy_opencv_ndk_1opencv002_MainActivity_erodeORdilate(JNIEnv *env, jclass type,
jintArray pixels_, jint w, jint h) {
jint *pixels = env->GetIntArrayElements(pixels_, NULL);
Mat img(h,w,CV_8UC4,pixels);
// 形态学
//
// 简而言之:一组基于形状处理图像的操作。形态操作将结构元素应用于输入图像并生成输出图像。
// 最基本的形态作用是:侵蚀和扩张。它们有广泛的用途,即:
// 消除噪音
// 隔离单个元素并连接图像中的不同元素。
// 查找图像中的强度凸点或孔
// 我们可以为我们的内核选择三种形状:
// 矩形框:MORPH_RECT
// 十字架:MORPH_CROSS
// 椭圆:MORPH_ELLIPSE
Mat pp = getStructuringElement(MORPH_RECT,Size(10,10));
//腐蚀(侵蚀)图像,向内有坍缩,10*10为基准,消除周边的颜色,用中心的颜色去填充周边颜色。
// 这个操作是扩张的姊妹。它计算给定内核区域的局部最小值。
// 当内核在图像上扫描时,我们计算由重叠的最小像素值,并用该最小值替换锚点下的图像像素。
// 对于扩张的例子,我们可以将侵蚀算子应用于原始图像
// src:源图像
// erosion_dst:输出图像
// element:这是我们将用来执行操作的内核。如果我们不指定,默认是一个简单的3x3矩阵。否则,我们可以指定它的形状。为此,我们需要使用函数cv :: getStructuringElement:
erode(img,img,pp);
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result,0,size,pixels);
env->ReleaseIntArrayElements(pixels_, pixels, 0);
return result;
}
扩张
扩张是求局部最大值算法,与腐蚀相反操作是积卷核与图像进行积卷计算,计算出核覆盖区域的像素点的最大值,并将最大值赋值给锚点,这样图像中的高亮区域就会逐渐增大。
JNIEXPORT jintArray JNICALL
Java_com_xy_opencv_ndk_1opencv002_MainActivity_erodeORdilate(JNIEnv *env, jclass type,
jintArray pixels_, jint w, jint h) {
jint *pixels = env->GetIntArrayElements(pixels_, NULL);
Mat img(h,w,CV_8UC4,pixels);
// 形态作业
//
// 简而言之:一组基于形状处理图像的操作。形态操作将结构元素应用于输入图像并生成输出图像。
// 最基本的形态作用是:侵蚀和扩张。它们有广泛的用途,即:
// 消除噪音
// 隔离单个元素并连接图像中的不同元素。
// 查找图像中的强度凸点或孔
// 我们可以为我们的内核选择三种形状:
// 矩形框:MORPH_RECT
// 十字架:MORPH_CROSS
// 椭圆:MORPH_ELLIPSE
Mat pp = getStructuringElement(MORPH_RECT,Size(10,10));
// src:源图像
// erosion_dst:输出图像
// element:这是我们将用来执行操作的内核。如果我们不指定,默认是一个简单的3x3矩阵。否则,我们可以指定它的形状。为此,我们需要使用函数cv :: getStructuringElement:
//扩张
// 扩张,向外扩张
//
// 该操作包括将图像与某些内核进行卷积,其可以具有任何形状或尺寸,通常为正方形或圆形。
// 内核具有定义的锚点,通常是内核的中心。
// 当内核在图像上扫描时,我们计算由核重叠的最大像素值,并用该最大值替换锚点位置中的图像像素。您可以推断,这种最大化的操作会使图像中的亮区“增长”(因此称为扩张)。
dilate(img,img,pp);
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result,0,size,pixels);
env->ReleaseIntArrayElements(pixels_, pixels, 0);
return result;
}