Computer Vision(C. Rasche)计算机视觉 论文解读(2 Simple Image Manipulations)
2 Simple Image Manipulations
为了熟悉一些基础知识,我们在本节中执行一些简单的图像处理操作。 首先,我们了解图像格式和一些基本操作,如阈值处理和数据类型转换(第2.1节)。 然后我们介绍一个简单的面部部分定位检测器(第2.2节)。
2.1 Image Format, Thresholding, Conversion
典型的数字图像,例如jpeg图像,作为三维数组。 前两个维度对应于空间轴x和y。 第三维将颜色信息保存在三个“通道”中,即红色,绿色和蓝色(RGB)。 颜色值通常在0到255之间,并且存储为无符号整数,特别是uint8,数字8代表8位,设计的数据类型用于精确保持该范围(255 = 2^8-1)。 对于每个像素,存在24位(3 * 8位),其允许存储256×256×256≈1670万种颜色。 尽管有丰富的颜色信息,但仅使用该图像的灰度版本,计算机通常更方便,因此将信息减少回每像素8位。 要将RGB图像转换为灰度图像,可以通过根据特定比率添加三个分量将颜色值转换为灰度值L,例如:
(1)
在Matlab 中,可以使用命令imread加载图像。 要将其转换为灰度图像,存在函数rgb2gray。 为了显示图像,我们使用函数imagesc(图像比例),为此我们使用函数figure初始化图形。 函数clf清除图形。 使用命令subplot可以将多个图像打包到同一个图中。 以下代码显示了如何使用这些命令,其输出如图1所示。
clear; % clear memory
Irgb = imread(’yellowlily.jpg’); % load jpg image
Igry = rgb2gray(Irgb); % convert it to gray-scale
IrgbCen = Irgb(400:1200,300:900,:); % zoom into center
Igreen = Irgb(:,:,2); % green channel only
BWflw = Igry>100; % thresholded (black-white image)
Iblur = conv2(single(Igry),ones(25,25)); % blurring the image
%% ----- Plotting ------
figure(1); clf; [nr nc] = deal(3,2);
subplot(nr,nc,1); imagesc(Irgb); title(’Original’);
subplot(nr,nc,2); imagesc(Igry); colormap(gray); title(’Gray-Scale’);
subplot(nr,nc,3); imagesc(IrgbCen); title(’Sub-Selection (Zoom)’);
subplot(nr,nc,4); imhist(Igreen); title(’Histogram of Green Channel’);
subplot(nr,nc,5); imagesc(BWflw); title(’Black-White (Logical) Image’);
subplot(nr,nc,6); imagesc(Iblur); title(’Blurred Image’);
要选择图像的一部分 - 请参阅注释'zoom into center' - ,我们首先指定行号 - 首先指定垂直轴 - 然后指定列号 - 水平轴。 也就是说,人们将索引指定为数学中的矩阵。
Black-White Image 我们可以通过应用关系运算符来threshold图像,参见行BWflw = Igry> 100,在这种情况下,图像会自动转换为逻辑数据类型,即true或false,即一位(值分别为1和0)。 该数据类型的图像有时也称为黑白图像,因此变量的名称为BW。 在上面的代码示例中,我们尝试将花与其背景分开,因此它也被称为前景/背景分离。 我们在某种程度上任意选择了阈值,当然,根据直方图选择阈值是有意义的,例如如图所示的灰度值的直方图。 我们在第9节中对此进行了详细阐述。在我们进行分割之后,人们经常通过所谓的形态学操作来操纵黑白图像,这将在第10节中介绍。

