TP 图形处理 traitement d’images


Lama ITANI – Application Engineer/ litani@mathworks.com


  • 引入图像与像素 Introducing images and pixels
  • 图像增强技术 Image enhancement techniques
  • 分割 Segmentation
  • 形态学技术 Morphological techniques
  • 边缘与线条检测 Edge and line detection
  • 嵌入式部署 Embedded deployment
  • 深入研究(计算机视觉、机器学习和深度学习的示例)

图像和像素


图像由离散的像素点组成,每个像素点决定一个边长为最小分辨率的正方形的颜色,一般由一个整数表示。由三种不同类型的图像:

  • 二值图像
  • 灰度图像
  • 真彩(RGB)图像

以灰度图为例,灰度图使用0表示黑色,255表示白色,使用0和255之间的数值以表示不同的灰度:

图像增强


  • 更清晰地查看和评估图像所包含的视觉信息
  • 为特定任务准备原始图像

滤波

与一个像素相邻的像素:

\(3\times 3\)滤波器 filter。对于一个滤波器:

\[ G(i)=\sum_{k=1}^9 w_k I_k(i) \]

作用在这个给图片上:

\[ G(i, j)=\frac{1}{(2 k+1)^2} \sum_{u=-k}^k \sum_{v=-k}^k I(i+u, j+v) \]

常用的滤波器:

  • 均值滤波器:average filter
  • 高斯滤波器 gaussian filter
  • 中值滤波器(非线性)median filter

这些滤波器可以用于降噪。

  • 均值滤波器
1
2
h2 = fspecial('average',hsize); % Calling on 'average' filter
avgCow = imfilter(noisyCow,h2,'replicate');

  • 高斯滤波器
1
2
h1 = fspecial('gaussian',hsize,sigma); % Calling on 'gaussian' filter
blurredCow = imfilter(noisyCow,h1,'replicate');

  • 中值滤波器
1
medianCow = medfilt2(noisyCow,[m n]); % medfilt2: built-in median filter function

中值滤波器相比于线性滤波器更优越,因为它能更好地保持边缘特征。由于中值是从像素邻域内的像素值中选择的,因此它对异常值更加鲁棒,不会生成新的不真实的像素值。这有助于防止边缘模糊和图像细节的丢失。


对比度 contrast

对比度是画面黑与白的比值。在灰度图和RGB图像中中,使用0-255之间的值代表颜色强度。然而,对于一张图片,可能大量的颜色分布在如100-200之间的一小段区间内,这将导致对比度较低,图片颜色偏灰。如果我们将原本的100视为0,200视为255,颜色对比将更加明显。

matlab中的imadjust 函数将输入图像的像素强度值映射到输出图像的新的强度值区间,使得输入区间内的强度low_in到high_in映射为输出区间 0 到 1 之间的值,从而提高了对比度。

1
adjCow = imadjust(contrast_cow,[low_in high_in]); 

如此提高对比度对导致部分信息的丢失。


锐化

图像锐化用于增强图像中的细节。锐化滤波器通过从原始图像中减去其平滑版本来突出图像的边缘。平滑版本通常是通过对原始图像应用平均滤波器获得的。

1
2
3
4
5
hax = drawcircle(gca,'Center',[x y],'Radius', radius); 
mask = createMask(hax); % Creating mask
amount =12; % Intensity of sharpening (the higher the amount, the sharpener the image)
f = @(x)imsharpen(x,'Amount',amount);
sharpCow = roifilt2(unsharpCow,mask,f);

分割


图像分割的基本目标是将图像划分为互斥的区域,以便随后为这些区域附加有意义的标签。分割出的对象通常称为前景foreground,而图像的其余部分为背景background。

不存在所谓的“正确”分割,图像的分割强烈依赖于我们感兴趣的对象或区域的类型。为了分割图像,可以利用图像的属性和特征。


基本强度阈值法

