首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

形态学图像处理

  • 23-09-22 20:41
  • 3463
  • 11150
blog.csdn.net

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

形态学操作及其公式小结:
这里写图片描述

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

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

(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
#include
#include
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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
注:本文转载自blog.csdn.net的Sun-Flower的文章"https://blog.csdn.net/swj110119/article/details/51123072"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top