形态学图像处理 腐蚀
2011-03-16 14:56:00 woxincd 阅读数 1286

腐蚀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。

膨胀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。

腐蚀的作用是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点;膨胀的作用是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的空洞。

开运算是先腐蚀后膨胀的过程,可以消除图像上细小的噪声,并平滑物体边界。

闭运算时先膨胀后腐蚀的过程,可以填充物体内细小的空洞,并平滑物体边界

2018-12-03 20:08:10 yql_617540298 阅读数 113

一、形态学概述

       形态学(morphology)一词通常表示生物学的一个分支,该分支主要研究动植物的形态和结构,而图像处理中的形态学主要是指数学形态学。

       数学形态学(Mathematical morphology)是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。(简单理解:形态学是基于形状的一系列图像处理操作)

       基本运算:二值腐蚀和膨胀,二值开闭运算,骨架抽取,极限腐蚀,击中击不中变换,形态学梯度,Top-hat变换,颗粒分析,流域变换,灰值腐蚀和膨胀,灰值开闭运算,灰值形态学梯度等。

二、膨胀与腐蚀

       作用:(1)消除噪声;

                  (2)分割出独立的图像元素,在图像中连接相邻的元素‘;

                   (3)寻找图像中的明显的极大值或极小值区域;

                   (4)求出图像的梯度。

       注意:腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。 

       膨胀:邻域扩张,效果图拥有比原图更大的高亮区域;

       腐蚀:原图中的高亮部分被腐蚀,邻域缩小,效果图拥有比原图更小的高亮区域。

       膨胀或腐蚀:将图像(或图像的一部分区域,A)与核(B)卷积。

       核:可以是任何形状和大小,它拥有一个单独定义的参考点,称为锚点。多数情况下,核是一个中间带有参考点和实心正方形或者圆形。

三、膨胀

        膨胀:求局部最大值操作。

       核B与图形A卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。

代码:

#coding=utf-8
import cv2
image = cv2.imread("F:/a.jpg",0);
#构造一个3×3的结构元素 
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dilate = cv2.dilate(image, element)
erode = cv2.erode(image, element)
 
#将两幅图像相减获得边,第一个参数是膨胀后的图像,第二个参数是腐蚀后的图像
result = cv2.absdiff(0,erode);
 
#上面得到的结果是灰度图,将其二值化以便更清楚的观察结果
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY); 
#反色,即对二值图每个像素取反
result = cv2.bitwise_not(result); 
#显示图像
#cv2.imshow("result",result); 
cv2.imwrite("F:/b.jpg",result)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、腐蚀

         腐蚀:与膨胀是一对相反的操作,腐蚀是求局部最小值的操作。

       代码:

#coding=utf-8
import cv2
image = cv2.imread("F:/a.jpg",0);
#构造一个3×3的结构元素 
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dilate = cv2.dilate(image, element)
erode = cv2.erode(image, element)
 
#将两幅图像相减获得边,第一个参数是膨胀后的图像,第二个参数是腐蚀后的图像
result = cv2.absdiff(dilate,0);
 
#上面得到的结果是灰度图,将其二值化以便更清楚的观察结果
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY); 
#反色,即对二值图每个像素取反
result = cv2.bitwise_not(result); 
#显示图像
#cv2.imshow("result",result); 
cv2.imwrite("F:/c.jpg",result)
cv2.waitKey(0)
cv2.destroyAllWindows()

2017-01-06 14:41:33 OliverkingLi 阅读数 469

膨胀就是求局部最大值的操作(dilate),腐蚀就是求局部最小值的操作(erode),无论是膨胀操作还是腐蚀操作就是蒋图片或者额图像的一部分区域,标记为A与核标记为B进行卷积。

代码:

#include"stdafx.h"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include"opencv2/core/core.hpp"
#include <iostream>

using namespace cv;
using namespace std;

// 定义全局变量
Mat image, dstImage;
int g_nTrackbarNumer = 0;
int g_nStructElementSize = 3;
//函数声明
void process();
void on_TrackbarNumChange(int, void*);
void on_ElementSizeChange(int, void*);

