图像处理连通区获取_matlab 获取最大连通区域图像 - CSDN
  • 申明:本文转载自... Matlab中regionprops的使用示例 获取图像连通区域。有这样一幅图, 我们想获取其中的连通区域,可以使用以下代码: src_img_name = 'blue_sky_white_clound_002594.jpg'; img = imrea

     申明:本文转载自http://blog.csdn.net/shaoxiaohu1/article/details/40272531

    Matlabregionprops的使用示例

    获取图像的连通区域。有这样一幅图,

    我们想获取其中的连通区域,可以使用以下代码:

    src_img_name = 'blue_sky_white_clound_002594.jpg';

    img = imread(src_img_name);

     

    % get binary image

    gray_img = rgb2gray(img);

    T = graythresh(gray_img);

    bw_img = im2bw(gray_img, T);

     

    % find the largest connected region

    img_reg = regionprops(bw_img, 'area', 'boundingbox');

    areas = [img_reg.Area];

    rects = cat(1,  img_reg.BoundingBox);

     

    显示所有连通区域,

    % show all the largest connected region

    figure(1),

    imshow(bw_img);

    for i = 1:size(rects, 1)

        rectangle('position',rects(i, :), 'EdgeColor', 'r');

    end

     

    显示最大连通区域,

    [~, max_id] = max(areas);

    max_rect = rects(max_id, :);

     

    % show the largest connected region

    figure(2),

    imshow(bw_img);

    rectangle('position', max_rect, 'EdgeColor', 'r');

    展开全文
  • Matlab形态学图像处理:二值图像分割 标记连通区域和重心位置 删除连通区域 Matlab中可以使用graythresh(Img)函数设置二值化的阈值,再用im2bw转化为二值图像。在Matlab中,可以使用bwlabel()和bwlabeln()函数来...

    Matlab形态学图像处理:二值图像分割 标记连通区域和重心位置 删除连通区域

    尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/details/71440949
        Matlab中可以使用graythresh(Img)函数设置二值化的阈值,再用im2bw转化为二值图像。在Matlab中,可以使用bwlabel()和bwlabeln()函数来标记二值图像的连通区域。需要注意的是:所谓的连通区域标记是指对二值图像中白色像色而言,即值为1的像素进行标记,而黑色像素看作是背景颜色。当然,Matlab中还有个regionprops()函数可以用于统计图像区域的属性,如面积大小,重心位置。关于bwlabel()、bwlabeln()和regionprops()的用法,请查看相关博客吧

        本博客Matlab代码将实现的功能:将图像转为二值图像,分割出感兴趣的区域,并用“红色矩形线框”标记连通区域的面积,用蓝色点标记连通区域的重心位置,为了减少噪声的干扰,代码中将连通区域面积(像素个数)不足100的区域认为是噪声点,并将其删除(即置为背景黑色)。本人用PS制作了一个GIF动画图,以便大家观看效果图:

    clc;clear all;close all
    %% 清空变量,读取图像,并显示其属性
    clear;close all
    src = imread('rice.jpg');
    %显示原始图像
    figure,
    subplot(2,2,1),imshow(src),title('原图')
    
    %用ostu方法获取二值化阈值,进行二值化并进行显示
    level=graythresh(src);
    bw=im2bw(src,level);
    subplot(2,2,2),imshow(bw),title('二值图像')
    
    %运用开操作消去噪点
    se = strel('disk',2);
    openbw=imopen(bw,se);%对白色点而言
    subplot(2,2,3),imshow(openbw),title('开运算后的效果图')
    
    %获取连通区域,并进行显示
    % L = bwlabel(openbw,8);
    [L,num] = bwlabel(openbw,8);
    RGB = label2rgb(L);
    subplot(2,2,4),imshow(RGB),title('用rgb颜色标记不同区域')
    
    %获取区域的'basic'属性, 'Area', 'Centroid', and 'BoundingBox' 
    % stats = regionprops(openbw, 'basic');
     stats = regionprops(openbw, 'BoundingBox' ,'Area','Centroid' ,'PixelList' ); %统计白色的连通区域
    centroids = cat(1, stats.Centroid);
    
    %%
    noiseArea=100;
    figure,imshow(openbw),title('2')  
    hold on
    for i=1:size(stats)
        imshow(openbw)
        rectangle('Position',[stats(i).BoundingBox],'LineWidth',2,'LineStyle','--','EdgeColor','r'),
        plot(centroids(i,1), centroids(i,2), 'b*');             %每个连通区域的重心位置
        area = stats(i).Area;                                   %连通区域的面积
        if area<noiseArea                                       %若当前连通区域面积小于噪声点的面积,则该区域设置为0
            pointList = stats(i).PixelList;                     %每个连通区域的像素位置
            rIndex=pointList(:,2);cIndex=pointList(:,1);
            pointList = stats(i).PixelList;                     %连通区域的像素坐标
            openbw(rIndex,cIndex)=0;                            %连通区域的面积不足100,置为背景颜色
        end
        pause(1);
        saveas(gcf,sprintf('img/%d',i),'jpg')                   %保存图片
    end
    hold off





    展开全文
  • 提取连通分量的过程实际上也是标注连通分量的过程,通常的做法是给原图像中的每个连通区分配一个唯一代表该区域的编号,在输出图像中该连通区内的所有的像素值就赋值为该区域的编号,我们将这样的输出图像称为标注...

    基本概念

            提取连通分量的过程实际上也是标注连通分量的过程,通常的做法是给原图像中的每个连通区分配一个唯一代表该区域的编号,在输出图像中该连通区内的所有的像素值就赋值为该区域的编号,我们将这样的输出图像称为标注图像。这里介绍一种基于形态学的膨胀操作的提取连通分量的方法。
    在这里插入图片描述
            以8连通的情况为例,对于图(a)的内含多个连通分量的图像A,从仅为连通分量A1内部某个的图像B开始,不断采用如图©所示的结构S进行膨胀。由于其他连通分量与A1之间至少有一条一像素宽的空白缝隙(如图(a)中的虚线),3*3的结构元素保证了只要B在区域A1内部,则每次膨胀都不会产生位于图像A中其他连通区域之内的点,这样只需用每次膨胀后的结构图像和原始图像A相交,就能把膨胀限制在A1内部。随着对B的不断膨胀,B的区域不断生长,但每次膨胀后与图像A的相交又将B限制在连通分量A1地内部,直到最终B充满整个连通分量A1,对连通分量A1地提取完毕。
    在这里插入图片描述

    示例演示

            我们用OpenCV实现连通分量提取函数,然后进行细菌计数。完整工程代码。

    /*
     *only process binary image
     *iseight = true means eight connected, otherwise four connected
    */
    int LabelConnectedComponent(const cv::Mat &src, cv::Mat &dst, bool iseight = true)
    {
        Mat structelement;
        if(iseight)
            structelement = getStructuringElement(MORPH_RECT, Size(3, 3));
        else
             structelement = getStructuringElement(MORPH_CROSS, Size(3, 3));
    
        dst = Mat::ones(src.size(), src.type());
        Mat tmp = Mat::ones(src.size(), src.type()); // save last reuslt image
        Mat img = Mat::ones(src.size(), src.type()); //image B
        int labelnum = 0; //label of connected component
    
        Mat backupsrc;
        src.copyTo(backupsrc);
        for(int i = 0; i < backupsrc.rows; i++)
        {
            for(int j = 0; j < backupsrc.cols; j++)
            {
                if(backupsrc.at<uchar>(i, j) == 255)
                {
                    Mat img = Mat::ones(src.size(), src.type());
                    img.at<uchar>(i, j) = 255;
                    img.copyTo(tmp);  //Temporary save
                    labelnum++;
    
                    while(true)  // until not change
                    {
                        cv::dilate(img, img, structelement);
                        bitwise_and(img, src, img);
                        //if img do not change, this connected component is finished
                        if (cv::countNonZero(img - tmp) == 0)
                            break;
                        img.copyTo(tmp);
                    }
    
    
                    //label the connected component
                    for(int r = 0; r < img.rows; r++)
                    {
                        for(int c = 0; c < img.cols; c++)
                        {
                            if(img.at<uchar>(r, c) == 255)
                            {
                                backupsrc.at<uchar>(r, c) = 0;
                                dst.at<uchar>(r, c) = labelnum;
                            }
                        }
                    }
                }
            }
        }
        return labelnum;
    }
    

            先对原始图像进行膨胀
    在这里插入图片描述
            然后进行细菌统计,实际的细菌个数为21。
    在这里插入图片描述

    展开全文
  • 在matlab中有对图像连通区域进行求解的函数,即bwlabel。但是opencv里好像没有,所以这里自己实现一下,方便以后使用。   首先,我回顾一下bwlabel的参数和用法:  L =bwlabel(BW,n)  返回一个和BW大小相同的L...

    在matlab中有对图像的连通区域进行求解的函数,即bwlabel。但是opencv里好像没有,所以这里自己实现一下,方便以后使用。

     

    首先,我回顾一下bwlabel的参数和用法:

     L =bwlabel(BW,n)
       
    返回一个和BW大小相同的L矩阵,包含了标记了BW中每个连通区域的类别标签,这些标签的值为12num(连通区域的个数)。n的值为48,表示是按4连通寻找区域,还是8连通寻找,默认为8

    [L,num] = bwlabel(BW,n)这里num返回的就是BW中连通区域的个数。

     

     

    实现步骤:

    (1)将输入图像阈值化,若输入图像为彩色图像,则先灰度化后再阈值化为二值图像。

    (2)给二值图像添加一个是否已访问的属性,类型为Bool(避免死循环)

    (3)找到第一个非零的像素点,将其入栈并将其是否已访问的属性置为真。

    (4)以栈的大小是否为0作为结束条件,寻找栈顶元素相邻的八邻域非零像素点,并将它们入栈,结束后将栈顶元素删除。

    (5)当栈为空时,表明一个连通区域已经遍历完成,需继续找到下一个非空且未访问过的像素点作为起点,重复4步骤,直到所有的非零像素点都被访问完成。

    (6)当所有的连通区域求解完成之后,将像素点个数最大的连通区域标记出来即可。

     

    用到的数据结构

    typedef struct{

             boolvSign;//像素点是否被访问过的标记,ture已访问,false表示未访问,给图片添加的一个属性

             intpixelValue;//像素值

    }isVisit;

     

     

    typedef struct{

             CvPointregionPoint;//该连通区域起点的坐标

             intregionId;//第i个连通区域的标号

             intpointNum;//第i个连通区域的像素点的总个数

    }connectRegionNumSet;

    输入图像:

     

    求解的连通区域:


    类似于bwlabel的标记


    提取出最大的连通区域:

























    --------------------------------------------------------------------------------------------------分割线-----------------------------------------------------------------------------------------------------

    别急,代码在最下哦。

    只有一个文件main.cpp。


    #include<cv.h>

    #include<highgui.h>

    #include<iostream>

    usingnamespace std;

    typedefstruct{

             bool vSign;//像素点是否被访问过的标记,ture已访问,false表示未访问,给图片添加的一个属性

             int pixelValue;//像素值

    }isVisit;

    typedefstruct{

             CvPoint regionPoint;//该连通区域起点的坐标

             int regionId;//第i个连通区域的标号

             int pointNum;//第i个连通区域的像素点的总个数

    }connectRegionNumSet;

     

    intcalConnectRegionNums(IplImage *srcGray,vector<vector<isVisit>>& validPicture,vector<connectRegionNumSet> &regionSet);

     

    intmain(){

             IplImage * src =cvLoadImage("useConnectImage.jpg");//F:/MasterHomeWork/ImageProcess/ConnectNumProgramMy/

             IplImage * srcGray = NULL;

     

             if(src->nChannels==1)

                       goto next;

             srcGray = cvCreateImage(cvSize(src->width,src->height),8,1);

             cvCvtColor(src,srcGray,CV_RGB2GRAY);

    next:

             if(!srcGray)

                       cvThreshold(src,srcGray,66,255,CV_THRESH_BINARY);

             else

                       cvThreshold(srcGray,srcGray,66,255,CV_THRESH_BINARY);

     

             cvNamedWindow("srcBinaryGray");

             cvShowImage("srcBinaryGray",srcGray);

            

     

            

             //按照以下方法,申请的是堆heap内存空间,相对而言较大,足够一般用户使用,而且可以动态分配。

             vector<vector<isVisit> >validPoint;//此种申请发放只要电脑内存足够大,图片的尺寸也可足够大

             validPoint.resize(srcGray->height);

             for(int i =0;i<validPoint.size();i++)

                       validPoint[i].resize(srcGray->width);

     

             vector<connectRegionNumSet>regionSet;//存放找到的各个连通区域

             //regionSet.size()为连通区域的个数。

     

             cout<<"连通区域的数目:"<<calConnectRegionNums(srcGray,validPoint,regionSet)<<endl<<endl;//计算连通区域数目

            

             char text[3];//设置连通区域的编号,最小标号为0,最大编号为99

             CvFont font;//设置字体

             //参数从左到右:字体初始化,字体格式,字体宽度,字体高度,字体倾斜度,字体粗细,字体笔画类型

             cvInitFont(&font,CV_FONT_HERSHEY_COMPLEX, 0.6, 0.6, 0, 1, 8);

             for(int i=0;i<regionSet.size();i++){

     

                       cout<<"第"<<i<<"个连通区域的起点坐标 =("<<regionSet[i].regionPoint.x<<","<<regionSet[i].regionPoint.y<<")"<<",像素总点数="<<regionSet[i].pointNum<<endl;

     

                       if(i < 10){//连通区域的个数为个位数

                                text[0] = '0';

                                text[1] = '0'+i;

                       }

                       else{//连通区域的个数为十位数

                                text[0] ='0'+(i)/10;

                                text[1] ='0'+(i)%10;

                       }

                       text[2] = '\0';

                       cvPutText(src,text,regionSet[i].regionPoint,&font,cvScalar(0,0,255));

             }

     

             cvNamedWindow("src");

             cvShowImage("src",src);

             cvShowImage("srcGray",srcGray);

     

             cvWaitKey(0);

             cvReleaseImage(&src);

             cvReleaseImage(&srcGray);

             cvDestroyAllWindows();

    }

     

    intcalConnectRegionNums(IplImage *srcGray, vector<vector<isVisit>>& validPicture,vector<connectRegionNumSet> &regionSet)

    {

             int regionId = 1;//管理连通区域标号的便令

             connectRegionNumSet regionSetTemp;//临时用到的regionSetTemp类型中间变量

             uchar * ptr = (uchar*)(srcGray->imageData);

             for(int y=0; y<srcGray->height;y++){//给图片加上一个是否已访问的属性

                       ptr = (uchar*)(srcGray->imageData+y*srcGray->widthStep);

                       for(int x=0;x<srcGray->width; x++){

                                validPicture[y][x].pixelValue= (int)ptr[x];

                                validPicture[y][x].vSign= false;//开始时默认都未访问

                       }

             }

             vector<CvPoint> stack;//stack(栈),heap(堆)

             CvPoint foundValidPoint;

             for(int y=0; y<srcGray->height;y++){//给图片加上一个是否已访问的属性

                       for(int x=0;x<srcGray->width; x++){

                                if(validPicture[y][x].pixelValue&& !validPicture[y][x].vSign){//找到下一个连通区域的起点,即像素值非零且未被访问过的点

                                         inteachRegionAcc = 1;//表示即将要寻找的连通区域的总像素点个数;

                                         //将validPicture[y][x]点默认为即将生成的连通区域的起点

                                         regionSetTemp.regionPoint= cvPoint(x,y);//x表示列,y表示行

                                         regionSetTemp.regionId= regionId++;

                                         regionSetTemp.pointNum= 1;

                                         regionSet.push_back(regionSetTemp);

                                         //将该点设置为已访问,并对其执行入栈操作

                                         validPicture[y][x].vSign= true;

                                         stack.push_back(cvPoint(x,y));

                                         while(stack.size()){//当栈内为元素时,表示该连通区域的点已经全部访问

                                                   foundValidPoint= stack.back();//从栈尾开始寻找八连通的相邻点

                                                   stack.pop_back();//上一句已得到栈尾像素点,该点可以出栈了

                                                   inti = foundValidPoint.x;//t

                                                   intj = foundValidPoint.y;//k

                                                   intminY = (j-1<0?0:j-1);

                                                   intmaxY = ((j+1>srcGray->height-1?srcGray->height-1:j+1));

                                                   intminX = (i-1<0?0:i-1);

                                                   intmaxX = (i+1>srcGray->width-1?srcGray->width-1:i+1);

                                                   for(intk=minY; k<=maxY; k++){//在八连通范围内(两点之间距离小于根号2的点),表示其相邻点,入栈c

                                                            for(intt=minX; t<=maxX; t++){

                                                                     if(validPicture[k][t].pixelValue&& !validPicture[k][t].vSign){//validPicture[k][t]如果没有访问过

                                                                               validPicture[k][t].vSign= true;//标志为已访问,防止死循环

                                                                               stack.push_back(cvPoint(t,k));//入栈,以便再次迭代

                                                                               eachRegionAcc++;//相邻点的数目加1                                                        

                                                                     }

                                                            }

                                                   }

                                         }

                                         if(eachRegionAcc> 1){//要求:连通区域的点数至少要有两个

                                                   regionSet[regionSet.size()-1].pointNum= eachRegionAcc;

                                         }

                                         else{//单个像素点不算,如果单个像素点也算,去掉该else语句即可

                                                   regionSet.pop_back();//上述默认的即将生成的连通区域不符合要求,出栈

                                                   regionId--;

                                         }

                                }

                       }

             }

     

             //找到最大连通区域,并标记-----------------------------------------------

             int max_pointNum = 0; //最大连通区域的像素点个数

             int max_regionId = 0;  //最大连通区域的标号

             for(int i=0;i<regionSet.size();i++)

             {

                       if(max_pointNum <regionSet[i].pointNum)

                       {        max_pointNum = regionSet[i].pointNum;

                                max_regionId =i;

                       }

             }

     

             for(int i=0;i<regionSet.size();i++)

                       if(i!=max_regionId)

             {

                      

                                //标记

                       int x = regionSet[i].regionPoint.x;

                       int y =regionSet[i].regionPoint.y;

     

                       //重置每个像素点为未访问

                       for(int y=0;y<srcGray->height; y++){//给图片加上一个是否已访问的属性

                                for(int x=0;x<srcGray->width; x++){

                                         validPicture[y][x].vSign= false;//开始时默认都未访问

                                }

                       }

     

                       //将该点设置为已访问,并对其执行入栈操作

                       validPicture[y][x].vSign =true;

                       cvSet2D(srcGray,y,x,CV_RGB(0,0,0));

                       stack.push_back(cvPoint(x,y));

                       while(stack.size()){//当栈内为元素时,表示该连通区域的点已经全部访问

                                foundValidPoint =stack.back();//从栈尾开始寻找八连通的相邻点

                                stack.pop_back();//上一句已得到栈尾像素点,该点可以出栈了

                                int i = foundValidPoint.x;//t

                                int j =foundValidPoint.y;//k

                                int minY =(j-1<0?0:j-1);

                                int maxY =((j+1>srcGray->height-1?srcGray->height-1:j+1));

                                int minX =(i-1<0?0:i-1);

                                int maxX =(i+1>srcGray->width-1?srcGray->width-1:i+1);

                                for(int k=minY;k<=maxY; k++){//在八连通范围内(两点之间距离小于根号2的点),表示其相邻点,入栈c

                                         for(intt=minX; t<=maxX; t++){

                                                   if(validPicture[k][t].pixelValue&& !validPicture[k][t].vSign){//validPicture[k][t]如果没有访问过

                                                            validPicture[k][t].vSign= true;//标志为已访问,防止死循环

                                                            stack.push_back(cvPoint(t,k));//入栈,以便再次迭代

                                                            cvSet2D(srcGray,k,t,CV_RGB(0,0,0));             

                                                   }

                                         }

                                }

                       }

             }

            

             //找到最大连通区域,并标记-----------------------------------------------

     

             return regionSet.size();

     

     

    }
    展开全文
  • %提取连通分量测试图像,用来检测食物中的外来物 I=im2double(imread('D:\Gray Files\9-18a.tif')); %获得图像大小 [M,N]=size(I); %存放腐蚀后的图像 %设定提取门限,根据经验设定 th=0.808; %将原图像根据上述门限...
  • ●标记分割后图像(为二值图像)中各区域的简单而有效的方法是检查各像素与其相邻像素的连通性(四、八连通方法)。 1、像素标记: ●假设对一幅二值图像从左到右、从上向下进行扫描(起点在图像的左下方)。 ●...
  • 本文主要介绍在CVPR和图像处理领域中较为常用的一种图像区域(Blob)提取的方法——连通性分析法(连通区域标记法)。文中介绍了两种常见的连通性分析的算法:1)Two-pass;2)Seed-Filling种子填充,并给出了两个...
  • 本博客主要记录我利用Matlab学习图像处理的一些学习笔记,欢迎交流,批评指正。 本篇是第一篇,主要讲解图像处理的一些基础知识,列出如下: 1.二值化 2.开操作 3.连通区域提取 4.连通区域重心提取 5.bouding box...
  • 一.确定不规则连通区域的质心 原样本
  • 二值图像分析 二值图像即亮度值为 黑(0)和白(255) 二值图像分析 二值图像分析最重要的方法就是连通区域标记, 原理 将二值图像中白色像素(目标)的标记 —> 单独的连通区域形成一个被标识的块—> 获取...
  • Matlab图像处理学习笔记(一):二值化、开操作、连通区域提取、重心、ROI
  • 数字图像处理数字图像处理 一学习内容总结 第一章 绪论 1 什么是数字图像处理 2 使用数字图像处理领域的实例 3 数字图像处理的基本步骤 4 图像处理系统的组成 第二章 数字图像处理基础 1 视觉感知要素 2 光和电磁...
  • 图像处理标记连通

    2020-05-06 23:30:22
    二值图像分析最重要的方法就是连通区域标记,它是所有二值图像分析的基础,它通过对二值图像中白色像素(目标)的标记,让每个单独的连通区域形成一个被标识的块,进一步的我们就可以获取这些块的轮廓、外接矩形、...
  • 数字图像处理-前端实现 源码地址:github.com/weiruifeng/…数字图像处理(Digital Image Processing)是指用计算机进行的处理。说起数字图像处理大家都会想到C++有很多库和算法,MATLAB的方便,但自从有了canvas...
  • 本文介绍了使用skimage完成二值图像连通区域标记及属性计算的过程,并给出了详细的文档。
  • 连通分量的提取

    2017-02-28 22:34:54
    应用背景:在许多自动图像分析应用中,如何识别出图像中的不同之处,往往是从其二值图像中提取连通分量。 连通分量的定义:令S是一个像素子集,如果S中的全部像素之间存在一个通路(m通路或8通路),则可以说两个...
  • 数字图像处理与Python实现笔记之基础知识摘要绪论1 数字图像处理基础知识1.1 数字图像简介1.1.1 数字图像处理的目的1.1.2 数字图像处理的应用1.1.3 数字图像处理的特点1.1.4 常见的数字图像处理方法1.2 图像采集和...
  • 数字图像处理即根据用户需求,使用计算机技术对图像进行处理得到所需效果。 1.采样  我们获取到的图像一般为模拟图像,要让计算机进行处理需将其数字化,采样的作用就是将模拟图像转变为数字图像。一般来说,采样...
  • 本博客主要记录我学习运用matlab进行一些基本的图像处理的一些笔记,如果有不当的地方,欢迎批评指正,一起学习,一起进步。 本篇是第一篇,只涉及到一些基本的操作,涉及到的知识点如下: 1、二值化 2、开操作 ...
  • 图像处理与识别

    2017-03-23 09:45:57
    数字图像处理是对图像进行分析、加工、和处理,使其满足视觉、心理以及其他要求的技术。图像处理是信号处理在图像域上的一个应用。目前大多数的图像是以数字形式存储,因而图像处理很多情况下指数字图像处理。此外,...
1 2 3 4 5 ... 20
收藏数 4,514
精华内容 1,805
关键字:

图像处理连通区获取