该方法在灰度图像上效果较好,灰度图像的像素强度范围为 0 到 255。为了应用基本强度阈值法,首先绘制直方图来检查图像中的强度分布。

1
histogram(CowSignGray)

希望保留牛的标志,同时去除背景中的树叶。为此,首先确定牛标志的像素强度CowSignGray(pix_row,pix_col)。然后即可消除强度较低的像素:

1
2
3
4
5
threshold = 190; 
mask = (CowSignGray < threshold);
idx = find(mask); % 找出强度 < 定义阈值的像素索引
CowSignGray_th = CowSignGray; % 输出图像(即处理后的图像)
CowSignGray_th(idx) = 0; % 将背景设置为零

尽管使用了强度阈值法,背景中的一些树叶仍然可见。接下来可以尝试基于颜色的阈值分割技术,看看是否能消除这些背景瑕疵。


颜色阈值法

颜色阈值法与基本强度阈值法几乎完全相同。唯一的区别是就分别对三种颜色取阈值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
% Define thresholds for Red channel based on histogram settings
channelRMin = 230;
channelRMax = 255;

% Define thresholds for Blue channel based on histogram settings
channelGMin = 0;
channelGMax = 255;

% Define thresholds for Green channel based on histogram settings
channelBMin = 0;
channelBMax = 17;

% Create mask based on chosen histogram thresholds
sliderBW = (CowSignColor(:,:,1) >= channelRMin ) & (CowSignColor(:,:,1) <= channelRMax) & ...
(CowSignColor(:,:,2) >= channelGMin ) & (CowSignColor(:,:,2) <= channelRMax) & ...
(CowSignColor(:,:,3) >= channelBMin ) & (CowSignColor(:,:,3) <= channelBMax);
BW = sliderBW;

% Initialize output masked image based on input image.
maskedColorImage = CowSignColor;

% Set background pixels where BW is false to zero.
maskedColorImage(repmat(~BW,[1 1 3])) = 0;

也可以使用colorThresholder来进行这一步骤。

形态学技术


  • 形态学 是研究形状或结构的学科。
  • 形态学的应用包括:
    • 分离图像中接触的对象
    • 去除不需要的图像结构和噪声
    • 根据对象的形状进行分类(等同于非线性滤波)
  • 形态学主要应用于二值图像,使用两个关键的形态学操作:腐蚀erosion膨胀dilation

  • 前景:表示图像中的对象,通常值为1。
  • 背景:表示图像的背景,通常值为0。

操作机制

  • 腐蚀:结构元素从前景中移除像素,减小对象的边缘,用于分离相邻的对象或去除噪声。
  • 膨胀:结构元素向前景中添加像素,扩大对象的边缘,用于填补对象中的小孔或连接分离的对象。


  • A: 结构元素完全适配图像,表示腐蚀条件下前景对象被保存。
  • B: 结构元素部分匹配图像,表示膨胀过程中前景对象被扩展。
  • C: 结构元素既不适配也不匹配图像。

结构元素 Structuring element

结构元素是一个矩阵,它确定正在处理的图像像素并定义处理每个像素时使用的邻域。通常,选择的结构元素大小和形状与想要处理的图像对象相同。例如,若要在图像中查找线条,可以创建一个线性结构元素。

1
2
l = 5; % Size of the structuring element
SE = strel("diamond", l) % Calling on 'diamond' to be the shape of the stucturing element


侵蚀和膨胀

在定义结构元素之后即可应用膨胀和侵蚀

1
2
dilImage= imdilate(BinaryImage,SE); % Applying dilation on the original binary image
erodeImage = imerode(BinaryImage,SE); % Applying erosion on the original binary image


闭合和开启 closing and opening

  • 闭合操作先进行膨胀,然后进行腐蚀。这种操作通常用于填充小的孔洞,连接相邻的物体或消除细小的裂缝。
  • 开启操作先进行腐蚀,然后进行膨胀。这种操作通常用于去除图像中的小型噪声或孤立的小物体,同时保持图像的大型结构完整。