int main() {
	system("color 5E");
	//读取图片
	image = imread("E:\\pictures\\For_Project\\New_opencv\\Sceen\\1.jpg");
	namedWindow("【原始图像】", 1);
	imshow("【原始图像】", image);

	namedWindow("【效果图】", 1);
	//创建滑动条
	createTrackbar("腐蚀/膨胀", "【效果图】", &g_nTrackbarNumer, 1, on_TrackbarNumChange);
	createTrackbar("内核尺寸", "【效果图】", &g_nStructElementSize, 21, on_ElementSizeChange);
	//分别调用回调函数
	on_TrackbarNumChange(g_nTrackbarNumer, 0);
	on_ElementSizeChange(g_nStructElementSize, 0);

	//等待键盘按键‘q’退出
	while (char(waitKey(1)) != 'q') {}
	return 0;
}

void process() {
	//自定义核
	Mat element = getStructuringElement(MORPH_RECT, Size(2 * g_nStructElementSize + 1, 
		2 * g_nStructElementSize + 1), Point(g_nStructElementSize, g_nStructElementSize));
	//判断进行腐蚀或者膨胀操作
	if (g_nTrackbarNumer == 0) {
		//服饰操作
		erode(image, dstImage, element);
	}
	else {
		//膨胀操作
		dilate(image, dstImage, element);
	}

	imshow("【效果图】", dstImage);
}

void on_TrackbarNumChange(int,void*) {
	process();
}

void on_ElementSizeChange(int, void *) {
	process();
}


2013-05-02 20:50:26 dyl_love98 阅读数 169

PS:今天上午,非常郁闷,有很多简单基础的问题搞得我有些迷茫,哎,代码几天不写就忘。目前又不当COO,还是得用心记代码哦!

    

言前

    上一篇文章,我们讲解了图像处理中的值阈数函,这一篇文章我们来做膨胀和腐蚀数函。

 

    

膨胀与腐蚀

    说念概可能很难释解,我们来看图,首先是原图:

    Original image

    膨胀后以会成变这样:

    Dilation result - Theory example

    腐蚀后以则会成变这样:

    Erosion result - Theory example

    看起来可能有些稀里糊涂,明显是膨胀,为什么字反而变细了,而明显是腐蚀,为什么字反而变粗了。

    实际上,所谓膨胀该应指:

    

    较亮色块膨胀。

    

    而所谓腐蚀该应指:

    

    较亮色块腐蚀。

    

    面上图面里,由于景背白色是较亮色块,所以膨胀时就把玄色较暗色块的字压扁了……相反腐蚀时,字就吸水膨胀了……

    用数学公式表现就是:

    

    

    说白了就是在指定巨细的内核里找最暗或者最亮的像素点,并用该点替换掉内核锚点上的像素。 

    

 

    

实现

    首先我们来实现膨胀dilate数函。

var dilate = function(__src, __size, __borderType, __dst){
    __src || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
    if(__src.type && __src.type == "CV_RGBA"){
        var width = __src.col,
            height = __src.row,
            size = __size || 3,
            dst = __dst || new Mat(height, width, CV_RGBA),
            dstData = dst.data;
        
        var start = size >> 1;
        var withBorderMat = copyMakeBorder(__src, start, start, 0, 0, __borderType),
            mData = withBorderMat.data,
            mWidth = withBorderMat.col;
        
        var newOffset, total, nowX, offsetY, offsetI, nowOffset, i, j;
        
        if(size & 1 === 0){
            error(arguments.callee, UNSPPORT_SIZE/* {line} */);
            return __src;
        }
        
        for(i = height; i--;){
            offsetI = i * width;
            for(j = width; j--;){
                newOffset = 0;
                total = 0;
                for(y = size; y--;){
                    offsetY = (y + i) * mWidth * 4;
                    for(x = size; x--;){
                        nowX = (x + j) * 4;
                        nowOffset = offsetY + nowX;
                        (mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2] > total) && (total = mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2]) && (newOffset = nowOffset);
                    }
                }
                dstData[(j + offsetI) * 4] = mData[newOffset];
                dstData[(j + offsetI) * 4 + 1] = mData[newOffset + 1];
                dstData[(j + offsetI) * 4 + 2] = mData[newOffset + 2];
                dstData[(j + offsetI) * 4 + 3] = mData[newOffset + 3];
            }
        }
        
    }else{
        error(arguments.callee, UNSPPORT_DATA_TYPE/* {line} */);
    }
    return dst;
};
    每日一道理
