【Matlab 系列教程】图像处理基础解析

1. 简介

Image Processing Toolbox™ 为图像处理、分析、可视化和算法开发提供了一套全面的参考标准算法和工作流 App。您可以使用深度学习和传统图像处理技术执行图像分割、图像增强、去噪、几何变换和图像配准。工具箱支持处理二维、三维和任意大的图像。

1-1. 快速入门

在这部分你可以学到:

imread()
imwrite()
iminfo()
imshow()
delete()
figure()
subplot()
rgb2gray()
imdistline()
imfindcircles()
viscircles()

基于文件读写图像数据,获取图像文件的内容信息
一般文件的导入和导出

  • imread 从图形文件读取图像
  • imwrite 将图像写入图形文件
  • imfinfo 有关图形文件的信息

处理 DICOM 文件

  • dicominfo Read metadata from DICOM message
  • dicomread 读取 DICOM 图像
  • dicomwrite Write images as DICOM files

案例实践1:基本图像导入、处理和导出

素材图片:

pout.png

Step1. 读取(保证图片放在与脚本的同一级目录)并展示图片
I = imread('pout.tif'); 此时工作区会出现变量 I 其中存储着 pout.tif 的图像矩阵
imshow(I)
显示图像,使用imshow功能。您也可以在 Image Viewer app 中查看图像。imtool功能打开图像查看器应用程序,该应用程序提供了显示图像和执行一些常见图像处理任务的集成环境。图像查看器应用程序提供了imshow的所有图像显示功能,但也提供了访问其他几个工具来导航和探索图像,如滚动条,像素区域工具,图像信息工具和对比度调整工具

pout.png

Step2. 检查图像在工作区中的显示方式
使用whos命令检查imread函数如何在工作区中存储图像数据。您还可以在工作区浏览器中检查该变量。imread函数返回变量I中的图像数据,这是一个291 × 240元素的uint8数据数组。

>> whos I
  Name        Size             Bytes  Class    Attributes

  I         291x240            69840  uint8

Step3. 提高图像对比度
为了凸显前后对比度,先使用 imhist显示直方图
查看图像像素强度的分布。tif图像是一个对比度稍低的图像。要查看图像中的强度分布,可以通过调用imhist函数创建一个直方图。(在调用imhist之前使用figure命令,这样直方图就不会覆盖当前图形窗口中图像I的显示。) 请注意直方图表明图像的强度范围相当窄。该范围不包括[0,255]的潜在范围,并且缺少可以产生良好对比度的最高值和低值。

figure
imhist(I)

使用histeq函数提高图像的对比度。直方图均衡化将强度值扩展到图像的整个范围。显示图像。(该工具箱包括执行对比度调整的其他几个功能,包括imadjustadapthisteq,以及图像查看器中可用的交互式工具,如调整对比度工具。)

I2 = histeq(I);
figure
imshow(I2)
pout.png

将处理前后图片以及对应的直方图显示在同一个figure中,其中用到(自定义 figure 名称subplot 方法close all 关闭所有figure等)

pout.png
点击查看代码
close all;
figure('Name', '计院研僧');
subplot(2,2,1);
imshow(reshape(I,[291,240]));
title('对比增强图像前');

subplot(2,2,2); 
imshow(reshape(I2,[291,240]));
title('对比增强图像后');

subplot(2,2,3); 
imhist(reshape(I,[291,240]));
title('增强图像前直方图');

subplot(2,2,4); 
imhist(reshape(I2,[291,240]));
title('增强图像后直方图');

Step4. 将调整后的图片写入磁盘文件
使用imwrite函数将新调整的图像I2写入磁盘文件。这个例子在文件名中包含了文件扩展名'.PNG',因此imwrite函数将图像以PNG格式写入文件,但您可以指定其他格式。
imwrite (I2, 'pout2.png');

Step5. 检查新写入文件的内容
imfinfo('pout2.png')

查看输出

>> imfinfo('pout2.png')

ans = 

  包含以下字段的 struct:

                  Filename: 'D:\Documents\MATLAB\Examples\pout2.png'
               FileModDate: '26-Aug-2023 18:03:14'
                  FileSize: 36938
                    Format: 'png'
             FormatVersion: []
                     Width: 240
                    Height: 291
                  BitDepth: 8
                 ColorType: 'grayscale'
           FormatSignature: [137 80 78 71 13 10 26 10]
                  Colormap: []
                 Histogram: []
             InterlaceType: 'none'
              Transparency: 'none'
    SimpleTransparencyData: []
           BackgroundColor: []
           RenderingIntent: []
            Chromaticities: []
                     Gamma: []
               XResolution: []
               YResolution: []
            ResolutionUnit: []
                   XOffset: []
                   YOffset: []
                OffsetUnit: []
           SignificantBits: []
              ImageModTime: '26 Aug 2023 10:03:14 +0000'
                     Title: []
                    Author: []
               Description: []
                 Copyright: []
              CreationTime: []
                  Software: []
                Disclaimer: []
                   Warning: []
                    Source: []
                   Comment: []
                 OtherText: []

