图像像素点赋值_图像的形态学操作

本文介绍了图像处理中的形态学操作,包括腐蚀和膨胀。腐蚀通过求局部最小值,常用于去除图像噪声,而膨胀则通过求局部最大值,用于填充图像中的空洞或连接接近的物体。文中详细讲解了两种操作的原理,提供了OpenCV在Ubuntu上的实现,并展示了不同结构元素(如矩形、十字)对图像进行腐蚀和膨胀的效果。
摘要由CSDN通过智能技术生成

 此篇介绍两种的对图像形态学操作方式(形态学腐蚀、形态学膨胀)

在许多视觉识别的应用场合,若需要去除图像中微小噪声,分离较近的两个物体,则可对图像形态学腐蚀处理;若需要填充图像中缺失的微小区域、合并较近的两个物体,则可对图像形态学膨胀处理;以下就两种情况展开描述:


运行环境:

  • Ubuntu20.04

  • OpenCV4.5.1

  • Qt-Creator4.11.1

  • gdb-ImageWatch

>注意:以下操作均在对源图像进行二值化操作的前提下进行!

01

形态学腐蚀

形态学腐蚀就是求局部最小值的操作,[核]与图像卷积,即计算核B覆盖的区域的像素点的最小值,并把这个最小值赋值给参考点指定的像素。


  1. 原理:

    A⨀B={z|(B)z⊆A}

    解释:移动结构B,如果结构B与A图的交集完全属于结构A的区域内,则保存该位置点。

    结构元素的中心像素与原图像的非零像素重合,结构元素覆盖区域有零像素,则原图像被覆盖的中心像素要被删除;结构元素覆盖区域无零像素,则原图像被覆盖的中心像素要被保留;以次X、Y并行移动,按此操作。

    为了更好的理解原理,这里先引入一个概念即结构元素。以下分别为3×3十字结构元素、3×3矩形结构元素、7×7椭圆结构元素,这里是的结构元素也可以自定义。

    1eb9f23ecf15ef901acd707b96a84f69.png

    如下图利用3×3十字结构元素对左图像腐蚀变成右图:

    09e2992df5e093105bcfe8c154fd3814.png

    具体做了什么呢?当结构元素对二值化图像每个像素扫描出现的两种情况(如下图)。

    06bb74983345f4af141e5a443eff64ec.png

    中心像素要被删除

    6769b6a5c21aa371dad6ebba3ecb1903.png

    中心像素要被保留

  2. 步骤

    Step1:生成或制作结构元素

    Step2:结构元素的中心像素与原图像的非零像素重合,结构元素覆盖区域有零像素,则原图像被覆盖的中心像素要被删除;结构元素覆盖区域无零像素,则原图像被覆盖的中心像素要被保留;以次X、Y并行移动,按此操作。

  3. 函数介绍:

    >结构元素生成函数

    getStructuringElement(int shape,Size ksize,Point anchor=Point(-1,-1))

    shape:结构元素的种类;

    ksize:结构元素的尺寸大小;

    anchor:中心点的位置,默认参数为结构元素的几何中心;

    标记参数简记作用
    MORPH_RECT0矩形结构元素,所有元素都为1
    MORPH_CROSS1十字结构元素,中间的列和行元素为1
    MORPH_ELLIPSE2椭圆结构元素,矩形的椭圆内接元素为1

    >图像腐蚀操作函数

    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())

    src:输入的待腐蚀图像,图像的通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一;

    dst:腐蚀后的输出图像,与输入图像src具有相同的尺寸和数据类型;

    kernel:用于腐蚀操作的结构元素,可以自己输入,也可以用getStructuringElement()函数生成;

    anchor:中心点在结构元素中的位置,默认参数为结构元素的几何中心点;

    iterations:腐蚀的次数;

    borderType:像素外推法选择标志;

    borderValue:边界不变的边界值;

  4. 代码展示:

    #include #include using namespace cv;using namespace std;void drawState(Mat &img,int number,Mat centroids,Mat stats,String str);int main(){    //生成用于腐蚀的原图像    Mat src=(Mat_(6,6)<<0,0,0,0,255,0,                               0,255,255,255,255,255,                               0,255,255,255,255,0,                               0,255,255,255,255,0,                               0,255,255,255,255,0,                               0,0,0,0,0,0);    Mat struct1,struct2;    struct1=getStructuringElement(0,Size(3,3));//矩形结构元素    struct2=getStructuringElement(1,Size(3,3));//十字结构元素    Mat erodeSrc;    erode(src,erodeSrc,struct2);    namedWindow("src",WINDOW_GUI_NORMAL);    namedWindow("erodeSrc",WINDOW_GUI_NORMAL);    imshow("src",src);    imshow("erodeSrc",erodeSrc);//~~~~~~~~~~~~~~~~~~形态学腐蚀应用于图像中~~~~~~~~~~~~~~~~~~~~    cout<<"文字腐蚀验证"<<endl;    waitKey(0);    Mat black=imread("/home/zja/Pictures/Black1.png");    Mat erode_black1,erode_black2;    //黑背景图像腐蚀    erode(black,erode_black1,struct1);    erode(black,erode_black2,struct2);    imshow("black",black);    imshow("erode_black1",erode_black1);    imshow("erode_black2",erode_black2);//~~~~~~~~~~~~~~~~~对小连通域的去除腐蚀去除~~~~~~~~~~~~~~~~~    cout<<"验证腐蚀对小连通域的去除"<<endl;    waitKey(0);    Mat star=imread("/home/zja/Pictures/star.jpg");    Mat star2;    copyTo(star,star2,star);//深拷贝 克隆一个单独的图像,用于后期图像绘制    Mat wink,winkBW;    //将图像转成二值化图像,用于统计连通域    cvtColor(star,wink,COLOR_BGR2GRAY);    threshold(wink,winkBW,50,255,THRESH_BINARY);    Mat out,stats,centroids;    //统计图像中连通域的个数    int number=connectedComponentsWithStats(winkBW,out,stats,centroids,8,CV_16U);    drawState(star,number,centroids,stats,"未腐蚀时统计连通域");//绘制图像    erode(winkBW,winkBW,struct1);    number=connectedComponentsWithStats(winkBW,out,stats,centroids,8,CV_16U);    drawState(star2,number,centroids,stats,"腐蚀后统计连通域");//绘制图像waitKey(0);return 0;}//绘制图像的子函数void drawState(Mat &img,int number,Mat centroids,Mat stats,String str){    RNG rng(10086);    vector colors;    for(int i=0;i    {        //使用均匀分布的随机数确定颜色        Vec3b vec3=Vec3b(rng.uniform(0,256),rng.uniform(0,256),rng.uniform(0,256));        colors.push_back(vec3);    }    for(int i=1;i    {       //中心位置       int center_x=centroids.at<double>(i,0);       int center_y=centroids.at<double>(i,1);       //矩形边框       int x=stats.at<int>(i,CC_STAT_LEFT);       int y=stats.at<int>(i,CC_STAT_TOP);       int w=stats.at<int>(i,CC_STAT_WIDTH);       int h=stats.at<int>(i,CC_STAT_HEIGHT);       //中心位置绘制       circle(img,Point(center_x,center_y),2,Scalar(0,255,0),2,8,0);       //外接矩形       Rect rect(x,y,w,h);       rectangle(img,rect,colors[i],1,8,0);       putText(img,format("%d",i),Point(center_x,center_y),FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,0,255),1);    }    imshow(str,img);}
  5. 运行效果:

对黑底白字图分别用矩形、十字结构元素腐蚀操作效果图:

b57e2c05c3dcc54ea87bac64a5c807da.png

以下分别为原图、未腐蚀时统计连通域数量(统计了44颗星星)、腐蚀后统计连通域数量(统计了40颗星星):

由此看出如图白色箭头标注的星星太小而被腐蚀掉(等同于噪声干扰的去除)

c9ee19b2259c03a40555ad0b50e5b99a.png

eebaed4e08d8ebc26357b90c3bf56a59.png

02

形态学膨胀

形态学膨胀就是求局部最大值的操作,[核]与图像卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。


  1. 原理:

    A⨁B={z|(B^)z⋂A≠∅}

    解释:移动结构B的过程中,与A图存在重叠区域,则记录该位置。

    结构元素的中心像素与原图像的非零像素重合,将没有像素值的区域填充为1,以次X、Y并行移动,以次X、Y并行移动,按此操作。

    结构元素名词在上述已介绍过,在此不做赘述。

    如下图利用3×3十字结构元素对左图像膨胀变成右图:

    988e2ccf55a2f5b3599febc75f1bb9a7.png

    具体做了什么呢?当结构元素对二值化图像每个像素扫描时,对十字覆盖区域填充255(如下图)。

    080ff6da0311e74e530209a5ba383760.png

  2. 步骤

    Step1:生成或制作结构元素

    Step2:结构元素的中心像素与原图像的非零像素重合,将没有像素值的区域填充为1,以次X、Y并行移动,按此操作。

  3. 函数介绍:

    >结构元素生成函数

    getStructuringElement(int shape,Size ksize,Point anchor=Point(-1,-1

    ))

    >图像膨胀操作函数

    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(

    ))

    src:输入的待膨胀图像,图像的通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一;

    dst:腐蚀后的输出图像,与输入图像src具有相同的尺寸和数据类型;

    kernel:用于膨胀操作的结构元素,可以自己输入,也可以用getStructuringElement()函数生成;

    anchor:中心点在结构元素中的位置,默认参数为结构元素的几何中心点;

    iterations:腐蚀的次数;

    borderType:像素外推法选择标志;

    borderValue:边界不变的边界值;

  4. 代码展示:

    #include #include using namespace cv;using namespace std;int main(){    //生成用于膨胀的原图像    Mat src=(Mat_(6,6)<<0, 0,  0,  0, 255,0,                               0,255,255,255,255,255,                               0,255,255,255,255,0,                               0,255,255,255,255,0,                               0,255,255,255,255,0,                               0, 0,  0,  0,  0, 0);    Mat struct1,struct2;    struct1=getStructuringElement(0,Size(3,3));//矩形结构元素    struct2=getStructuringElement(1,Size(3,3));//十字结构元素    Mat dilateSrc;//存放膨胀后的图像    dilate(src,dilateSrc,struct2);        /*    namedWindow("src",WINDOW_GUI_NORMAL);    namedWindow("dilateSrc",WINDOW_GUI_NORMAL);    imshow("src",src);    imshow("dilateSrc",dilateSrc);    *///~~~~~~~~~~~~~~~~~~~~形态学膨胀应用于图像中~~~~~~~~~~~~~~~~~~~~    cout<<"文字膨胀"<<endl;    waitKey(0);    Mat black=imread("/home/zja/Pictures/Black1.png",IMREAD_ANYCOLOR);    Mat dilate_black1,dilate_black2;    //黑背景图像膨胀    dilate(black,dilate_black1,struct1);    dilate(black,dilate_black2,struct2);  /*    imshow("black",black);    imshow("dilate_black1",dilate_black1);    imshow("dilate_black2",dilate_black2);  */waitKey(0);return 0;}
  5. 运行效果:

对黑底白字图分别用矩形、十字结构元素膨胀操作效果图:

6b1e1b0a1354943f924605794d269043.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值