Figure 1(图1):一些简单的图像处理。
左上 :原始RGB图像; 每个像素由24位(3个色度通道×8位)表示。
右上 :灰度:RGB值根据等式1组合成单个亮度值; 现在每个像素仅由8位表示(值从0到255)。
中左 :zoom图像; 使用矩阵式索引(行/列)进行选择。
中右 :绿色通道的图像直方图:x轴表示色度值,范围从0到255; y轴表示像素数。
左下 :将灰度图像阈值化为等于100的结果:白色表示像素开(真),黑色表示像素关(假)。
右下 :使用平均滤波器模糊化的灰度图像:在每个像素处获取其25x25像素邻域的平均值。
Blurred Image 有时模糊图像很有用,因为模糊的图像有助于分析图像的“粗糙”结构,否则难以在原始图像中检测到其所有细节。 我们可以通过在Matlab中的函数conv2完成对图像中每个像素的局部邻域进行平均来模糊图像。 在我们的例子中,我们采用一个25x25像素的邻域,用ones(25,25)生成并仅仅将其625像素值相加:对图像中的每个像素进行该求和操作。 我们将在第3节回到这一点。
Data-Type Conversion 函数imread返回数据类型为uint8的jpeg图像,这对于某些计算不是很实用。 对于许多图像处理函数,我们需要将图像转换为浮点数据类型。 在Matlab中,例如是single或double,分别代表更低和更高精度。 在上面的代码中,我们为函数conv2做了这个,但是如果需要,我们也可以写一个单独的行,Irgb = single(Irgb)。
许多函数都很灵活,会产生相同数据类型的输出; 其他的函数期望特定的数据类型作为输入; 某些函数产生特定的数据类型作为输出,例如threshold运算。 最好始终了解图像的数据类型 - 或任何变量 - 以及函数期望和生成的类型。
在Python 中,代码看起来非常相似,但我们需要从模块中“导入(import)”这些函数。 特别是skimage模块具有许多用于计算机视觉和图像处理的函数:
from numpy import arange, ones, histogram
from skimage.io import imread
from skimage.color import rgb2gray
from scipy.signal import convolve2d
Irgb = imread(’KlausIohannis.jpg’) # loading the image
Igry = rgb2gray(Irgb) # convert to gray-scale
IrgbCen = Irgb[100:500,400:700,:] # zoom into center
Igreen = Irgb[:,:,2] # green channel only
BWflw = Igry>0.3 # thresholding(black-white image)
Iblur = convolve2d(Igry,ones((25,25))) # blurring the image
#%% ---- Plotting
from matplotlib.pyplot import figure, subplot, imshow, plot, hist, title, cm
figure(figsize=(10,6)); (nr,nc) = (3,2)
subplot(nr,nc,1); imshow(Irgb); title(’Original’)
subplot(nr,nc,2); imshow(Igry, cmap=cm.gray); title(’Gray-Scale’)
subplot(nr,nc,3); imshow(IrgbCen); title(’Sub-Selection (Zoom)’)
subplot(nr,nc,4); hist(Igreen.flatten(),bins=arange(256)); title(’Histogram of Green Channel’)
subplot(nr,nc,5); imshow(BWflw); title(’Black-White (Logical) Image’)
subplot(nr,nc,6); imshow(Iblur, cmap=cm.gray); title(’Blurred Image’)
请注意,在Matlab中,如果输入的类型为uint8, 函数rgb2gray返回数据类型uint8的映射,而在Python中,函数skimage.color.rgb2gray立即将强度值向下缩放到间隔∈[0 1.0] 并将它们分配给浮点数据类型。
Topology 为了获得图像所代表的深刻类型,我们建议使用函数mesh观察图像,如Matlab代码块中的最后一行所示。 这更好地说明了图像阵列具有“强度景观”(图2)。 出于这个原因,计算机视觉科学家经常从拓扑学领域借用术语来描述他们的算法的运算,例如在分割算法的情况下术语“分水岭(watershed)”。