案例实践2:检测和测量图像中的圆形对象

此示例说明如何使用 imfindcircles 自动检测图像中的圆或圆形对象。它还显示如何使用 viscircles 可视化检测到的圆。

素材图片:

pout.png

Step1. 加载图像
此示例使用包含各种颜色的圆形塑料片的图像。

rgb = imread('coloredChips.png');
imshow(rgb)

除了有大量要检测的圆之外,从圆检测的角度来看,此图像还有一些有趣的特点:

有不同颜色的塑料片,它们相对于背景有不同对比度。一方面,蓝色和红色塑料片在此背景上形成强烈的对比。另一方面,一些黄色塑料片与背景的对比不明显。

请注意一些塑料片重叠在一起,而另一些塑料片则靠得很近,几乎互相接触。对于目标检测来说,场景中存在重叠的对象边缘和对象遮挡通常具有挑战性。

Step2. 确定搜索圆的半径范围
imfindcircles 需要半径范围来搜索圆。找到合适半径范围的快速方法是使用交互式工具 imdistline 获得各种对象半径的近似估计值。

d = imdistline;
pout.png

imdistline 会创建一个可拖动的工具,可以移动该工具以匹配塑料片,并且可以读取数字以获得其半径的近似估计值。大多数塑料片的半径在 21-23 个像素的范围内。为保险起见,请使用稍大一点的半径范围(20-25 个像素)。在此之前,请删除 imdistline 工具。

delete(d)
pout.png

Step3. 寻找圆的初步尝试
请对此图像调用 imfindcircles,使用的搜索半径为 [20 25] 像素。在此之前,最好要清楚对象是比背景亮还是比背景暗。要回答该问题,请运行下面代码看此图像的灰度版本。

gray_image = rgb2gray(rgb);
imshow(gray_image)
pout.png

上图可以看到背景相当亮,大多数塑料片比背景暗。但是,默认情况下,imfindcircles 会找到比背景亮的圆形对象。因此,在 imfindcircles 中将参数 'ObjectPolarity' 设置为 'dark' 以搜索较暗的圆。

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark');
点击查看输出:
centers =

     []


radii =

     []

请注意,输出 centers 和 radii 为空,这意味着未找到圆。这种情况经常发生,因为 imfindcircles 是圆形检测器,与大多数检测器类似,imfindcircles 有内部检测阈值决定其敏感度。简而言之,这意味着检测器对某个(圆形)检测的信心必须大于某个水平,也就是我们常说的置信度,才将其视为有效检测。imfindcircles 有参数 'Sensitivity',可用于控制此内部阈值,从而控制算法的敏感度。较高的 'Sensitivity' 值会将检测阈值设置得较低,并导致检测到更多圆。这类似于家庭安全系统中使用的运动检测器的敏感度控制。

Step4. 提高检测敏感度
回到塑料片图像,在默认敏感度水平下,可能所有圆都低于内部默认阈值,因此未检测到圆。'Sensitivity' 是介于 0 和 1 之间的数字,默认设置为 0.85。我们现在将 'Sensitivity' 提高到 0.9。

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', 'Sensitivity',0.9);

% 这里注意 "..." 视为一行语句的换行作用
[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark',...
    'Sensitivity',0.9);
点击查看输出
centers = 8×2    
  146.1895  198.5824
  328.8132  135.5883
  130.3134   43.8039
  175.2698  297.0583
  312.2831  192.3709
  327.1316  297.0077
  243.9893  166.4538
  271.5873  280.8920

radii = 8×1    
   23.1604
   22.5710
   22.9576
   23.7356
   22.9551
   22.9995
   22.9055
   23.0298

这次,imfindcircles 发现了一些圆 —— 准确地说是八个。centers 包含圆心的位置,radii 包含这些圆的估计半径。

Step5. 在图像上绘制圆
函数 viscircles 可用于在图像上绘制圆。来自 imfindcircles 的输出变量 centersradii 可以直接传递给 viscircles

imshow(rgb)
h = viscircles(centers,radii);
pout.png

圆心似乎定位正确,它们对应的半径似乎与实际塑料片匹配良好。但仍未检测到相当多的塑料片。请尝试将 'Sensitivity' 提高到 0.92。这里似乎没有更好的办法自适应,手动调节阈值测试!

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
    'Sensitivity',0.92);

length(centers)

输出:16意味着找到了16个圆形
可以发现增加 'Sensitivity' 会让我们找到更多圆。再次在图像上绘制这些圆。

