• 热门专题

形态学图像处理(一)

作者:  发布日期:2016-04-11 21:28:21
Tag标签:形态学  图像处理  
  • 形态学操作及其公式小结:

    这里写图片描述

    上述操作是对二值图像进行操作的,当腐蚀、膨胀是最基本的操作,其他操作是基于这两个操作和集合论的组合。对于灰度图像来说,腐蚀和膨胀也是基本其他操作的基础,但是灰度图像腐蚀和膨胀不同于二值图像的腐蚀和膨胀。

    灰度图像的腐蚀和膨胀定义如下:

    (1)腐蚀:当结构元素b的原点位于(x,y)处时,用b对图像f进行腐蚀,是查找f中与结构元素b重合区域灰度级别最小的值,然后把最小的灰度值赋值给点(x,y):
    这里写图片描述

    (2)膨胀:当结构元素b的原点位于(x,y)处时,用b的反射(-b)对图像f进行腐蚀,是查找f中与结构元素b的反射重合区域灰度级别最大的值,然后把最大的灰度值赋值给点(x,y):
    这里写图片描述

    关于灰度图像的应用有:
    (1)形态学梯度:
    这里写图片描述

    (2)顶帽变换:
    这里写图片描述

    (3)底帽变换:
    这里写图片描述

    具体代码如下:

    #include<opencv.hpp>
    #include<highgui.h>
    #include<imgproc.hpp>
    using namespace cv;
    
    //把灰度图像转化为二值图像
    Mat changeToBinaryImage(Mat grayImage)
    {
        Mat binaryImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        //转化为二值图像
        for (int i = 0; i < grayImage.rows; i++)
        {
            for (int j = 0; j < grayImage.cols; j++)
            {
                if (grayImage.data[i*grayImage.step + j]>100)
                {
                    binaryImage.data[i*grayImage.step + j] = 255;
                }
                else
                {
                    binaryImage.data[i*grayImage.step + j] = 0;
                }
            }
        }
        imshow('binaryImage', binaryImage);
    
        return binaryImage; 
    }
    
    //创建结构元素
    //一般结构元素 关于原点对称
    //Mat createSE()
    //{
    //  int a[3][3]={ 0,1,0,
    //  1,1,1,
    //  0,1,0};
    //  Mat structureElement(3, 3, CV_8UC1, a);
    //}
    
    //二值图像腐蚀操作
    Mat binaryErosion(Mat binaryImage, Mat se)
    {
        //二值图像移动
        Mat window(se.rows, se.cols, CV_8UC1);
    
        //定义一个矩阵,存储腐蚀后的图像
        Mat binaryErosionImage(binaryImage.rows, binaryImage.cols, CV_8UC1, Scalar(0));
    
        for (int i = (se.rows-1)/2; i < binaryImage.rows-(se.rows-1)/2; i++)
        {
            for (int j = (se.cols - 1) / 2; j < binaryImage.cols - (se.cols - 1) / 2; j++)
            {
                //先设置第i行第j列像素值为255,即白色
                binaryErosionImage.data[i*binaryImage.step + j] = 255;
                for (int row = 0; row < se.rows; row++)
                {
                    for (int col = 0; col < se.cols; col++)
                    {
                        //把se对应的元素赋值到与se结构相同的矩阵中
                        window.data[row*window.step + col] = binaryImage.data[(i + row - (window.rows - 1) / 2)*binaryImage.step + (j + col - (window.cols - 1) / 2)];
                    }
                }
                //比较se与window中的像素值
                int row, col;
                for (row = 0; row < se.rows; row++)
                {
                    for (col = 0; col < se.cols; col++)
                    {
                        if (se.data[row*se.step + col] != window.data[row*se.step + col])
                        {
                            break;
                        }
                    }
                    if (col == se.cols)
                    {
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }
                if (row == se.rows&&col == se.cols)
                {
                    binaryErosionImage.data[i*binaryImage.step + j] = 0;
            }
            }
        }
    
        //imshow('binaryErosionImage', binaryErosionImage);
    
        return binaryErosionImage;
    }
    
    //二值图像膨胀操作
    Mat binaryDilation(Mat binaryImage, Mat se)
    {
        //二值图像移动
        Mat window(se.rows, se.cols, CV_8UC1);
    
        //定义一个矩阵,存储膨胀后的图像
        Mat binaryDilationImage(binaryImage.rows, binaryImage.cols, CV_8UC1, Scalar(0));
    
        for (int i = (se.rows - 1) / 2; i < binaryImage.rows - (se.rows - 1) / 2; i++)
        {
            for (int j = (se.cols - 1) / 2; j < binaryImage.cols - (se.cols - 1) / 2; j++)
            {
                //先设置第i行第j列像素值为255,即白色
                binaryDilationImage.data[i*binaryImage.step + j] = 255;
                for (int row = 0; row < se.rows; row++)
                {
                    for (int col = 0; col < se.cols; col++)
                    {
                        //把se对应的元素赋值到与se结构相同的矩阵中
                        window.data[row*window.step + col] = binaryImage.data[(i + row - (window.rows - 1) / 2)*binaryImage.step + (j + col - (window.cols - 1) / 2)];
                    }
                }
                //比较se与window中的像素值
                //只要有一个相匹配 就把像素值设为0,即置黑
                int flag = 0;  //标记是否有对应相等的像素值:0表示没有,1表示有
                int row, col;
                for (row = 0; row < se.rows; row++)
                {
                    for (col = 0; col < se.cols; col++)
                    {
                        if (se.data[row*se.step + col] == window.data[row*se.step + col])
                        {
                            flag = 1;
                            break;
                        }
                    }
                    if (flag)
                    {
                        break;
                    }
                }
                if (flag)
                {
                    //如果有交集,就设置为黑,即0
                    binaryDilationImage.data[i*binaryImage.step + j] = 0;
                }
            }
        }
    
        //imshow('binaryDilationImage', binaryDilationImage);
        return binaryDilationImage;
    }
    
    //灰度图像腐蚀操作
    Mat grayErosion(Mat grayImage,Mat se)
    {
        //结构元素移动时所对应的源图像区域
        Mat window(se.rows, se.cols, CV_8UC1);
    
        //定义一个矩阵,存储腐蚀后的图像
        Mat grayErosionImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        for (int i = (se.rows - 1) / 2; i < grayImage.rows - (se.rows - 1) / 2; i++)
        {
            for (int j = (se.cols - 1) / 2; j < grayImage.cols - (se.cols - 1) / 2; j++)
            {
                //先设置第i行第j列像素值为255,即白色
                grayErosionImage.data[i*grayImage.step + j] = 255;
                for (int row = 0; row < se.rows; row++)
                {
                    for (int col = 0; col < se.cols; col++)
                    {
                        //把se对应的元素赋值到与se结构相同的矩阵window中
                        window.data[row*window.step + col] = grayImage.data[(i + row - (window.rows - 1) / 2)*grayImage.step + (j + col - (window.cols - 1) / 2)];
                    }
                }
                //比较se与window中的像素值
                //在灰度图像中,腐蚀是取window中最小的值赋值给原点所对用的像素
                int minPixel = 255;
                int row, col;
                for (row = 0; row < se.rows; row++)
                {
                    for (col = 0; col < se.cols; col++)
                    {
                        if (window.data[row*se.step + col] < minPixel)
                        {
                            minPixel = window.data[row*se.step + col];
                        }
                    }   
                }   
                grayErosionImage.data[i*grayImage.step + j] = minPixel;
            }
        }
    
        /*imshow('grayErosionImage', grayErosionImage);*/
    
        return grayErosionImage;
    }
    
    //灰度图像膨胀操作
    Mat grayDilation(Mat grayImage,Mat se)
    {
        //结构元素移动时所对应的源图像区域
        Mat window(se.rows, se.cols, CV_8UC1);
    
        //定义一个矩阵,存储腐蚀后的图像
        Mat grayDilationImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        for (int i = (se.rows - 1) / 2; i < grayImage.rows - (se.rows - 1) / 2; i++)
        {
            for (int j = (se.cols - 1) / 2; j < grayImage.cols - (se.cols - 1) / 2; j++)
            {
                //先设置第i行第j列像素值为255,即白色
                grayDilationImage.data[i*grayImage.step + j] = 255;
                for (int row = 0; row < se.rows; row++)
                {
                    for (int col = 0; col < se.cols; col++)
                    {
                        //把se对应的元素赋值到与se结构相同的矩阵window中
                        window.data[row*window.step + col] = grayImage.data[(i + row - (window.rows - 1) / 2)*grayImage.step + (j + col - (window.cols - 1) / 2)];
                    }
                }
                //比较se与window中的像素值
                //在灰度图像中,膨胀是取window中最大的值赋值给原点所对用的像素
                int maxPixel = 0;
                int row, col;
                for (row = 0; row < se.rows; row++)
                {
                    for (col = 0; col < se.cols; col++)
                    {
                        if (window.data[row*se.step + col] > maxPixel)
                        {
                            maxPixel = window.data[row*se.step + col];
                        }
                    }
                }
                grayDilationImage.data[i*grayImage.step + j] = maxPixel;
            }
        }
    
        /*imshow('grayDilationImage', grayDilationImage);*/
    
        return grayDilationImage;
    }
    
    //二值图像开操作
    Mat binaryOpen(Mat binaryImage, Mat se)
    {
        Mat openImage(binaryImage.rows,binaryImage.cols,CV_8UC1,Scalar(0));
    
        openImage = binaryDilation(binaryErosion(binaryImage, se), se);
    
        return openImage;
    }
    
    //二值图像闭操作
    Mat binaryClose(Mat binaryImage, Mat se)
    {
        Mat closeImage(binaryImage.rows, binaryImage.cols, CV_8UC1, Scalar(0));
    
        closeImage = binaryErosion(binaryDilation(binaryImage, se), se);
    
        return closeImage;
    }
    
    //灰度图像开操作
    Mat grayOpen(Mat grayImage, Mat se)
    {
        Mat openImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        openImage = grayDilation(grayErosion(grayImage, se), se);
    
        return openImage;
    }
    
    //灰度图像闭操作
    Mat grayClose(Mat grayImage, Mat se)
    {
        Mat closeImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        closeImage = grayErosion(grayDilation(grayImage, se), se);
    
        return closeImage;
    }
    
    //二值图像边界提取
    Mat binaryBorder(Mat binaryImage,Mat se)
    {
        Mat borderImage(binaryImage.rows, binaryImage.cols, CV_8UC1, Scalar(0));
        Mat erosionImage(binaryImage.rows, binaryImage.cols, CV_8UC1, Scalar(0));
        erosionImage = binaryErosion(binaryImage,se);
    
        for (int i = 0; i < erosionImage.rows; i++)
        {
            for (int j = 0; j < erosionImage.cols; j++)
            {
                if (binaryImage.data[i*erosionImage.step+j]!=erosionImage.data[i*erosionImage.step+j])
                {
                    borderImage.data[i*erosionImage.step + j] = 255;
                }
            }
        }
    
        return borderImage;
    }
    
    //灰度图像边界提取
    Mat grayBorder(Mat grayImage, Mat se)
    {
        Mat borderImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        borderImage = grayImage - grayErosion(grayImage, se);
    
        return borderImage;
    }
    
    //灰度图像梯度
    Mat gradient(Mat grayImage, Mat se)
    {
        Mat gradient(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        gradient = grayDilation(grayImage, se) - grayErosion(grayImage, se);
    
        return gradient;
    }
    
    //灰度图像的顶帽运算 T(f)=f-fob
    Mat topHat(Mat grayImage,Mat se)
    {
        Mat topHatImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        topHatImage = grayImage - grayOpen(grayImage,se);
    
        return topHatImage;
    }
    
    //灰度图像的底帽运算 B(f)=f⋅b-f
    Mat bottomHat(Mat grayImage, Mat se)
    {
        Mat bottomHatImage(grayImage.rows, grayImage.cols, CV_8UC1, Scalar(0));
    
        bottomHatImage = grayClose(grayImage, se)-grayImage;
    
        return bottomHatImage;
    }
    
    
    int main()
    {
        Mat src = imread('E:\project\images\32.jpg');
    
        Mat grayImage(src.rows, src.cols, CV_8UC1);
        //转化为灰度图像
        cvtColor(src, grayImage, CV_BGR2GRAY);
    
        imshow('original Image',src);
        imshow('gray Image', grayImage);
    
        //转化为二值图像
        Mat binaryImage = changeToBinaryImage(grayImage);
    
        //创建模板  一般结构元素关于自身原点对称  
        //也可以自定义结构元素  下面的变量是3*3的矩阵 全部为0  
        Mat structureElement(3, 3, CV_8UC1, Scalar(0));
    
        //调用二值图像腐蚀函数
        //binaryErosion(binaryImage, structureElement);
        imshow('binaryErosionImage', binaryErosion(binaryImage, structureElement));
    
        //调用二值图像膨胀函数
        //binaryDilation(binaryImage, structureElement);
        imshow('binaryDilationImage', binaryDilation(binaryImage, structureElement));
    
        //调用灰度图像腐蚀函数
        //grayErosion(grayImage, structureElement);
        imshow('grayErosionImage', grayErosion(grayImage, structureElement));
    
        //调用灰度图像膨胀函数
        //grayDilation(grayImage, structureElement);
        imshow('grayDilationImage', grayDilation(grayImage, structureElement));
    
        //调用二值图像开操作
        imshow('binaryOpenImage',binaryOpen(binaryImage,structureElement));
    
        //调用二值图像闭操作
        imshow('binaryCloseImage', binaryClose(binaryImage, structureElement));
    
        //调用灰度图像开操作
        imshow('grayOpenImage', grayOpen(grayImage, structureElement));
    
        //调用灰度图像闭操作
        imshow('grayCloseImage', grayClose(grayImage, structureElement));
    
        //二值图像边界提取
        imshow('binaryBorderImage',binaryBorder(binaryImage,structureElement));
        //灰度图像边界提取
        imshow('grayBorderImage',grayBorder(grayImage,structureElement));
    
        //调用灰度梯度函数
        imshow('Gradient', gradient(binaryImage, structureElement));
    
        //调用顶帽函数
        imshow('topHat',topHat(grayImage,structureElement));
    
        //调用底帽函数
        imshow('bottomHat', bottomHat(grayImage, structureElement));
    
        cvWaitKey(0);
    
        return 0;
    }
About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规