Figure2(图2):从三维视角(Matlab中的命令mesh)观察到的图像。 图像显示为景观,其高程 - 垂直轴 - 表示强度,其值通常为0到255(对于用8位编码的图像)。 从这个角度来看,人类不容易理解场景的语义内容,因为人类视觉系统来训练用来解释图像的正面视图。 但是这个视角更好地说明了计算机视觉系统作为输入接收的内容。
2.2 Face Part Detection
通过一些简单的图像处理,我们有时可以获得大量信息。 例如,为了检测肖像中的人脸特征,在许多情况下观察沿每个维度的像素强度值的总和就足够了,参见图3。我们生成两个这样的轮廓,一个通过沿水平轴积分像素值 (尺寸),并且沿垂直轴积分。 在Matlab中,这很容易完成如下:
Pver = sum(Ig,1); % vertical intensity profile
Phor = sum(Ig,2)’; % horizontal intensity profile
这些轮廓在图3中以黑色显示。在这种轮廓中,原则上 - 通过观察局部最大值,最小值等可以相对容易地定位面部特征。“原始”轮廓总和有点“噪声”但是 - 像大多数原始信号一样:它们包含太多“不稳定”的极值,使得检测面部特征变得困难。因此,我们通过对它们进行低通滤波来平滑轮廓。平滑版本在图中以洋红色显示;现在,更容易找到面部特征。可以通过对轮廓中的每个像素处的信号中的局部邻域求平均来完成平滑。我们已经通过使用函数conv2在二维中获得模糊图像完成了上述操作。这里我们只在一个维度上进行。我们使用所谓的高斯滤波器来实现这一目标,这是一种形状为“凸起”的函数:它是一种优雅的滤波方式,参见附录C.2的确切形状。对于上面图像的模糊,我们使用了扁平滤波器,这是一种相当粗糙的方式。
滤波器的尺寸很重要:小尺寸不会非常平滑,大尺寸会使信号变得很平坦。因此,我们通过选择滤波器的一部分来使滤波器尺寸依赖于图像尺寸。 使用函数pdf生成高斯值。
nPf = round(w*0.05); % # points: fraction of image width
LowFlt = pdf(’norm’, -nPf:nPf, 0, round(nPf/2)); % generate a Gaussian
Pverf = conv(Pver, LowFlt, ’valid’); % filter vertical profile
Phorf = conv(Phor, LowFlt, ’valid’); % filter horizontal profile
如果您不熟悉卷积过程,请参阅附录B - 目前关于一维卷积的附录B.1就足够了。 这些概念是信号处理领域的一部分,我们不能对这些概念进行冗长的介绍。 但是使用Matlab,您可以方便地浏览它们并快速了解这些操作,这就是我们在附录中提供了大量代码示例的原因。

