图像处理找边界_图像处理卷积图像边界的像素点怎么处理 - CSDN
  • 边界跟踪:内边界跟踪算法解释 边界跟踪是基于边缘的分割常用方法之一,用于区域已分出(二值或已标注),但边界未知的情况。分为内边界与外边界。内边界为区域的一个子集,外边界不是区域的一个子集。 内边界...

                             边界跟踪:内边界跟踪算法解释

     

            边界跟踪是基于边缘的分割常用方法之一,用于区域已分出(二值或已标注),但边界未知的情况。分为内边界与外边界。内边界为区域的一个子集,外边界不是区域的一个子集。

            内边界跟踪算法具体的实施方法比较明确,但在学习的时候感觉稍微有点抽象,结合自己的理解拓展一下。
            具体算法:

                                                                                                           图1

     

                                                                                                             图2


           具体有四步,以上图片中包含四邻域与八邻域,下面主要以以八邻域为例,四邻域原理相似。

     

           第一步中图像处理是以整个图片的最左上角为坐标原点(0,0),所以最靠近左上角的P0为最小行数与最小列数之像素。定义的dir为边界移动的方向,具体为八邻域中的八个方向(0,1,2,3,4,5,6,7)中的一个(如图2中的(b)图),此时默认初始值为7(右下方向)。

           第二步中先判断dir的奇偶性(默认值为7),然后对dir进行计算更改(就是根据上下文调整邻域扫描的初始方向))进行下一轮边界扫描。具体操作看图,画的不是很好,有点乱。

      

     

          这里的奇偶判断及为何是+6,+7具体原理尚未能有效想明白,有待进一步学习。

          第三步比较好理解边界是一个闭合空间,搜索到首尾相接时即结束。

         第四步及将计算了两遍的Pn-1与Pn删除,最后边界为P0到Pn-2。

         水平有限,理解可能有误,加之文笔不好,凑合看哈。

         PS:后边发现有一个不确定的地方,搜索P0的时候dir是默认的7还是先判断dir的奇偶性再按第二步的步骤进行呢?这里先按初始7计算。

         参考文献:

         《图像处理、分析与机器视觉(第三版)》     作者 :Milan Sonka、艾海舟。

     

    展开全文
  • 边界提取         要在二值图像中提取物体的边界,容易想到的一个方法是将所有物体内部的点删除(置为背景色)。具体地说,可以逐行扫描图像,如果发现一个黑点的8个邻域都...

    边界提取

            要在二值图像中提取物体的边界,容易想到的一个方法是将所有物体内部的点删除(置为背景色)。具体地说,可以逐行扫描图像,如果发现一个黑点的8个邻域都是黑点,则该点为内部点,在目标图 像中将它删除。实际上这相当于采用一个3*3的结构元素对原图进行腐蚀,使得只有那些8个邻域都有黑点的内部点被保留,再用原图像减去腐蚀后的图像,恰好删除了这些内部点,留下了边界像素。这过程如下图所示。
    在这里插入图片描述

    示例演示

            利用OpenCV实现上面边界提取的功能。

    #include<opencv2/opencv.hpp>
    using namespace cv;
    
    int main(int argc, char *argv[])
    {
       Mat originimage = imread("E:/TestData/head_portrait.bmp");
       Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
       imshow("OriginImage", originimage);
       Mat erodeimage;
       cv::erode(originimage, erodeimage, element);
       imshow("ErodeImage", erodeimage);
    
       Mat output = originimage -  erodeimage;
       imshow("Output", output);
    
    
        waitKey(0);
        return 0;
    
    }
    

    运行结果

    在这里插入图片描述

    边界跟踪

            为了依次记录边界上的每个像素,边界跟踪首先按照某种扫描规则找到目标物体边界上的一个像素,然后就以该像素为起始点,根据某种顺序(如顺时针或逆时针)依次找出物体边界上的其余像素,直到又回到起始点,完成整条边界的跟踪。
    例如,我们可以按照从左到右、从上到下的顺序扫描图像,这样首先会找到目标物体最左上方的边界点P0.显然,这个点的左侧及上侧都不可能存在边界点(否则左侧或上侧的边界点就会称为第一个被扫描到的边界点),因此不妨从左下方逆时针开始探查,如左下方的点是黑点,直接跟踪至此边界点,否则探查方向逆时针旋转45度,直至找到第一个黑点为止,跟踪至此边界点。找到边界点后,在当前探查方向的基础上顺时针回转90度,继续用上述方法搜索下一个边界点,知道探查又回到初始的边界点P0,则完成整条边界的跟踪。

    示例演示

            在一幅图像中,实现跟踪多个边界的功能。对于带孔洞的物体也可以跟踪至其孔洞的轮廓。

    #include<opencv2/opencv.hpp>
    using namespace cv;
    
    //only process binary image
    //black is boundary
    std::vector<std::vector<cv::Point>> TraceBoundary(Mat &image)
    {
        std::vector<std::vector<Point>> boundaryset;
        Point start, current, next; // start point and current point
        //search dirction array
        int direction[8][2] ={{-1, 1}, //left-down
                              {0, 1}, // down
                              {1, 1}, //right-down
                              {1, 0}, //right
                              {1, -1}, //right-up
                              {0, -1}, //up
                              {-1, -1}, //left-up
                              {-1, 0}  // left
                             };
        int begindirection = 0, currentdirection = 0;
        bool atstart = false, findboundary = false;
    
        for(int i = 0; i < image.rows; i++)
        {
            for(int j = 0; j < image.cols; j++)
            {
                if(image.at<uchar>(i, j) == 0) //find start point
                {
                    start.x = j;
                    start.y = i;
                    current = start;
                    atstart = true;
                    findboundary =  true;
                    std::vector<Point> points;
                    points.push_back(current);
                    std::cout << "Start: " << j << " " << i << std::endl;
                    while((current.x != start.x) || (current.y != start.y) || atstart)
                    {
                        atstart = false;
    
                        //search next point
                        next.x = current.x + direction[currentdirection][0];
                        next.y = current.y + direction[currentdirection][1];
                        int searchtimes = 1;
                        while(next.x < 0 || next.x >= image.cols || next.y < 0 || next.y >= image.rows || image.at<uchar>(next) == 255)
                        {
                            currentdirection++; //rotate 45 degrees counterclockwise
                            currentdirection %= 8;
                            next.x = current.x + direction[currentdirection][0];
                            next.y = current.y + direction[currentdirection][1];
                            //there are no boundary points in 8 domains, which means they are isolated points
                            if(++searchtimes >= 8)
                                break;
                        }
                        if(image.at<uchar>(next) == 0) // find next point
                        {
                            std::cout << "Next: " << next.x << " " << next.y << std::endl;
                            points.push_back(next);
                            current = next;
                            currentdirection -= 2;
                            if(currentdirection < 0)
                                currentdirection += 8;
    
                        }
                        else // not find next point
                        {
                            findboundary = false;
                            break;
                        }
                    }
                    if(findboundary)
                    {
                        boundaryset.push_back(points);
                        for(auto &p : points)
                        {
                            image.at<uchar>(p) = 255;
                        }
                    }
                } // find boundary one time
            } // for j
        } // for i
        return boundaryset;
    }
    
    int main(int argc, char *argv[])
    {
       Mat originimage = imread("E:/TestData/head_boundary.bmp");
       imshow("OriginImage", originimage);
    
       Mat image;
       cvtColor(originimage, image, CV_BGR2GRAY);
       std::vector<std::vector<Point>> boundaryset = TraceBoundary(image);
    
       //show result
       Mat result;
       originimage.copyTo(result);
       for(auto &points : boundaryset)
       {
           for(auto &p : points)
           {
                result.at<Vec3b>(p)[0]= 0;
                result.at<Vec3b>(p)[0]= 0;
                result.at<Vec3b>(p)[1]= 255;
           }
       }
       imshow("Output", result);
    
    
        waitKey(0);
        return 0;
    
    }
    

    运行结果

    在这里插入图片描述

    展开全文
  • matlab图像处理之二值图像内外边界跟踪 注:原文链接:http://www.cnblogs.com/tiandsp/archive/2013/04/26/3045747.html  目标内边界的像素全都在目标里面,目标外边界的像素全都不在目标上,是包围着目标的。 二...

     matlab图像处理之二值图像内外边界跟踪

    注:原文链接:http://www.cnblogs.com/tiandsp/archive/2013/04/26/3045747.html
           目标内边界的像素全都在目标里面,目标外边界的像素全都不在目标上,是包围着目标的。
    二值图像内外边界的计算都是有两种方法的,所以一共是4种算法,不过实际用到跟踪的只有一个而已。
     
           首先是内边界跟踪:
    第一种方法不是跟踪方法。步骤是先对原图像腐蚀,然后用原图像减去腐蚀后的图像就得到边界了。
    第二种方法是跟踪方法。步骤如下:
    1.遍历图像。
    2.标记第一个遇见像素块的前景像素(i,j)。
    3.对这个像素周围八邻域逆时针搜索,如果搜索到周围有前景像素,那么更新坐标(i,j)为(i',j'),并标记。
    4.不断执行第3步直到再次遇见此像素块第一次标记的像素。
    5.继续执行第1步。
     
         然后是外边界跟踪:
    第一种方法和求内边界第一种方法类似。先对原图像进行膨胀,然后用膨胀后的图像减去原图像即可。
         第二种也不算跟踪方法,只是标记算法而已。就是将图像中前景像素周围的非前景像素标记一下就行了。
     
    效果如下:

    原图:

    内边界:

    外边界:

    matlab程序如下:

    内边界:

    clear all;
    close all;
    clc;
    
    img=imread('rice.png');
    img=img>128;
    imshow(img);
    [m n]=size(img);
    
    imgn=zeros(m,n);        %边界标记图像
    ed=[-1 -1;0 -1;1 -1;1 0;1 1;0 1;-1 1;-1 0]; %从左上角像素,逆时针搜索
    for i=2:m-1
        for j=2:n-1
            if img(i,j)==1 && imgn(i,j)==0      %当前是没标记的白色像素
                if sum(sum(img(i-1:i+1,j-1:j+1)))~=9    %块内部的白像素不标记
                    ii=i;         %像素块内部搜寻使用的坐标
                    jj=j;
                    imgn(i,j)=2;    %本像素块第一个标记的边界,第一个边界像素为2
                    
                    while imgn(ii,jj)~=2    %是否沿着像素块搜寻一圈了。
                        for k=1:8           %逆时针八邻域搜索
                            tmpi=ii+ed(k,1);        %八邻域临时坐标
                            tmpj=jj+ed(k,2);
                            if img(tmpi,tmpj)==1 && imgn(tmpi,tmpj)~=2  %搜索到新边界,并且没有搜索一圈
                                ii=tmpi;        %更新内部搜寻坐标,继续搜索
                                jj=tmpj;
                                imgn(ii,jj)=1;  %边界标记图像该像素标记,普通边界为1
                                break;
                            end
                        end
                    end
                    
                end
            end
        end
    end
    
    figure;
    imgn=imgn>=1;
    imshow(imgn,[]);
    
    %不过要是真取二值图像内边界,通常是原图减去其腐蚀图就行了
    se = strel('square',3); 
    imgn=img-imerode(img,se);    
    figure;
    imshow(imgn)
    
    

    外边界:

    clear all;
    close all;
    clc;
    
    img=imread('rice.png');
    img=img>128;
    imshow(img);
    [m n]=size(img);
    
    imgn=zeros(m,n);        %边界标记图像
    ed=[-1 -1;0 -1;1 -1;1 0;1 1;0 1;-1 1;-1 0]; %从左上角像素判断
    for i=2:m-1
        for j=2:n-1
            if img(i,j)==1      %如果当前像素是前景像素
                
                for k=1:8
                    ii=i+ed(k,1);
                    jj=j+ed(k,2);
                    if img(ii,jj)==0    %当前像素周围如果是背景,边界标记图像相应像素标记
                        imgn(ii,jj)=1;
                    end
                end
                
            end
        end
    end
        
    figure;
    imshow(imgn,[]);
    
    %不过要是真取二值图像外边界,通常是原图膨胀图减去原图就行了
    se = strel('square',3); 
    imgn=imdilate(img,se)-img;    
    figure;
    imshow(imgn)



    展开全文
  • BORDER_DEFAULT(边界默认)openCV中默认的处理方法,自动填充图像边界(效果像是映像一样)。 BORDER_CONSTANT – (边界常数)填充边缘用指定像素值,使用常数填充边界,不一定是0或者RGB黑色。 BORDER_REPLICATE ...
    1. BORDER_DEFAULT(边界默认)openCV中默认的处理方法,自动填充图像边界(效果像是映像一样)。
    2. BORDER_CONSTANT – (边界常数)填充边缘用指定像素值,使用常数填充边界,不一定是0或者RGB黑色。
    3. BORDER_REPLICATE – (边界复制)填充边缘像素用已知的边缘像素值,复制原图中最临近的行或者列。
    4. BORDER_WRAP – (边界包装)用另外一边的像素来补偿填充。
    展开全文
  • 边界跟踪利用边缘检测算法可以检测出图像中的边界点。但是在很多情况下,仅仅检测出边界点是不够地,必须通过边界跟踪得到边界点序列等数据,为图像分析做准备。对二值图像边界跟踪可基于八个方向码进行,如图所示...
  • 今天下午要完成一部分实验,中间涉及到二值边界的提取,去百度了一下。根据自己实验的结果表明,方法确实是好用,关键自己之前写过,但是效果不如网上的好!需要在别人的基础上结合自己的需要或者自己已有的结果具体...
  • 链码在图像提取的后期即模式识别是一个很重要的特征,比如进行数字识别或者文字识别都会用到链码的特征,而链码的提取则可以借助于边界跟踪算法获取边界序列,注意是边界序列而不是边界边界很容易获取,但是要想把...
  • 边界点和边界段可以用图(graph)结构(在图结构中,每个结点既可有多个直接前驱,也可有多个直接后继)表示,通过在图中进行搜索对应最小代价的通道也可以找到闭合边界。(主要用并行边界算法) 优点:是一种...
  • 图像边界处理方法 1 忽略边界数据 2.拓展图像(四周补上数据) 使用P值填充(如:P=0) 复制图像边界像素的值 镜像图像边界像素的值 周期扩展 1. 忽略边界数据 优点:滤波后的图像中所有像素点都能由整个模版...
  • 目录 ...初学OpenCV图像处理的小伙伴肯定对什么高斯函数、滤波处理、阈值二值化等特性非常头疼,这里给各位分享一个小项目,可通过摄像头实时动态查看各类图像处理的特点,也可对各位调参、测试...
  • 形象点说,核就像一个可以滑动的小四方形,叠加于处理的图片矩阵之上——有点像用单词书(需要处理图像)被单词时附带的红色遮挡塑料片(核)。  比如一个要处理的、尺寸为30x30矩阵的图片,而核是一个3x3的矩阵...
  • 在对图像进行卷积运算的时候,为了防止图像边界区域产生边缘效应,即一部分卷积核位于图像外,需要对原始图像进行延拓处理,这里介绍一种周期镜像延拓图像边界的方法。A=imread('Lean.tif'); [m,n]=size(A); p=m; ...
  • 第九章 形态学图像处理 第九章 形态学图像处理 一腐蚀和膨胀 1 腐蚀 2 膨胀 二开操作与闭操作 三击中或击不中变换 四一些基本的形态学算法 1 边界提取 2 孔洞填充 3 连通分量的提取 4 凸壳 5 细化 6 粗化 7 ...
  • 基于边界图像分割技术是基于灰度不连续性进行的分割方法,其基础就是边缘检测边缘检测利用梯度、差分、拉普拉斯算子及高通滤波等处理方法进行图像锐化,增强图像边缘,再进行一次阈值化处理,便可以将边缘增强的...
  • 形态学一般是使用二值图像,进行边界提取,骨架提取,孔洞填充,角点提取,图像重建。  基本的算法:膨胀腐蚀,开操作,闭操作,击中击不中变换  边界提取主要涉及腐蚀和求补集操作 代码如下: int ...
  • 三边缘连接和边界检测 通常情况下,检测出的像素并不能完全描述边缘特性,需要紧接连接算法,才能组合成有意义的边缘或区域边界。 1局部处理 2区域处理 按给出的顺序追踪这些点 3使用霍夫变换的全局处理 通常所...
  •  链码(又称为freeman码)是用曲线起始点的坐标和边界点方向代码来描述曲线或边界的方法,常被用来在图像处理、计算机图形学、模式识别等领域中表示曲线和区域边界。它是一种边界的编码表示法,用边界方向作为编码...
  • 本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程《数字图像处理》及课件进行讲解,主要通过MFC单文档视图实现显示BMP图像增强处理,包括图像普通平滑、高斯平滑、不同算子的图像锐化知识...
1 2 3 4 5 ... 20
收藏数 70,959
精华内容 28,383
关键字:

图像处理找边界