形态学图像处理(一)

前几天一直在研究形态学在图像处理中的应用,查了很多资料。首先关于图像形态学的具体理论知识,课参考如下博客:
http://www.cnblogs.com/slysky/archive/2011/10/16/2214015.html
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

形态学操作及其公式小结:
形态学图像处理(一)_第1张图片

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

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

(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;
}

你可能感兴趣的:(图像处理,膨胀,形态学,腐蚀)