Figure3(图3):面部图像的强度轮廓。 通过沿y轴(垂直;逐列)对像素强度值求和来生成垂直轮廓; 通过沿x轴求和(水平;行方向)生成水平轮廓。 部件的哪些部分与配置文件中的极值相对应?
对于极值检测,我们可以使用函数findpeaks,它返回局部最大值以及它们在信号中的位置。 为了找到局部最小值,我们反转了分布。 附录I.1中的代码显示了如何应用这些函数。
这种类型的面部局部定位稍微简单,但其时间复杂度较低,这就是为什么这种方法经常被用作更复杂的面部特征跟踪系统的第一阶段的原因。 许多应用的计算机视觉系统由级联的子系统组成,这些子系统逐渐地以越来越高的精度执行任务。
2.3 Exercises
2.3.1 Displaying an Image, Coordinate System
1. 从上面给出的代码块开始。 在绘图功函数magesc之后添加函数colorbar:这样可以方便地观察图像范围。 将图像的强度值除以2,图像现在变得“更暗”,这种效果可能不会立即显现,因为函数imagesc将缩放强度范围。 然后使用imagesc(Igry, [0 255])来观察效果。 添加命令hold on,允许您继续绘制图像 - 我们将在下一个练习中执行此操作。
2. 理解显示图中的坐标系:绘制某些东西,例如: plot(20,40,'*')中的星号。观察图像以矩阵模式显示,即在y轴上我们有行,在x轴上我们有列。如果你更喜欢在笛卡尔坐标图像的顶部看你的绘图,您需要通过使用axis命令(例如轴xy)或通过交换绘图坐标的x和y维度来切换轴。
2.3.2 Localizing Face Parts
下载包含人脸的图像数据库,其中面部大致位于图像中心:在网上搜索“人脸数据库”; 几十张图片就足够了。 使用附录I.1中的代码作为起点。 手动构建一些识别面部特征的规则。 用户有某些外观,这使得难以识别某些面部特征。 他们是哪一个?
附录1.1 Face Profiles
MATLAB代码:
clear;
Iorg = imread(’KlausIohannisCrop.jpg’); % image is color [m n 3]
Ig = rgb2gray(Iorg); % turn into graylevel image
Ig = Ig(35:end-35,35:end-35); % crop borders a bit more
[h w] = size(Ig); % image height and width
%% ===== Raw Profiles ======
Pver = sum(Ig,1); % vertical intensity profile
Phor = sum(Ig,2)’; % horizontal intensity profile
%% ===== Smoothen Profiles ======
nPf = round(w*0.05); % # points: fraction of image width
LowFlt = pdf(’norm’, -nPf:nPf, 0, round(nPf/2)); % generate a Gaussian
Pverf = conv(Pver, LowFlt, 'valid'); % filter vertical profile
Phorf = conv(Phor, LowFlt, 'valid'); % filter horizontal profile
Pverf = padarray(Pverf, [0 nPf], 'replicate'); % extend to original size
Phorf = padarray(Phorf, [0 nPf], 'replicate'); % extend to original size
%% ===== Detect Extrema ======
[PksVer LocPksVer] = findpeaks(Pverf); % peaks
[TrgVer LocTrgVer] = findpeaks(-Pverf); % troughs (sinks)
[PksHor LocPksHor] = findpeaks(Phorf); % peaks
[TrgHor LocTrgHor] = findpeaks(-Phorf); % troughs
%% -------- Plotting -----------
figure(1);clf;
subplot(1,2,1);
imagesc(Ig); colormap(gray);
subplot(2,2,2); hold on;
plot(Pver,’k’);
plot(Pverf,’m’);
plot(LocPksVer,PksVer,’g^’);
plot(LocTrgVer,abs(TrgVer),’rv’);
set(gca,’xlim’,[1 w]);
xlabel(’From Left to Right’);
title(’Vertical Profile’);
subplot(3,2,6); hold on;
plot(Phor,’k’);
plot(Phorf,’m’);
plot(LocPksHor,PksHor,’g^’);
plot(LocTrgHor,abs(TrgHor),’rv’);
set(gca,’xlim’,[1 h]);
xlabel(’From Top to Bottom’);
title(’Horizontal Profile’);
Python代码:
from numpy import asarray, diff, nonzero, shape, sign, sum
from skimage.io import imread
from skimage.color import rgb2gray
from scipy.signal import convolve, get_window, argrelmax, argrelmin
#%% ---- Load Image -----
Irgb = imread(’c:/klab/do_lec/compvis/Matlab/KlausIohannisCrop.jpg’) # image is color [m n 3]
Ig= rgb2gray(Irgb) # turn into graylevel image
Ig= Ig[34:-36,34:-36] # crop borders a bit more
(h,w) = shape(Ig) # image height and width
#%% ===== Raw Profiles ======
Pver = sum(Ig,axis=0) # vertical intensity profile
Phor = sum(Ig,axis=1) # horizontal
#%% ===== Smoothen Profiles =======
sgm = 10
nPf = round(w*0.10); # #points: fraction of image width
LowFlt = get_window((’gaussian’,sgm),nPf) # generate a Gaussian
LowFlt = LowFlt / sum(LowFlt) # normalize the filter
Pverf = convolve(Pver, LowFlt, ’same’) # filter vertical profile
Phorf = convolve(Phor, LowFlt, ’same’) # filter horizontal profile
#%% ===== Detect Extrema =======
LocMaxVer = argrelmax(Pverf) # peaks
LocMinVer = argrelmin(Pverf) # troughs (sinks)
LocMaxHor = argrelmax(Phorf) # peaks
LocMinHor = argrelmin(Phorf) # troughs (sinks)
#%% ---- Plotting
from matplotlib.pyplot import figure, subplot, imshow, plot, title, xlim, ylim, cm
figure(figsize=(10,6))
subplot(1,2,1)
imshow(Ig, cmap=cm.gray)
subplot(2,2,2)
plot(Pver,’k’)
plot(Pverf,’m’)
plot(LocMaxVer[0],Pverf[LocMaxVer],’g^’)
plot(LocMinVer[0],Pverf[LocMinVer],’rv’)
xlim(1,w)
title(’Vertical Profile’)
subplot(2,2,4)
plot(Phor,’k’)
plot(Phorf,’m’)
plot(LocMaxHor[0],Phorf[LocMaxHor],’g^’)
plot(LocMinHor[0],Phorf[LocMinHor],’rv’)
ylim(1,h)
title(’Horizontal Profile’)
希望本文能帮助你在计算机视觉领域走得更远,学习得更加深入!