1
2
closeImage = imclose(BinaryImage, SE); imshow(closeImage); title('闭合')
openImage = imopen(BinaryImage, SE); imshow(openImage); title('开启')解释这两行代码


使用imageMorphology工具

边缘与线条检测


  • 一种用于在图像中查找物体边界的技术
  • 通过检测亮度的不连续性来工作


1
BW_Sobel = edge(A, 'Sobel');


图像梯度

在实际操作中,图像并不是一个连续函数,因此无法直接求导。我们需要通过计算差分来近似梯度。一个简单的近似方法为:

\[ \frac{\partial I}{\partial x} \approx I(x+1, y)-I(x, y), \quad \frac{\partial I}{\partial y} \approx I(x, y+1)-I(x, y) \]

1
2
3
[Gmag, Gdir] = imgradient(A);
subplot(1,2,1), imshow(Gmag, []), colorbar, title("图像梯度幅值")
subplot(1,2,2), imshow(Gdir, []), colorbar, title("图像梯度方向")

imgradient允许指定梯度算子。梯度算子通过将权重矩阵与图像的每个像素及其邻域进行卷积,计算每个像素在水平方向和垂直方向上的梯度。


直线检测

从图像空间到霍夫空间的转换。

每个点都可以通过以下方程在霍夫空间中表示:

\[ \rho=x \cdot \cos \theta+y \cdot \sin \theta \]

其中 \(\rho\) 表示从原点到直线的垂直距离, \(\theta\) 表示垂线与 \(x\) 轴的夹角。

  • 离散化角度 \(\theta\) : 对于每个点 \(\left(x_1, y_1\right)\) ,通过不同的 \(\theta\) 值计算对应的 \(\rho\)
  • 霍夫空间中的相交:如果多个点对应的曲线在同一点相交,这意味着这些点属于同一条直线。


标准霍夫变换

  • 查找所有边缘点(Canny边缘检测)。
  • 计算所有边缘点对应的霍夫空间的曲线,对于曲线经过的所有点(离散的点),增加该点的计数。
  • 认为在霍夫空间\(HT(\rho,\theta)\)中,值表示上述的点的计数。
  • 由此霍夫空间的峰值表示可能的直线,峰值越高,直线上有越多的点。

  • 首先将图像转化为二值图像
1
[BWImage, outputImage] = createMask(I);
  • 骨架化skeleton,然后闭合
1
2
3
skel_img = bwmorph(BWImage, 'skel', Inf);
se = strel('line',4,180);
close_skel = imdilate(skel_img,se)

  • 进行Hough变换
1
[H,theta,rho] = hough(skel_img);
  • 找到Hough空间中的峰值
1
P = houghpeaks(H,2,'threshold',ceil(0.6*max(H(:))));
  • 使用houghlines检测直线,并显示
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
lines = houghlines(BWImage,theta,rho,P,'FillGap',10,'MinLength',10); % 使用峰值检测直线

% 显示原始图像,并叠加检测到的直线
figure, imshow(I), hold on
max_len = 0;
for k = 1:length(lines)
xy = [lines(k).point1; lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',2,'Color','green'); % 绘制检测到的线条

% 绘制线段的起点和终点
plot(xy(1,1),xy(1,2),'x','LineWidth',2,'Color','yellow');
plot(xy(2,1),xy(2,2),'x','LineWidth',2,'Color','red');

% 确定最长线段的终点
len = norm(lines(k).point1 - lines(k).point2);
if (len > max_len)
max_len = len;
xy_long = xy;
end
end
% 突出显示最长的线段
plot(xy_long(:,1),xy_long(:,2),'LineWidth',2,'Color','red');

嵌入式部署


  • 为嵌入式设备生成 C 代码:
  • MATLAB 函数的自动 C 代码生成支持:
  • Simulink 更适合流式数据处理和嵌入式部署: