介绍
在这篇文章中,我们将学习如何执行图像处理。在整篇文章中,我们使用到的库是Scikit Image。
基础知识
1、什么是图像?
图像数据可能是文本之后最常见的数据。那么,电脑如何理解你在埃菲尔铁塔前的自拍呢?
它使用一个称为像素的小正方形网格。像素覆盖一个小区域,并具有表示颜色的值。图像中的像素越多,其质量越高,存储所需的内存越多。
就是这样。图像处理主要是处理这些单独的像素(有时是像素组),以便计算机视觉算法可以从中提取更多信息。
文末有惊喜哦!!学习资料文末点击拿走~
2、NumPy和Skimage的图像基础
在Matplotlib和Skimage中,图像都作为NumPy ndarray加载。
from skimage.io import imread # pip install scikit-image
image = imread("images/colorful_scenery.jpg")
>>> type(image)
numpy.ndarray
NumPy数组带来灵活性、速度和力量。图像处理也不例外。
Ndarrays可以轻松检索图像的一般详细信息,例如图像的尺寸:
>>> image.shape
(853, 1280, 3)
>>> image.ndim
3
# The number of pixels
>>> image.size # 853 * 1280 * 3
3275520
我们的图像高度为853像素,宽度为1280像素。第三维表示RGB(红、绿、蓝)颜色通道的值。最常见的图像格式是3D。
你可以通过常规NumPy索引检索单个像素值。下面,我们尝试索引图像以检索三个颜色通道中的每一个通道:
red = image[:, :, 0]
compare(image, red, "Red Channel of the Image", cmap_type="Reds_r")
green = image[:, :, 1]
compare(image, green, "Green Channel of the Image", "Greens_r")
blue = image[:, :, 2]
compare(image, blue, "Blue Channel of the Image", "Blues_r")
0表示红色,1表示绿色,2表示蓝色通道-非常简单。
创建了两个函数,show和compare,它们显示一个图像或并排显示其中两个进行比较。在整个教程中,我们将广泛使用这两个函数。
按照约定,ndarray的第三维用于颜色通道,但并不总是遵循此约定。Skimage通常提供参数来指定这种行为。
图像与通常的Matplotlib绘图不同。它们的原点不位于左下角,而是位于左上角的位置(0,0)。
>>> show(image, axis=True)
当我们在Matplotlib中绘制图像时,轴表示像素的顺序,但我们通常会隐藏它们。
3、常见转换
我们将要执行的最常见的图像转换是将彩色图像转换为灰度。许多图像处理算法需要灰度图像。因为颜色不是图片的定义特征,没有它,计算机仍然可以提取足够的信息。
from skimage.color import rgb2gray
image = imread("images/grayscale_example.jpg")
# Convert image to grayscale
gray = rgb2gray(image)
compare(image, gray, "Grayscale Image")
>>> gray.shape
(853, 1280)
当将图像转换为灰度时,它们会丢失其第三维度-颜色通道。相反,图像数组中的每个单元格现在表示uint8类型的整数。它们的范围从0到255,提供256种灰度。
你还可以使用np.flipud或者np.fliplr之类的NumPy函数,随心所欲地以任何方式操纵图像。
kitten = imread("images/horizontal_flip.jpg")
horizontal_flipped = np.fliplr(kitten)
compare(kitten, horizontal_flipped, "Horizontally Flipped Image")
ball = imread("images/upside_down.jpg")
vertically_flipped = np.flipud(ball)
compare(ball, vertically_flipped, "Vertically Flipped Image")
在“颜色”模块中,你可以找到许多其他变换函数来处理图像中的颜色。
4、颜色通道直方图
有时,查看每个颜色通道的强度有助于了解颜色分布。我们可以通过切片每个颜色通道并绘制它们的直方图来实现这一点。以下是执行此操作的函数:
def plot_with_hist_channel(image, channel):
channels = ["red", "green", "blue"]
channel_idx = channels.index(channel)
color = channels[channel_idx]
extracted_channel = image[:, :, channel_idx]
fig, (ax1, ax2) = plt.subplots(
ncols=2, figsize=(18, 6)
)
ax1.imshow(image)
ax1.axis("off")
ax2.hist(extracted_channel.ravel(), bins=256, color=color)
ax2.set_title(f"{channels[channel_idx]} histogram")
除了Matplotlib的一些细节之外,你还应该注意hist函数的调用。提取颜色通道及其数组后,我们将其展平为1D数组,并将其传递给hist函数。
bin数量应该是256个,每个像素值对应一个-0表示黑色,255表示完全白色。
让我们使用彩色风景图像:
colorful_scenery = imread("images/colorful_scenery.jpg")
plot_with_hist_channel(colorful_scenery, "red")
>>> plot_with_hist_channel(colorful_scenery, "green")
>>> plot_with_hist_channel(colorful_scenery, "blue")
还可以使用直方图在将图像转换为灰度后找出图像中的亮度:
gray_color_scenery = rgb2gray(colorful_scenery)
plt.hist(gray_color_scenery.ravel(), bins=256);
大多数像素的值较低,因为景物图像较暗。
我们将在以下部分探讨直方图的更多应用。
过滤器
1、手动阈值
现在,我们来看看有趣的东西——过滤图像。我们将学习的第一个操作是阈值化。让我们加载一个示例图像:
stag