delete(h)  % 删除原先绘制的图像
h = viscircles(centers,radii);
pout.png
至此,第一种方法(也叫做:相位编码方法)尝试完毕,缺点如下: 1. 并未找到我们所期待的所有圆形 2. 圆形半径并不是很准确

Step6. 使用第二种方法(两阶段法)寻找圆
此方法的结果看起来更好。imfindcircles 有两种不同寻找圆的方法。到当前为止,默认方法(称为相位编码方法)用于检测圆。在 imfindcircles 中还可以使用另一种方法,通常称为两阶段方法。使用两阶段方法并显示结果。

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
          'Sensitivity',0.92,'Method','twostage');

delete(h)
h = viscircles(centers,radii);
pout.png

可以发现,两阶段方法使用敏感度 0.92 可以检测更多圆。一般来说,这两种方法是互补的,因为它们有不同优点。同样的敏感度相位编码方法通常比两阶段方法更快,抗噪声的稳定性稍强。 但是,它也可能需要更高的 Sensitivity 水平才能实现与两阶段方法相同数量的检测。例如,如果 'Sensitivity' 水平提高到 0.95,相位编码方法也会找到相同的塑料片。

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...
          'Sensitivity',0.95);

delete(h)
viscircles(centers,radii);
pout.png

请注意,imfindcircles 中的两种方法都能准确找到部分可见(遮挡)塑料片的中心和半径。

Step7. 为什么有些圆仍检测不到?
查看最后一个结果,很奇怪 imfindcircles 没有在图像中找到黄色塑料片。黄色塑料片与背景的对比不够强烈。事实上,它们看起来和背景的强度非常相似。是不是黄色塑料片并没有想象中的那样比背景“更暗”?要确认这一点,请再次显示该图像的灰度版本。

imshow(gray_image)
pout.png

同样的,我们也可以基于灰度图把圆形标注出来,如下图

imshow(gray_image)
[centers,radii] = imfindcircles(gray_image,[20 25],'ObjectPolarity','dark', ...
          'Sensitivity',0.92,'Method','twostage');
viscircles(centers,radii);
pout.png

Step8. 在图像中找到“明亮”的圆
与背景相比,黄色塑料片的强度几乎相同,甚至更亮。因此,要检测黄色塑料片,请将 'ObjectPolarity' 更改为 'bright'。

[centersBright,radiiBright] = imfindcircles(rgb,[20 25], ...
    'ObjectPolarity','bright','Sensitivity',0.92);

% 用不同颜色绘制 'Bright' 圆
imshow(rgb)
hBright = viscircles(centersBright, radiiBright,'Color','b');
pout.png

请注意,找到了三个原先未检测到的黄色塑料片,但仍有黄色塑料片未检测到。这些黄色塑料片很难检测到,因为在这种背景下,它们没有呈现出与众不同。

Step9. 降低 EdgeThreshold 的值
在这里还可以使用 imfindcircles 中的另一个参数,即 EdgeThreshold。要查找圆,imfindcircles 仅使用图像中的边缘像素。这些边缘像素基本上是具有高梯度值的像素。'EdgeThreshold' 参数控制像素的梯度值必须有多高,才能将其视为边缘像素并包含在计算中。该参数的高值(更接近 1)只允许包含强边缘(较高梯度值),而低值(更接近 0)的宽容度更高,可在计算中包含较弱的边缘(较低梯度值)。对于检测不到黄色塑料片的情况,是因为对比度低,一些边界像素(在塑料片的圆周上)预期具有低梯度值。 因此,请降低 'EdgeThreshold' 参数,以确保黄色塑料片的大多数边缘像素都包含在计算中。

[centersBright,radiiBright,metricBright] = imfindcircles(rgb,[20 25], ...
    'ObjectPolarity','bright','Sensitivity',0.92,'EdgeThreshold',0.1);

delete(hBright)
hBright = viscircles(centersBright, radiiBright,'Color','b');
pout.png

Step10. 同时绘制“暗”,“明”圆
现在 imfindcircles 找到了所有黄色圆,还找到了一个绿色圆。用蓝色绘制这些塑料片,用红色绘制之前发现的其他塑料片('ObjectPolarity' 设置为 'dark')。

h = viscircles(centers,radii);
pout.png

所有圆都被检测到。最后 - 应注意,在检测中更激进地更改参数可能会发现更多圆,但也会增加检测到假圆的可能性。需要在可找到的真圆数量(检测率)和用它们找到的假圆数量(虚警率)之间实现某种平衡。也就是要根据不同的图像找到合理的阈值啦!

祝您能顺利检测到圆!

2. 导入、导出和转换 再等等哈!

posted @ 2023-08-26 18:11  计院研僧  阅读(575)  评论(0)    收藏  举报