精华内容
下载资源
问答
  • 膨胀和腐蚀操作的核心内容是结构元素,(后面的开闭运算等重要的也是结构元素的设计,一个合适的结构元素的设计可以带来很好的处理效果)一般来说结构元素是由元素为1或者0的矩阵组成。结构元素为

    图像形态学介绍

    • 形态学的应用: 主要针对二值图进行,消除噪声、边界提取、区域填充、连通分量提取、凸壳、细化、粗化等;分割出独立的图像元素,或者图像中相邻的元素;求取图像中明显的极大值区域和极小值区域;求取图像梯度。
      在这里插入图片描述

    结构和元素形状

    • 膨胀和腐蚀操作的核心内容是结构元素,(后面的开闭运算等重要的也是结构元素的设计,一个合适的结构元素的设计可以带来很好的处理效果)一般来说结构元素是由元素为1或者0的矩阵组成。结构元素为1的区域定义了图像的领域,领域内的像素在进行膨胀和腐蚀等形态学操作时要进行考虑。
    • 一般来说,二维或者平面结构的结构元素要比处理的图像小得多。结构元素的中心像素,即结构元素的原点,与输入图像中感兴趣的像素值(即要处理的像素值)相对应。三维的结构元素使用0和1来定义x-y平面中结构元素的范围,使用高度值定义第三维。
    • API :getStructuringElement
    CV_EXPORTS_W Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
    
     //shape: \MORPH_CROSS(十字交叉形核) \MORPH_ELLIPSE(椭圆形核));
    // ksize: 结构元素大小;
    // anchor: 锚点 默认是Point(-1, -1)意思就是中心像素,也可以自己指定
    
    	//结构元素设计
    	Mat elementRect, elementCross, elementEllipse;
    
    	elementRect = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));//矩形
    	elementCross =  getStructuringElement(MORPH_CROSS, cv::Size(3, 3), cv::Point(-1, -1));//十字
    	elementEllipse = getStructuringElement(MORPH_ELLIPSE, cv::Size(5, 5), cv::Point(-1, -1));//椭圆
    
    	cout << "3X3矩形核:" << endl << elementRect << endl;
    	cout << "3X3十字交叉形核:" << endl << elementCross << endl;
    	cout << "5X5椭圆形核:" << endl << elementEllipse << endl << endl;
    

    在这里插入图片描述

    • 自定义结构元素
      使用Mat_模板类自定义5×5大小十字形、菱形、方形、x形结构元素:
    
        //自定义核(结构元素)
        Mat_<uchar> cross(5, 5);
        Mat_<uchar> diamond(5, 5);
        Mat_<uchar> x(5, 5);
        Mat_<uchar> square(5, 5);
    
        // Creating the cross-shaped structuring element
        cross <<
            0, 0, 1, 0, 0,
            0, 0, 1, 0, 0,
            1, 1, 1, 1, 1,
            0, 0, 1, 0, 0,
            0, 0, 1, 0, 0;
    
        // Creating the diamond-shaped structuring element
        diamond <<
            0, 0, 1, 0, 0,
            0, 1, 1, 1, 0,
            1, 1, 1, 1, 1,
            0, 1, 1, 1, 0,
            0, 0, 1, 0, 0;
    
        // Creating the x-shaped structuring element
        x <<
            1, 0, 0, 0, 1,
            0, 1, 0, 1, 0,
            0, 0, 1, 0, 0,
            0, 1, 0, 1, 0,
            1, 0, 0, 0, 1;
    
        // Creating the square-shaped structuring element
        square <<
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1;
            
    	//打印 x
        int xnr = x.rows;
        int xnl = x.cols;
        for (int j = 0; j < xnr; j++)
        {
            char* data = x.ptr<char>(j);
            for (int i = 0; i < xnl; i++)
            {
                int value = data[i];
                std::cout << value << " ";
            }
            std::cout << std::endl;
        }
    

    腐蚀和膨胀

    • 膨胀
      膨胀的具体操作:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。用最大值来替换中心像素
      膨胀的作用: 是将与物体接触的所有背景点合并到物体中,使目标增大,可添补目标中的空洞,通过对图像的胀大,使图像中的物体的轮廓向外发散,体积变大。
      在这里插入图片描述
      作用:

    • 腐蚀
      腐蚀的具体操作:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。用最小值来替换中心像素
      腐蚀的作用:是消除物体边界点,使目标缩小,可以消除小于结构元素的噪声点;腐蚀了就意味着图像中物体的边界被侵蚀了,轮廓向内收缩,体积变小了。
      在这里插入图片描述

    • PS: 要注意的是这里的膨胀和腐蚀的概念是针对图像中高亮区域而言的(二值图像中对应像素值255,白色),变大和缩小也是针对图像中高亮的部分。所以对图像执行膨胀,对高亮区域是胀大,面积增大,对暗区域相当于是腐蚀,面积缩小

    • API:dilateerode

    CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel,
                             Point anchor = Point(-1,-1), int iterations = 1,
                             int borderType = BORDER_CONSTANT,
                             const Scalar& borderValue = morphologyDefaultBorderValue() );
    
    void dilate(
        InputArray src,//输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一
        OutputArray dst,//目标图像,需要和源图片有一样的尺寸和类型
        InputArray kernel,//操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核,可以使用getStructuringElement来创建结构元素
        Point anchor=Point(-1,-1),//锚点的位置,其有默认值(-1,-1),表示锚位于中心
        int iterations=1,//迭代使用该函数的次数,默认值为1
        int borderType=BORDER_CONSTANT,//用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT
        const Scalar& borderValue=morphologyDefaultBorderValue() //当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释
    );
    //使用dilate函数时,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。
    
    • 实例
    	Mat src = imread("F:/code/images/hist_02.jpg");
        namedWindow("input", WINDOW_AUTOSIZE);
    	imshow("input", src);
    
        //二值图
        Mat gray, binary;
        cvtColor(src, gray, COLOR_BGR2GRAY);
        threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
        namedWindow("binary", WINDOW_AUTOSIZE);
        imshow("binary", binary);
    
        //腐蚀
        Mat elementRect = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));//矩形
        erode(binary, binary, elementRect);
        namedWindow("erode", WINDOW_AUTOSIZE);
        imshow("erode", binary);
    
        //膨胀
        Mat elementRect2 = getStructuringElement(MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));//矩形
        dilate(binary, binary, elementRect2);
        namedWindow("dilate", WINDOW_AUTOSIZE);
        imshow("dilate", src);
    

    开闭操作

    • 开运算:先腐蚀后膨胀,作用:用来消除图像中细小对象,在纤细点处分离物体和平滑较大物体的边界而有不明显改变其面积和形状,所有小到不能容纳结构元素的物体都会被移除。删除小的干扰快
      在这里插入图片描述
    • 闭运算:先膨胀后腐蚀,作用:用来填充目标内部的细小孔洞(fill hole),将断开的邻近目标连接,在不明显改变物体面积和形状的情况下平滑其边界,基本上所有小到不能完整容纳结构元素的空隙或间隙,都会被闭运算消除(即连起来),填充闭合区域
      在这里插入图片描述
    • API :morphologyEx
    CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst,
                                    int op, //操作的类型:MORPH_ERODE    = 0, //腐蚀
       										 MORPH_DILATE   = 1, //膨胀
        									 MORPH_OPEN     = 2, //开操作
          									 MORPH_CLOSE    = 3, //闭操作
        									 MORPH_GRADIENT = 4, //梯度操作
        									 MORPH_TOPHAT   = 5, //顶帽操作
    									     MORPH_BLACKHAT = 6, //黑帽操作
        									 MORPH_HITMISS  = 7  
                                    InputArray kernel,//结构元素
                                    Point anchor = Point(-1,-1), //锚点
                                    int iterations = 1,//迭代使用函数的次数
                                    int borderType = BORDER_CONSTANT,
                                    const Scalar& borderValue = morphologyDefaultBorderValue() );
    
    • 实例
    	 Mat src = imread("F:/code/images/cells.png");
        CV_Assert(!src.empty());
    
        Mat gray, binary;
        cvtColor(src, gray, COLOR_BGR2GRAY);
        threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
        bitwise_not(binary, binary, Mat());
        imshow("binary", binary);
    
        //开操作
        Mat dst;
        Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));//Size(15,1)为水平方向结构元素 Size(1, 15)为垂直方向结构元素
        morphologyEx(binary, dst, MORPH_OPEN, kernel, Point(-1, -1), 1);
        imshow("open-demo", dst);
    
        //闭操作
        Mat dst2;
        Mat kerne2 = getStructuringElement(MORPH_RECT, Size(15, 15), Point(-1, -1));
        morphologyEx(binary, dst2, MORPH_CLOSE, kerne2, Point(-1, -1), 1);
        imshow("close-demo", dst2);
    

    在这里插入图片描述

    形态学梯度

    • 通常所说形态学梯度(Morphological Gradient)是膨胀图像与腐蚀图像的之差得到的图像,也是基本梯度。数学表达式如下:
    dst = morph_grad(src,element) = dilate(src,element) - erode(src,element)
    
    • 梯度用于刻画目标边界或边缘位于图像灰度级剧烈变化的区域,形态学梯度根据膨胀或者腐蚀与原图作差组合来实现增强结构元素领域中像素的强度,突出高亮区域的外围。计算图像的形态学梯度是形态学重要操作,常常将膨胀和腐蚀基础操作组合起来一起使用实现一些复杂的图像形态学梯度。可以计算的梯度常见如下四种:
      在这里插入图片描述
    • 形态学梯度操作的输出图像像素值是在对应结构元素而非局部过渡区域所定义的领域中灰度级强度变化的最大值。对二值图像进行形态学操作可以将团块(blob)的边缘突出出来,可以用形态学梯度来保留物体的边缘轮廓。
    • API:MORPH_GRADIENT
    • 实例
     	 Mat src = imread("F:/code/images/yuan_test.png");
    
        Mat gray, binary;
        cvtColor(src, gray, COLOR_BGR2GRAY);
        imshow("input", gray);
    
        Mat basic_grad, inter_grad, exter_grad;
        
        //基本梯度
        Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
        morphologyEx(gray, basic_grad, MORPH_GRADIENT, kernel, Point(-1, -1), 1);
        imshow("basic gradient", basic_grad);
    
        //内部和外部梯度
        Mat dst1, dst2;
        erode(gray, dst1, kernel);
        dilate(gray, dst2, kernel);
    
        subtract(gray, dst1, inter_grad);
        subtract(dst2, gray, exter_grad);
        imshow("internal gradient", inter_grad);
        imshow("external gradient", exter_grad);
    
        //二值图
        threshold(basic_grad, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
        imshow("binary", binary);
    

    在这里插入图片描述
    在这里插入图片描述

    黑帽与顶帽

    • 当我们在处理一张图片的时候(例如提取眼底彩照的血管等信息),很多情况需要对这张图片进行一定的预处理,而通常我们就会用顶帽或者底帽变换。
    • 顶帽变换:原图像与开操作对象的差,dst = blackhat(src,element) = src - open(src,element);
      因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。因此,顶帽变换用于凸显暗背景上的亮物体。对二值图来说,进行顶帽变换或之后底帽变换看起来就像是加一个阴影,有一种立体的效果。顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。
    • 黑帽变换:闭操作与原图像的差值。,数学表达式为:dst = blackhat(src,element) = close(src,element) - src;
      黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。所以,黑帽运算用来分离比邻近点暗一些的斑块。黑帽变换可以用于凸显亮背景上的暗物体。二值图效果与顶帽变换相比,就是一个方向相反的阴影。
    • 实例
     Mat src = imread("F:/code/images/cross.png");
        imshow("input", src);
    
        Mat gray, binary;
        cvtColor(src, gray, COLOR_BGR2GRAY);
    
        threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
        imshow("binary", binary);
    
        //顶帽
         Mat k = getStructuringElement(MORPH_ELLIPSE, Size(15, 15), Point(-1, -1));
         Mat hothat;
         morphologyEx(binary, hothat, MORPH_TOPHAT, k);
         imshow("top hat demo", hothat);
    
         //黑帽
         morphologyEx(binary, hothat, MORPH_BLACKHAT, k);
         imshow("black hat demo", hothat);
    

    在这里插入图片描述

    击中击不中

    在这里插入图片描述

    • 实例
      例如怎么检测球网的好坏,采用设计十字结构元素,进行原二值图击中,球网节点完好的会检测出绳节点!
    	Mat src = imread("F:/code/images/cross.png");
        imshow("input", src);
    
        Mat gray, binary;
        cvtColor(src, gray, COLOR_BGR2GRAY);
    
        threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
        imshow("binary", binary);
    	
    	Mat hitmiss;
        Mat k = getStructuringElement(MORPH_CROSS, Size(15, 15), Point(-1, -1));
        morphologyEx(binary, hitmiss, MORPH_HITMISS, k);
        imshow("hit and miss", hitmiss);
    

    在这里插入图片描述

    展开全文
  • 以图像的形态特征为研究对象,通过设计一套独特的数字图像处理方法和理论来描述图像的基本特征和结构通过引入集合的概念来描述图像中元素与元素、部分与部分的关系运算。因此,数学形态学的运算由基础的集合运算(并...

    计算机视觉学习小练习2(MATLAB)

    理论基础:
    1.数字形态学
    以图像的形态特征为研究对象,通过设计一套独特的数字图像处理方法和理论来描述图像的基本特征和结构通过引入集合的概念来描述图像中元素与元素、部分与部分的关系运算。因此,数学形态学的运算由基础的集合运算(并、交、补等来)定义,并且所有的图像矩阵能够方便地转换为集合。
    2.图像去噪方法
    数字图像在获取、传输过程中都可能会受到噪声的污染,常见的噪声主要有高斯噪声和椒盐噪声。其中,高斯噪声主要由摄像机传感器元器件内部产生的,椒盐噪声主要是由图像切割所产生的黑白相间的亮暗点噪声,“椒” 表示和黑色噪声,“盐”表示白色噪声。
    数字图像去噪也可以分为空域和频域来完成。空域图像去噪常用的由均值滤波算法和中值滤波算法,主要是针对图像像素领域的运算来达到去噪效果。频域图像去噪首先是对数字图像进行某种变换,将其从空域转换到频域(傅里叶变换、小波变换等),然后对频域中的变换系数进行处理,最后对图像进行反变换,将其从频域转换到空域来达到去噪效果。`
    数学形态学原理参考《数字图像处理》。
    为了简化算法实现步骤,具体实现过程可以选择将串联处理结果与原始图像进行差异值计算的方式来作为权值向量,在通过对串联结果加权求和的方式来进行计算。对其进行数学形态学滤波器级联滤波去噪的仿真,选区一副人脸图像,加入泊松噪声,通过构建不同的串联滤波器、并联滤波器来进行滤波去噪实验,最后在计算绘制PSNR值曲线(峰值信噪比)来显示去噪效果。主函数代码如下:

    clc;clear all; close all
    filename = fullfile(pwd, 'images/im.jpg');
    Img = imread(filename);
    if ndims(Img) == 3                        %ndims是matlab中求一个数组维数的函数。
    	I = rgb2gray(Img);
    else
    	I = Img:
    end
    Ig = imnoise(I,'poisson');
    %获取算子
    s = GetStrelList();
    %串联去噪
    e = ErodeList(Ig, s);
    %计算权重
    f = GetRateList(Ig, e);
    %并联
    Igo = GetRemoveResult(f, e);
    %显示结果
    figure;
    subplot(1, 2 ,1); imshow(I, []); title('原图像');    %用空矩阵([])用于[低-高],imshow将使用[最小(i(:))最大(i(:)];即i中的最小值显示为黑色,最大值显示为白色。中间值为中间灰度。
    subplot(1, 2 ,2); imshow(I, []); title('噪声图像');
    figure;
    subplot(2, 2 ,1); imshow(e.eroded_co12, []); title('串联1处理结果');
    subplot(2, 2 ,2); imshow(e.eroded_co22, []); title('串联2处理结果');
    subplot(2, 2 ,3); imshow(e.eroded_co32, []); title('串联3处理结果');
    subplot(2, 2 ,4); imshow(e.eroded_col4, []); title('串联4处理结果');
    figure;
    subplot(1, 2 ,1); imshow(Ig, []); title('噪声图像');
    subplot(1, 2 ,2); imshow(Igo, []); title('并联去噪图像');
    

    获取算子函数GetStrelList将返回指定的线型算子,具体代码如下:

    function s = GetStrelList()
    %获取算子
    %输出参数
    %s ——算子结构体
    
    %生成四种不同的串联算子来对比结果
    %Strel函数主要用来构建形态学运算中的结构元素,语法为strel(shape,parameters)。shape为形状参数,即设置什么样的结构元素;parameters为控制形状参数大小方向的参数
    s.co11 = strel('line',5,-45);  
    s.co12 = strel('line',7,-45);   %为构造的线性结构元素,7为长度(size),-45为角度
    %%生成串联算子
    s.co21 = strel('line',5,45);
    s.co22 = strel('line',7,45);
    %生成串联算子
    s.co31 = strel('line',3,90);
    s.co32 = strel('line',5,90);
    %生成串联算子
    s.co41 = strel('line',3,0);
    s.co42 = strel('line',5,0);
    

    串联去噪函数ErodeList根据输入的滤波算子,通过imerode逐个处理,在进行串联处理。imdilate or imerode函数需要两个基本输入参数,即待处理的输入图像和结构元素对象。具体代码如下:

    function e = ErodeList(Ig,s)
    %串联去噪
    %input param:Ig—图像矩阵;s—算子
    %output param:e—处理结果
    e.eroded_co12 = imerode(imerode(Ig,s.co11),s.co12);
    e.eroded_co22 = imerode(imerode(Ig,s.co21),s.co22);
    e.eroded_co32 = imerode(imerode(Ig,s.co31),s.co32);
    e.eroded_co42 = imerode(imerode(Ig,s.co41),s.co42);
    

    权值计算函数GetRateList将根据串联结果与原始图像的差异程度进行计算,求出每个处理后的差异图像矩阵的总和,最后四个矩阵总和相加得到总值。代码如下:

    function f = GetRateList(Ig, e)
    %计算权重
    %输入参数:Ig = 图像矩阵,e = 串联结果
    %输出参数:f = 结果
    f.df1 = sum(sum(abs(double(e.eroded_co12)-double(Ig))));
    f.df2 = sum(sum(abs(double(e.eroded_co22)-double(Ig))));
    f.df3 = sum(sum(abs(double(e.eroded_co32)-double(Ig))));
    f.df4 = sum(sum(abs(double(e.eroded_co42)-double(Ig))));
    f.df = sum = ([f.df1 f.df2 f.df3 f.df4]);
    

    上一步求的权值,各个矩阵的元素总和除以四个矩阵的元素总和得到权值,并联去噪函数GetRemoveResult将根据输入的权值向量、串联结果,通过加权求和的方式进行处理。

    function Igo = GetRemoveResult(f,e)
    %并联去噪
    %输入两个参量,f—权值向量
    Igo = f.df1/f.df*double(e.eroded_co12)+f.df2/f.df*double(e.eroded_co22)+f.df3/f.df*double(e.eroded_co32)+f.df4/f.df*double(e.eroded_co42);
    Igo = mat2gray(Igo);
    

    最终处理结果:明显并联去噪效果更好。

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    注:本文为学习所做记录,备忘,无其他用途。

    展开全文
  • 样本1样本2样本3而我设计的轮廓模板是轮廓模板据说 halcon有比较NB的 形状模板匹配算子,不过,如果图像预处理做得很好,可以用很简单的算法解决 问题,比如用 Hu矩、Zenike矩、灰度共生矩阵等特征值,或者...

    我以前做过一个项目,是提取 一个 锅盖葫芦,然后 定位葫芦的方向。

    其中用到了 形态学、二值化、轮廓分析,最后计算主方向。

    其中,必须进行形态学运算,不然无法提取 完整的轮廓。

    368825c62decb925d0ed1dd9830034e6.png

    样本图1

    0d1f7799b81703c6fa98b57f2c846b40.png

    样本图2

    a1e3ff5013d836d8334404ffebabd474.png

    样本图3

    而我设计的轮廓模板是

    9e5bb2dd8b79528352ef11e827c92589.png

    轮廓模板

    据说 halcon有比较NB的 形状模板匹配算子,不过,如果图像预处理做得很好,可以用很简单的算法解决 问题,比如用 Hu矩、Zenike矩、灰度共生矩阵等特征值,或者根据一些 尺寸、圆度、面积等等。

    为了提取完整的 形状轮廓,我设计了如下的算法流程:

    72fa1903ddde7a8647564ecad1bea6ab.png

    算法流程(可视化模块)

    1. 图像 resize 到 0.25/0.25 ,因为原图有 2592x1944; resize之后,648x486;

    通过这个运算,可以减少10以上的数据量。

    2.使用重要的 形态学 开运算,强化 边缘特征。

    3.使用简单 的 二值化,直接 得到分割图

    4.生成 轮廓

    5.过滤轮廓

    6.显示

    1.执行 resize,使用 opencv API

    CV_EXPORTS_W void resize( InputArray src, OutputArray dst, Size dsize, double fx = 0, double fy = 0, int interpolation = INTER_LINEAR )

    2.执行 开运算,使用 API

     cv::morphologyEx(src, dst, cv::MORPH_OPEN, kernel, cv::Point(-1, -1), iterations, borderType, borderValue);

    使用了 Rect 15x15,强化 黑色的边缘,保证轮廓完整性

    1c7265ba9d4918e30eec27c11e53fd6a.png

    强化边缘1

    3.简单二值化,使用了 API

    CV_EXPORTS_W double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );

    此处使用 thresh = 210,就可以很好的分割轮廓了

    1cab573119f7d30fcafd040865c999b8.png

    分割目标1

    4.生成轮廓,使用 API

    CV_EXPORTS void findContours( InputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset = Point())

    此处使用 RETR_CCOMP, CHAIN_APPROX_NONE 参数,得到了轮廓列表。

    a4f1981abe94ba4456157be5503f2211.png

    轮廓1

    5.然后使用 轮廓过滤,使用 API

    CV_EXPORTS_W RotatedRect minAreaRect( InputArray points )

    此处使用 width 范围 [100,250] height 范围 [100,250]

    358f4585eb520c4c88bccb3d90a90c30.png

    目标轮廓1

    总体效果:

    6e1bba6bf7fcf9078ad5faf22637d1a4.png

    图1

    0525fb519f02fd94257fbda70a1f9617.png

    图2

    4a7f90f53906aaf0cba9decc86037e72.png

    图3

    011ec846d50a95f5217a3684e16ed439.png

    图4

    总结一下,主要算法:

    1. 形态学滤波,强化边缘特征,便于二值化分割
    2. 使用 简单的二值化,不需要很复杂的算法。因为很多工业生产,可以控制生产环境,比如光源、位置、摄像角度等

    3.使用 连通域 分析算法

    4.分析连通域,根据 面积、拟合的矩形、圆、三角形、多边形等等 特征,搜索可能的目标。

    ……

    其中算法的执行时间:

    34470fc150deade7bfea7dc5c723b385.png

    算法时间13.15ms

    很多项目都是用简单算法,就可以解决问题。找到合适的算法,才是最难的。

    所以打好算法基本功,理解场景模型,有利于解决问题。

    比如还有后面的 主方向:

    03a6ad61d9fb9f1496a7edfec387ec8f.png

    添加了PCA 主方向

    2b4014d85ce4983f486699021f77af6f.png

    计算 PCA中心和方向

    大家的关注,是我的动力。有机会给大家分享更多的算法和应用。

    展开全文
  • 6.9.3 散点图矩阵 6.10 轮廓 6.10.1 二维轮廓 6.10.2 三维轮廓 6.11 向量 6.11.1 罗盘 6.11.2 羽状 6.11.3 箭头 6.11.4 法线 第七章 MATLAB 高级绘图功能 7.1 彗星 7.1.1 ...
  • MATLAB图形图像处理

    热门讨论 2011-01-03 12:20:11
    6.9.3 散点图矩阵 6.10 轮廓 6.10.1 二维轮廓 6.10.2 三维轮廓 6.11 向量 6.11.1 罗盘 6.11.2 羽状 6.11.3 箭头 6.11.4 法线 第七章 MATLAB 高级绘图功能 7.1 彗星 7.1.1 二维彗星轨迹...
  • 6.9.3 散点图矩阵 6.10 轮廓 6.10.1 二维轮廓 6.10.2 三维轮廓 6.11 向量 6.11.1 罗盘 6.11.2 羽状 6.11.3 箭头 6.11.4 法线 第七章 MATLAB 高级绘图功能 7.1 彗星 7.1.1 二维彗星轨迹...
  • 四、形态矩阵法创建机构运动方案 ………………………………………… 6 五、机械系统运动循环 ……………………………………………………… 8 六、机械系统运动方案简图 …………………………………………...
  • 2.2.1 矩阵和数组的概念及其区别 2.2.2 矩阵的构造 2.2.3 矩阵大小及结构的改变 2.2.4 矩阵下标引用 2.2.5 矩阵信息的获取 2.2.6 矩阵的保存和加载 2.3 运算符 2.3.1 算术运算符 2.3.2 关系运算符 ...
  •  根据内容的侧重点不同,全书分为4 部分共20 章:第1~5 章为基础部分,讲解MATLAB R2014a 概述、MATLAB 基础知识、数组与矩阵、MATLAB 编程基础及数据可视化等;第6~8 章为数学应用部分,讲解数据分析、符号数学...
  • FPGA图像处理系列——实现窗处理

    千次阅读 2015-06-27 12:18:17
    本博文参考了《FPGA嵌入式图像处理系统设计》一书。该书的英文版下载链接:http://download.csdn.net/detail/lzy272942518/6949349 窗处理是图像处理中常见的一种处理,它的思想是对于图像矩阵,通过一个固定大小...

            本博文参考了《FPGA嵌入式图像处理系统设计》一书。该书的英文版下载链接:http://download.csdn.net/detail/lzy272942518/6949349

    窗处理是图像处理中常见的一种处理,它的思想是对于图像矩阵,通过一个固定大小(例如3*3)的小矩阵对图像进行运算操作。常用的窗处理包括Sobel边缘检测,形态学操作,模糊滤波,高斯滤波等。在基于PC的图像处理领域,可以方便的实现窗处理操作。比如,在opencv库中可以自己随意构建窗口大小,然后调用相关的函数实现窗处理。

    FPGA是一种可定制的逻辑电路,它拥有并行的结构特征,在设计上能实现硬件并行和流水线技术,可以实现算法的加速,而且性价比较高。本文即根据Sobel算法的理论,结合FPGA的结构特征,在FPGA上设计并尝试实现了Sobel窗处理算法方案。

    Sobel边缘检测的思想是:该算子包含两组3 x 3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度查分近似值。如果以A代表原始图像,Gx及Gy分别代表经纵向向及横向边缘检测的图像,其公式如下(来源于百度图片):


    对于FPGA实现Sobel,首先,是检测窗的实现。这种窗扩展了点运算,以一个局部邻域或窗口内像素值的函数运算结果作为输出:

    Q[x,y] = f(I[x,y],...,I[x+△x,y+△y]),  (△x,△y)∈W

    其中,W是I[x,y]为中心的窗口。以3×3大小的窗口为例,如图所示:


    Sobel算子所需的窗口大小为3×3。在设计过程中,窗口应当满足以下要求:

    1.能同时对窗口中所有的元素进行并行操作。

    2.窗口采用流水的形式遍历整个图像。

    设计的思路是:因为窗口在遍历图像过程中,每一个像素都会被窗口多次使用,因此需要通过缓存来存储像素,使得它们能在后续的窗口位置被重复利用。在FPGA中,可以设计3个单口行缓存(linebuffer),借助状态机和列计数值实现这种窗口,采用流水处理的方法,实现加速计算。如图为窗口结构:


    其中状态信号用环形计数器来实现(计数值0-2),其驱动时钟为每一行第一个像素的像素时钟。窗口的行0由3个移位寄存器组成;行1——行2由状态机决定和行缓存的对应关系。窗口的控制逻辑如表1所示:

    表1 窗口的控制逻辑

    输入行

    状态

    行缓存0

    行缓存1

    行缓存2

    输出行

    0

    0

    (行2)

    (行1)

    (空)

    1

    1

    行1

    (行2)

    (空)

    2

    2

    行2

    行1

    1

    3

    0

    行2

    行1

    2

    4

    1

    行1

    行2

    3

    5

    2

    行2

    行1

    4

    6

    0

    行2

    行1

    5

     

    ……

    ……

    ……

    ……

    ……

      (注:行x对应窗口结构中的行x)

      对于窗口操作,存在的一个问题是边界部分无法得到处理。不过,本系统的窗口比较小,那么边界像素的输出可以不计算。这样输出的图像比输入图像减小了1行和1列,并不会影响图像显示效果。

    具体实现思路:

    1.窗口模块:

     3个行缓存,每个大小为640×8 bit;

     状态机,状态信号(0-2),以每一行第一个像素时钟作为驱动状态信号的时钟;

     3个移位寄存器,每个大小为8 bit,作为检测窗口的第一行

    窗口的实现,需要建立一个像素时钟驱使的always块,根据窗口结构和表1的控制逻辑,构造窗口;

    2.边缘判断模块:

        通过窗口可在像素点P处得到以其为中心,周围8个点的像素值。根据Sobel算子结构,进行计算。设置一个阈值,当计算后的值大于此阈值时,判定此像素为边缘。


    关键部分代码(verilog):

    always@(posedge PCLK)begin//产生行时钟,作为状态机驱动时钟
    begin
    	 if(VtcHCnt==0)
    	   Line_CLK <= 1;
    	 else
    	   Line_CLK <= 0;
    end
    end
    
    reg[1:0] state;
    initial state = 0;
    
    always@(posedge Line_CLK)begin//产生状态计数器
     if(VtcVCnt==1)
     state <= 2'b00;
     else begin
       if(state == 2'b10)
    	   state <= 2'b00;
    	else 
    	   state <= state + 1;
    	end
    end 
    //定义窗口第0行的三个元素
    reg[7:0]S_Window0;
    reg[7:0]S_Window1;
    reg[7:0]S_Window2;
    
    
    //定义行缓存
    reg[7:0]LineBuffer0[639:0];
    reg[7:0]LineBuffer1[639:0];
    reg[7:0]LineBuffer2[639:0];
    always@(posedge PCLK)begin
       case(state)
    	 2'b00: begin
    	    <span style="white-space:pre">	</span>LineBuffer0[VtcHCnt] <= GRAY;
    		 LineBuffer1[VtcHCnt] <= LineBuffer1[VtcHCnt];
    		 LineBuffer2[VtcHCnt] <= LineBuffer2[VtcHCnt];	
    		 S_Window0 <= GRAY;
    		 S_Window1 <= S_Window0;
    	         S_Window2 <= S_Window1;
    		if(VtcHCnt>=2&&VtcVCnt>=3)begin
    		 if((S_Window0 + S_Window1*2 + S_Window2)>(LineBuffer1[VtcHCnt-2]+LineBuffer1[VtcHCnt-1]*2 +LineBuffer1[VtcHCnt]))
    	          DOUT_reg <= ((S_Window0 + S_Window1*2  + S_Window2 -LineBuffer1[VtcHCnt-2]-LineBuffer1[VtcHCnt-1]*2  -LineBuffer1[VtcHCnt]))/4;
    		 else
    		 DOUT_reg <= (LineBuffer1[VtcHCnt-2]+LineBuffer1[VtcHCnt-1]*2  +LineBuffer1[VtcHCnt]-(S_Window0 + S_Window1*2  + S_Window2))/4;
    		end 
    		end 
    	 2'b01: begin
    	         LineBuffer1[VtcHCnt] <= GRAY;
    		 LineBuffer0[VtcHCnt] <= LineBuffer0[VtcHCnt];
    		 LineBuffer2[VtcHCnt] <= LineBuffer2[VtcHCnt];		 
    		 S_Window0 <= GRAY;
    	         S_Window1 <= S_Window0;
    	         S_Window2 <= S_Window1;
    	   if(VtcHCnt>=2&&VtcVCnt>=3)begin
       	 if((S_Window0 + S_Window1 *2 + S_Window2)>(LineBuffer2[VtcHCnt-2]+LineBuffer2[VtcHCnt-1]*2  +LineBuffer2[VtcHCnt]))
    		 DOUT_reg <= ((S_Window0 + S_Window1*2  + S_Window2 -LineBuffer2[VtcHCnt-2]-LineBuffer2[VtcHCnt-1] *2 -LineBuffer2[VtcHCnt]))/4;
    		 else
    		 DOUT_reg <= (LineBuffer2[VtcHCnt-2]+LineBuffer2[VtcHCnt-1] *2 +LineBuffer2[VtcHCnt]-(S_Window0 + S_Window1*2  + S_Window2))/4;	
    		end		   
    		end
    	 2'b10: begin
    	    <span style="white-space:pre">	</span> LineBuffer2[VtcHCnt] <= GRAY;	 
    		 LineBuffer0[VtcHCnt] <= LineBuffer0[VtcHCnt];
    		 LineBuffer1[VtcHCnt] <= LineBuffer1[VtcHCnt];	
    		 S_Window0 <= GRAY;
    	    S_Window1 <= S_Window0;
    	    S_Window2 <= S_Window1;
    		if(VtcHCnt>=2&&VtcVCnt>=3)begin
    		 if((S_Window0 + S_Window1*2  + S_Window2)>(LineBuffer0[VtcHCnt-2]+LineBuffer0[VtcHCnt-1] *2 +LineBuffer0[VtcHCnt]))
    		 DOUT_reg <= ((S_Window0 + S_Window1*2  + S_Window2 -LineBuffer0[VtcHCnt-2]-LineBuffer0[VtcHCnt-1]*2  -LineBuffer0[VtcHCnt]))/4;
    		 else
    		 DOUT_reg <= (LineBuffer0[VtcHCnt-2]+LineBuffer0[VtcHCnt-1]*2  +LineBuffer0[VtcHCnt]-(S_Window0 + S_Window1*2  + S_Window2))/4;
    	    end
    		end
    	default:	begin
    	       DOUT_reg <= DOUT_reg;
    			 LineBuffer0[VtcHCnt] <= LineBuffer0[VtcHCnt];
    		    LineBuffer1[VtcHCnt] <= LineBuffer1[VtcHCnt];	
    		    LineBuffer2[VtcHCnt] <= LineBuffer2[VtcHCnt];	
    			 end
    	endcase
    
    end 









    展开全文
  • 全书从头到尾共设计了472个问题(很多是由学生提出来的),有问有答,循序渐进,逐步将各种图像技术依次介绍。这种形式除能帮助课堂教学外,也很适合自学,因为每一段都解决了一个疑问,对自学者会很有吸引力。书中...
  • OpenCV实现了很多图像处理中的...Mat型图像矩阵可以直接应用于OpenCV的大多数算法,例如图像形态学操作、行列号访问像素、仿射变换等。最近在研究中,我需要读取一些多波段的tiff影像,OpenCV读取tiff的时候,有个...
  • CUDA支持GPU上的一部分纹理硬件(它们原本是为图形处理而设计的),所以,纹理内存一般会用于加速图片的滤波和图片的resize操作上。 纹理内存实质上市全局内存的特殊形态,全局内存被绑定为纹理内存,对其的读,写...
  • 10.7.6 利用矩阵进行其他 几何变化 419 10.8 本章小结 422 第11章 图像的增强处理 423 11.1 图像的简单平滑 424 11.1.1 邻域处理的基本概念 424 11.1.2 图像的简单平滑原理 427 11.1.3 图像简单平滑的算法实现 427 ...
  • 第4部分“GUI界面编程”,包括第27~第29章,从程序设计、图形用户界面设计入手讲解了软件编程方面的问题,最后给出了图像处理软件及界面编程的实际例子。 本书写作结构明晰,图文并茂,案例丰富,具有很强的可操作...
  • 全书分为12章,包括绪论,数字图像基础,灰度变换与空间滤波,频域滤波,图像复原与重建,彩色图像处理,小波及多分辨率处理,图像压缩,形态学图像处理,图像分割,表现与描述,目标识别。 目录编辑 前言15 致谢19 ...
  • 2.3.1 空间灰度层共现矩阵 14 2.3.2 纹理能量测量 16 2.3.3 纹理的结构分析方法和纹理梯度 18 2.3.4 纹理识别示例——云类自动识别 19 2.4 图像的形态学处理技术 20 2.4.1 基本概念 21 2.4.2 开运算和闭...
  • 数据结构(C++)有关练习题

    热门讨论 2008-01-02 11:27:18
    4、用邻接矩阵或邻接实现一个有向的存储,并实现单源最短路径算法的实现(这个类的一个成员函数),并能输出该的关键路径。 注:1、要用面向对象的方法设计代码; 2、一个是一个类的实例; 3、类...

空空如也

空空如也

1 2 3 4 5
收藏数 94
精华内容 37
关键字:

形态矩阵图设计