站在历史的海岸漫溯那一道道历史沟渠:楚大夫沉吟泽畔,九死不悔;魏武帝扬鞭东指,壮心不已;陶渊明悠然南山,饮酒采菊……他们选择了永恒,纵然谄媚诬蔑视听,也不随其流扬其波,这是执著的选择;纵然马革裹尸,魂归狼烟,也要仰天长笑,这是豪壮的选择;纵然一身清苦,终日难饱,也愿怡然自乐,躬耕陇亩,这是高雅的选择。在一番选择中,帝王将相成其盖世伟业,贤士迁客成其千古文章。

    (mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2] > total) && (total = mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2]) && (newOffset = nowOffset);

    这行代码面里,我们先用RGB的数值和与上一个最大值total比较,然后如果新的值比较大,就把新的值赋给total,并把新的偏移量newOffset赋值以后偏移量nowOffset。

    然后个整内核巨细的面积环循完了就能够找到一个最大的total以及对应的偏移量newOffset。就能够赋值了:

    dstData[(j + offsetI) * 4] = mData[newOffset];
dstData[(j + offsetI) * 4 + 1] = mData[newOffset + 1];
dstData[(j + offsetI) * 4 + 2] = mData[newOffset + 2];
dstData[(j + offsetI) * 4 + 3] = mData[newOffset + 3];

    

    那么腐蚀erode数函则相反,找一个最小的值就好了。

var erode = function(__src, __size, __borderType, __dst){
    __src || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
    if(__src.type && __src.type == "CV_RGBA"){
        var width = __src.col,
            height = __src.row,
            size = __size || 3,
            dst = __dst || new Mat(height, width, CV_RGBA),
            dstData = dst.data;
        
        var start = size >> 1;
        var withBorderMat = copyMakeBorder(__src, start, start, 0, 0, __borderType),
            mData = withBorderMat.data,
            mWidth = withBorderMat.col;
        
        var newOffset, total, nowX, offsetY, offsetI, nowOffset, i, j;
        
        if(size & 1 === 0){
            error(arguments.callee, UNSPPORT_SIZE/* {line} */);
            return __src;
        }
        
        for(i = height; i--;){
            offsetI = i * width;
            for(j = width; j--;){
                newOffset = 0;
                total = 765;
                for(y = size; y--;){
                    offsetY = (y + i) * mWidth * 4;
                    for(x = size; x--;){
                        nowX = (x + j) * 4;
                        nowOffset = offsetY + nowX;
                        (mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2] < total) && (total = mData[nowOffset] + mData[nowOffset + 1] + mData[nowOffset + 2]) && (newOffset = nowOffset);
                    }
                }
                dstData[(j + offsetI) * 4] = mData[newOffset];
                dstData[(j + offsetI) * 4 + 1] = mData[newOffset + 1];
                dstData[(j + offsetI) * 4 + 2] = mData[newOffset + 2];
                dstData[(j + offsetI) * 4 + 3] = mData[newOffset + 3];
            }
        }
        
    }else{
        error(arguments.callee, UNSPPORT_DATA_TYPE/* {line} */);
    }
    return dst;
};
 

    

果效

    

    

 

    

系列目录

    Javascript图像处理系列

 

 参考资料

    Eroding and Dilating

文章结束给大家分享下程序员的一些笑话语录: 一个合格的程序员是不会写出 诸如 “摧毁地球” 这样的程序的,他们会写一个函数叫 “摧毁行星”而把地球当一个参数传进去。


2018-05-14 10:22:31 wo8vqj68 阅读数 200

腐蚀:用结构元对图像进行腐蚀可以达到缩小或者细化图像的效果。同时,结构元大小选择的不同,腐蚀的次数不同,都会对腐蚀结果造成影响

    特点:缩小 细化

    应用:去除图像中的某些部件

膨胀:用结构单元对图像进行膨胀可以达到增长和粗化二值图像的效果,结构元大小选择的不同可以使图像变成不同的形状

    特点:增长 粗化

    应用:桥接裂缝

最近在matlab中画圆柱体,然后绕中心点旋转之后造成有的图片中间出现裂隙,如图:

突然想到了这种情况下可以使用膨胀来处理,代码如下

% 对圆柱体中每一张进行膨胀处理
for i = 1:size(skel1,3)
    I = skel1(:,:,i);
    se = strel('disk',3);
    I = imdilate(I,se);
    skel1(:,:,i) = I;
end

成功!

其中结构元的选择对膨胀的效果也是不同的,我选择了square结构元,至此圆柱体绕中心点旋转圆满结束

开操作和闭操作的共同点:平滑轮廓

不同点:开操作可以断开狭颈并消除细长的突出物

             闭操作可以弥合较窄的间断和细长的沟壑,消除小的空洞,填补轮廓线中的断裂

开操作是先腐蚀后膨胀的结果

闭操作是先膨胀后腐蚀的结果

 

 

没有更多推荐了,返回首页