opencv图像处理机器学习真实项目教程(python实现)3图像处理基础

3 图像处理基础

在本章中,我们将介绍图像处理中的各种操作,首先是基于平移的操作,如旋转和调整大小。读者将学习如何使用 OpenCV 旋转和调整图像大小,以及如何控制生成图像的大小和方向。本章接着介绍了图像的算术运算,如加法、减法和除法。本章继续以图像运算为主题,介绍图像的位运算,如 AND、OR 和 XOR。最后,本章讨论了图像的通道和可以表示图像的各种色彩空间。

主要内容:

  • 图像的几何变换

    • 图像平移
    • 旋转
    • 缩放
    • 翻转
    • 剪切
    • 裁剪
  • 图像算术运算

    • 加法
    • 减法
    • 乘法
    • 除法
  • 图像的位运算

    • AND
    • OR
    • XOR
    • NOT
  • 通道和色彩空间

3.1 几何变换

图像变换能让我们以多种方式修改图像。它们在计算机视觉中起着至关重要的作用,使我们能够改变图像的大小或方向,以完成各种计算机视觉任务。这些操作被广泛用于计算机视觉任务中,并将成为我们所有计算机视觉应用的基本组成部分。这些变换在物体识别、图像分割和面部识别等计算机视觉应用中至关重要。

从技术角度讲,图像处理涉及将图像点的坐标从一个坐标系转换到另一个坐标系。利用各种变换函数,可以将原始图像中的像素坐标映射到变换后图像中的新坐标,从而产生不同类型的变换。

3.1.1 图像平移

图像平移是在水平和垂直方向上移动图像的过程。通过图像平移,我们可以在 x 轴和 y 轴上按指定的量移动图像。

要执行图像平移,需要对图像应用平移矩阵,将原始坐标映射到新的移动坐标。

图像平移是一种简单而有效的技术,可与其他图像处理技术相结合,以实现所需的结果。它有多种用途,例如将两幅图像对齐或在全景拍摄中拼接图像。在创建用于训练深度学习模型的数据集时,图像转换也常用于增强数据。

图像转换可以通过对输入图像应用仿射变换来实现。仿射变换是一种应用于图像的线性变换,它可以改变图像的大小和长宽,同时保留物体的位置和形状。仿射变换的一个重要特点是保留线条的平行性。

我们使用 OpenCV 中的 cv2.warpAffine 函数来应用仿射变换:


cv2.warpAffine(src, M, dsize, dst, flags=INTER_LINEAR,borderMode=BORDER_CONSTANT, borderValue=0)

参数

  • src:应用变换的源图像。

  • M:变换矩阵。

  • dsize:输出图像的大小: 输出图像的大小。

  • dst:dst 是可选的输出图像,用于存储变换结果。dst 图像的大小和类型必须与输入图像 src 相同。如果未提供 dst 图像,OpenCV 函数将创建与输入图像大小和类型相同的输出图像,并将其作为输出返回。

  • 标志(Flags): 这是一个可选参数,用于指定要使用的插值方法。

  • borderMode:边框模式: 指定如何处理超出图像边界的像素。默认值为 cv2.BORDER_CONSTANT。

  • borderValue(边框值): 仅用于 cv2.BORDER_CONSTANT 模式,指定用于填充图像的常量值。默认值为 0。


import cv2
import numpy as np

img = cv2.imread("../img/dog.jpg")

# Define the translation matrix
tx = 50   # x-direction
ty = 100  # y-direction
M = np.float32([[1, 0, tx], [0, 1, ty]])

# Apply the translation to the image
rows, cols, _ = img.shape
translated_img = cv2.warpAffine(img, M, (cols, rows))

cv2.imshow("Original Image", img)
cv2.imshow("Translated Image", translated_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.1.2旋转

图像旋转是将图像绕其中心点旋转一个角度的过程。它是图像处理中广泛使用的操作,可用于各种图像处理应用中。

有两种方法可以执行图像旋转,虽然一种方法就足够了,但为了全面了解这一主题,有必要讨论这两种方法。

第一种是使用cv2.rotate 函数进行图像旋转。使用该函数的缺点是,它只能将图像按顺时针或逆时针方向旋转90度。它不允许我们选择任意角度旋转图像cv2.rotate函数的实现方式如下

cv2.rotate(src, rotateCode, dst)

参数

  • src:要进行变换的源图像。
  • rotateCode:旋转代码: 该参数指定图像旋转的方向和角度。rotateCode 的可能值有
    • cv2.ROTATE_90_CLOCKWISE: 按顺时针方向将图像旋转 90 度。
    • cv2.ROTATE_90_COUNTERCLOCKWISE:按顺时针方向旋转图像 90 度: 按逆时针方向将图像旋转 90 度。
    • cv2.ROTATE_180: 将图像旋转 180 度。
  • dst:dst 是可选的输出图像,用于存储转换结果。dst 图像的大小和类型必须与输入图像 src 相同。如果未提供 dst 图像,OpenCV 函数将创建与输入图像大小和类型相同的输出图像,并将其作为输出返回。
import cv2

img = cv2.imread('../img/dog.jpg')

# Rotate clockwise by 90 degrees
rot_img_90cw = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)

# Rotate counterclockwise by 90 degrees
rot_img_90ccw = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)

# Rotate by 180 degrees
rot_img_180 = cv2.rotate(img, cv2.ROTATE_180)

cv2.imshow('Original', img)
cv2.imshow('Rotated 90 CW', rot_img_90cw)
cv2.imshow('Rotated 90 CCW', rot_img_90ccw)
cv2.imshow('Rotated 180', rot_img_180)
cv2.waitKey(0)
cv2.destroyAllWindows()

我们使用的另一种图像旋转方法是使用前面讨论过的cv2.warpAffine函数。这种方法允许我们选择任意角度和中心点来旋转图像。

我们使用另一个函数cv2.getRotationMatrix2D来生成用于cv2.warpAffine函数的旋转矩阵。虽然自行创建图片平移矩阵很简单,但使用专用函数来创建旋转矩阵还是很有帮助的:

cv2.getRotationMatrix2D(center=None, angle, scale=1)

参数

  • center: 图像旋转的中心点(x,y)。默认值为None。如果未指定中心点,函数将使用图像的中心点。
  • angle:角度: 旋转角度(度)。正值表示逆时针方向,负值表示顺时针方向。
  • scale:缩放比例: 缩放参数用于按系数缩放图像的大小。默认值为 1,表示输出图像与输入图像大小相同。

让我们试着用一些代码来实现旋转:

import cv2
import numpy as np

img = cv2.imread('../img/dog.jpg')
rows, cols = img.shape[:2]

# Get rotation matrices.
M1 = cv2.getRotationMatrix2D((100,100), 30, 1)

M2 = cv2.getRotationMatrix2D((cols/2,rows/2), 45, 2)

M3 = cv2.getRotationMatrix2D((cols/2,rows/2), -90, 1)

#new values for the output
scale = 2
new_cols = int(cols * scale)
new_rows = int(rows * scale)

# Create output image with the new size
rotated2 = cv2.warpAffine(img, M2, (new_cols, new_rows))

# Perform rotation
rotated1 = cv2.warpAffine(img, M1, (cols, rows))
rotated2 = cv2.warpAffine(img, M2, (cols, rows))
rotated3 = cv2.warpAffine(img, M3, (cols, rows))

cv2.imshow('Original Image', img)
cv2.imshow('Rotated Image 1', rotated1)
cv2.imshow('Rotated Image 2', rotated2)
cv2.imshow('Rotated Image 3', rotated3)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.1.3缩放

图像缩放是图像处理中的一项常见任务,它允许我们根据需要调整图像大小。在调整图像大小时,重要的是要保持图像的纵横比,以避免产生扭曲的图像。

我们使用 cv2.resize() 函数来调整 OpenCV 图像的大小:

cv2.resize(src, dst, dsize, fx=0, fy=0, interpolation=cv2.INTER_LINEAR)

参数

  • src:应用变换的源图像。
  • dst:dst 是可选的输出图像,用于存储变换结果。dst 图像的大小和类型必须与输入图像 src 相同。如果未提供 dst 图像,OpenCV 函数将创建与输入图像大小和类型相同的输出图像,并将其作为输出返回。
  • dsize: 调整大小后输出图像的尺寸。
  • fx: 沿水平轴的缩放因子。
  • fy: 沿垂直轴的缩放因子。

如果未指定 dsize,系统将自动使用缩放因子 fx 和 fy 计算出 dsize。

dsize = (int(src.shape[1] * fx), int(src.shape[0] * fy))
  • interpolation: 插值是指应用几何变换后估算新像素值的技术。该参数可使用以下值:
    • cv2.INTER_NEAREST:最近邻插值。
    • cv2.INTER_LINEAR:双线性插值。
    • cv2.INTER_CUBIC:对 4×4 像素邻域进行双三次插值。
    • cv2.INTER_AREA:使用像素面积关系重新采样。这是缩小图像时推荐的插值方法。
    • cv2.INTER_LANCZOS4: 在 8x8 像素邻域上进行 Lanczos 插值。
import cv2

img = cv2.imread('../img/dog.jpg')

# Resize the image to half its size
resized_img = cv2.resize(img, (0,0), fx=0.5, fy=0.5)

# Resize the image to a specific width and height
resized_img = cv2.resize(img, (640, 480))

cv2.imshow('Original Image', img)
cv2.imshow('Resized Image', resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

图像缩放也可以使用 cv2.warpAffine 函数来实现:

import cv2
import numpy as np

img = cv2.imread('cat.jpg')

# Define the new size
new_size = (400, 400)

# Compute the scaling factors for x and y axis
sx = new_size[0]/img.shape[1]
sy = new_size[1]/img.shape[0]

# Define the transformation matrix
M = np.float32([[sx, 0, 0], [0, sy, 0]])

# Apply the affine transformation
resized_img = cv2.warpAffine(img, M, new_size)

cv2.imshow('Original Image', img)
cv2.imshow('Resized Image', resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码会产生以下输出:

3.1.4翻转

图像翻转用于水平或垂直翻转图像。我们可以使用 cv2.flip 函数来实现图像翻转:

cv2.flip(src, dst, flipCode=1)

参数

  • src: 要翻转的源图像
  • dst: 输出变量
  • flipCode:翻转代码 指定如何翻转数组的标志。该参数可使用以下值。
    • '0': 垂直翻转。图像围绕 x 轴翻转。
    • '1': 水平翻转。图像围绕 Y 轴翻转
    • '-1': 图像围绕两个轴翻转
      默认值为 1:
import cv2

img = cv2.imread('../img/dog.jpg')

# Flip the image horizontally
x_flip = cv2.flip(img, 1)

# Flip the image vertically
y_flip = cv2.flip(img, 0)

# Flip the image on both axes
xy_flip = cv2.flip(img, -1)

cv2.imshow('Original Image', img)
cv2.imshow('Horizontal flip', x_flip)
cv2.imshow('Vertical flip', y_flip)
cv2.imshow('Both axes', xy_flip)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码产生的输出如下,演示了图像翻转:

3.1.5 Shearing

图像剪切是一种线性变换,它沿着图像的一个轴扭曲图像。当图像沿 x 轴剪切时,图像中的像素会水平移动。这会导致图像在 x 轴方向上倾斜。同样,当图像沿 Y 轴剪切时,图像中的像素会垂直移动,导致图像在 Y 轴方向看起来倾斜。图像剪切时不会保留平行线。

import cv2
import numpy as np

img = cv2.imread('../img/dog.jpg')

# shearing parameters
shear_factor_x = 0.2
shear_factor_y = 0.3

# Obtain shearing matrices
M_x = np.array([[1, shear_factor_x, 0],
                [0, 1, 0]])
M_y = np.array([[1, 0, 0],
                [shear_factor_y, 1, 0]])

# Apply shearing transformations
rows, cols = img.shape[:2]
sheared_img_x = cv2.warpAffine(img, M_x, (cols + int(rows * shear_factor_x), rows))
sheared_img_xy = cv2.warpAffine(sheared_img_x, M_y, (cols + int(rows * shear_factor_x), rows + int(cols * shear_factor_y)))

cv2.imshow("Original Image", img)
cv2.imshow("Sheared Image (X axis)", sheared_img_x)
cv2.imshow("Sheared Image (X and Y axis)", sheared_img_xy)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.1.6 裁剪(cropping)

图像裁剪是选择图像矩形部分的过程。裁剪可被视为一种几何变换,通过去除源图像的一部分来生成新图像。在原始图像中,选择一个矩形的感兴趣区域(ROI),只保留该区域中的像素,其余像素将被丢弃。

import cv2

img = cv2.imread('../img/dog.jpg')

# Define ROI coordinates
x1, y1 = 10, 10 # top-left corner
x2, y2 = 200, 200 # bottom-right corner

# Crop image
cropped_img = img[y1:y2, x1:x2]

cv2.imshow("Original Image", img)
cv2.imshow("Cropped Image", cropped_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.2 算术运算

算术运算是图像处理中的一个基本概念。这些运算涉及对图像执行基本数学运算,以生成具有不同属性的新图像。这些运算对像素值进行处理,使我们能够从图像中提取有用的信息。

图像上的算术运算可用于多种应用,如调整图像的亮度或对比度。算术运算的另一个主要用途是将两幅或多幅图像混合在一起。

在图像上可以执行多种类型的算术运算。一些基本的算术运算包括加法、减法、乘法和除法。

在图像上执行算术运算的主要挑战之一是像素值超出 0-255 的范围。出现这种情况的原因可能是在图像中加入或减去了一个较大的值,并可能导致信息丢失和图像失真等重大问题。

剪切是一种用于解决像素值超出 0-255 有效范围问题的技术。这包括将任何高于 255 的像素值设置为 255,将任何低于 0 的像素值设置为 0,确保所有像素值都在有效范围内。另一种解决方案是使用缠绕法,即如果数值超过 255,则缠绕到 0,而不是超过 255。例如,如果数值为 270,在剪切的情况下会设置为 255,但在另一种情况下,会绕到 15。

选择使用哪种技术最终取决于手头图像处理任务的具体需求。

我们首先讨论图像加法,以及在使用 cv2 进行图像加法时,如何处理像素值溢出,以及在 NumPy 值上使用普通 Python 加法时,如何处理像素值溢出。

3.2.1 加法

图像加法是一种基本算术运算,涉及将两幅或多幅图像的像素值相加以生成一幅图像。图像加法的主要优势在于它允许我们执行更复杂的操作,如图像混合或遮罩。图像混合是将两幅图像以不同的比例进行组合,生成输出图像,而遮罩则是在图像上叠加二进制遮罩,对选定的图像区域进行处理。随着本章的深入,我们将讨论这些主题。

我们使用 cv2.add() 函数来使用 OpenCV 库执行加法运算:

cv2.add(src1, src2, dst, mask, dtype)

参数:

  • src1 和 src2:要添加的源图像。两幅图像的类型和大小应相同。
  • dst: 输出变量。
  • mask: 屏蔽允许我们选择需要执行操作的特定像素。如果留空,则对所有像素执行操作。
  • dtype: 输出的数据类型。这是一个可选参数,如果留空,默认为输入数据类型。

现在,我们将尝试通过执行 cv2.add 函数来添加图像。此外,我们还将比较在 NumPy 加法中如何处理溢出值:

import numpy as np
import cv2

# Initialize two sample 3x3 images
img1 = np.array([[10, 20, 30],
                 [40, 50, 60],
                 [70, 80, 90]], dtype=np.uint8)
img2 = np.array([[100, 200, 150],
                 [50, 250, 100],
                 [150, 200, 50]], dtype=np.uint8)

# Add the images
cv2_add = cv2.add(img1, img2)
print("cv2.add() result:\n", cv2_add)

# Add the images using numpy addition
numpy_add = img1 + img2
print("Numpy addition result:\n", numpy_add)

结果

cv2.add() result:
 [[110 220 180]
 [ 90 255 160]
 [220 255 140]]
Numpy addition result:
 [[110 220 180]
 [ 90  44 160]
 [220  24 140]]

接下来,我们将讨论图像的加权相加,这意味着每幅图像对最终输出的贡献不同,而且这些贡献并不相等,如前所述。

为此,我们使用 cv2.addWeighted() 函数:

cv2.addWeighted(src1, alpha=1.0, src2, beta=0.0, gamma=0.0, dst, dtype)

参数

  • src1 和 src2:要添加的源图像。两幅图像的类型和大小应相同。
  • alpha: 第一幅图像的权重: 第一幅图像的权重。alpha 的取值范围为 0 至 1,其中 0 表示第一幅图像对输出没有贡献,1 表示第一幅图像对输出的贡献最大。默认值为 1。
  • beta: 第二幅图像的权重。beta 的范围介于 0 和 1 之间,与 alpha 参数类似。beta 的默认值为 0。
  • gamma:伽马值: 一个标量值,可在计算加权和后添加到所有像素中。默认值为 0。
  • dst:输出数组: 输出数组。
  • dtype:数据类型: 输出的数据类型。这是一个可选参数,如果留空,默认为输入数据类型。
import cv2
import numpy as np

img1 = cv2.imread('image1.jpg')
img2 = cv2.imread('image2.jpg')

# Add the two images with different weights
result = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)

cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

前面的代码加载了两幅图像,并以不同的权重将其混合。阿尔法参数设置为 0.7,贝塔参数设置为 0.3,这意味着 img1 对最终输出的贡献率为 70%,而 img2 为 30%。gamma 值设置为 0,表示初始结果中不添加任何标量。

3.2.2 图像减法

接下来,我们将讨论图像减法。我们在 OpenCV 中使用 cv2.subtract() 函数进行图像减法。该函数与我们之前讨论过的 cv2.add() 函数非常相似。

该函数将两幅图像作为输入,然后从第一幅图像中减去第二幅图像的像素值。如前所述,减法产生的任何负值都将设为 0:

cv2.subtract(src1, src2, dst, mask, dtype)

参数

  • src1 和 src2:要相减的源图像。两幅图像的类型和大小应相同。从 src1 图像减去 src2 图像。
  • dst: 输出变量。
  • mask: 屏蔽允许我们选择需要执行操作的特定像素。这是一个。如果留空,则对所有像素执行操作。
  • dtype(数据类型 输出的数据类型。这是一个可选参数,如果留空,默认为输入数据类型。

3.2.3 乘除

图像的乘法运算是将一幅图像的每个像素值与另一幅图像的相应像素值相乘。同样,图像除法是将一个图像的每个像素值与另一个图像的相应像素值相除。

由于图像乘法和除法的语法和文档相似,我们将一并讨论,并使用单个代码实现它们,以求简洁:

cv2.multiply(src1, src2, dst, scale=1.0, dtype)

cv2.divide(src1, src2, dst, scale=1.0, dtype)

参数:

  • src1 和 src2: 要相乘或相除的源图像。
  • dst: 输出变量。
  • scale:比例系数: cv2.multiply()中的比例因子是一个标量值,与输入图像中相应像素值的乘积相乘。cv2.divide 中的 scale 参数用于将分子(源图像)除以标量值。这是一个可选参数,默认值为 1.0。
  • dtype: 输出的数据类型。这是一个可选参数,如果没有输入数据类型,则默认为输入数据类型。

3.3 位运算

位运算可用于合并两幅图像,或提取和修改这些图像的特定部分。虽然位运算看似低级简单,但在图像处理中却是必不可少的。位wise 运算看起来与算术运算相似,但它们并不完全是算术运算。

算术运算通常涉及使用加、减、乘、除等数学运算来处理图像中像素的数值。另一方面,位运算涉及对图像中像素值的各个位进行操作。这些操作基于 AND、OR、XOR 和 NOT 的逻辑运算。

位运算是对这些像素值的二进制表示执行的。二进制操作既可以在二进制图像上进行,也可以在灰度/彩色图像上进行。二进制图像的像素值为 0 和 1,因此对其进行位运算非常简单。在灰度图像中,像素值范围为 0-255 的单通道,而对于彩色图像,则有多个通道,每个通道单独处理,然后合并。

四种主要的位操作是 AND、OR、XOR 和 NOT。我们将详细讨论这些操作,但由于它们的语法和文档相似,为简洁起见,我们将它们放在一起。

3.3.1 AND

比特 AND 是一种二进制操作,它将两幅图像进行逻辑 AND 运算。如果输入图像中的任何位为 0,则结果像素值为 0。

比特 AND 运算的主要用途是屏蔽。它可用于在图像上应用二进制掩码,以提取图像的某些区域。位与运算还可用于对象跟踪或图像分割和图像锐化等用途。此操作的语法为

cv2.bitwise_and(src1, src2, dst, mask)

3.3.2 OR

OR是一种二进制操作,它将两幅图像进行逻辑 OR 运算。如果输入图像的两个位都为 0,则生成的像素值为 0。

位操作 OR 的主要用途是图像混合;使用这种操作可以将两幅图像混合在一起。该操作也可用于图像分割或许多其他用途,例如在图像中添加随机噪音。此操作的语法为

cv2.bitwise_or(src1, src2, dst, mask)

参考资料

3.3.3 XOR

位操作XOR是一种二进制操作,它将两幅图像进行逻辑 XOR(排他 OR)操作。如果输入图像上的两个位都是 0 或 1,则生成的像素值为 0。

通过使用密钥,XOR可用于图像加密。它还可用于边缘检测和直方图均衡化等用例,我们将在本书中进一步深入探讨这一概念。此操作的语法为

cv2.bitwise_xor(src1, src2, dst, mask)

3.3.4 NOT

NOT是一种一元操作,它获取单个图像并对其执行逻辑 NOT 操作。该操作的结果是图像的所有值都被反转。在位操作 NOT 的过程中,所有对应于 0 的像素值都会被设置为 1,而所有对应于 1 的像素值都会被设置为 0。

这种操作的主要用途是图像反转。除此之外,它还可用于屏蔽和图像阈值处理。此操作的语法为

cv2.bitwise_not(src, dst, mask)

参数

  • src1 和 src:用于位操作的源图像。
  • dst: 输出变量。
  • mask:掩码: 这是可选的掩码,用于指定应处理输入图像中的哪些像素。默认值为 "无",即使用全部图像:
import cv2
import numpy as np

# Create two black and white images
img1 = np.zeros((400, 400), dtype=np.uint8)
img2 = np.zeros((400, 400), dtype=np.uint8)

# Draw a rectangle on img1
cv2.rectangle(img1, (50, 50), (350, 350), (255, 255, 255), -1)

# Draw a circle on img2
cv2.circle(img2, (200, 200), 150, (255, 255, 255), -1)

# Perform bitwise AND
bitwise_and = cv2.bitwise_and(img1, img2)

# Perform bitwise OR
bitwise_or = cv2.bitwise_or(img1, img2)

# Perform bitwise XOR
bitwise_xor = cv2.bitwise_xor(img1, img2)

# Perform bitwise NOT on img1
bitwise_not = cv2.bitwise_not(img1)

cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('AND', bitwise_and)
cv2.imshow('OR', bitwise_or)
cv2.imshow('XOR', bitwise_xor)
cv2.imshow('NOT of img1', bitwise_not)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.4通道和色彩空间

在 OpenCV 中,图像以像素值矩阵的形式表示。图像中的通道数就是用于表示图像的矩阵数。例如,灰度图像有一个通道,而彩色图像通常有三个通道(红、绿、蓝)。通过图像中的通道,我们可以分离图像中的颜色成分,并分别处理它们以获取更多信息。

色彩空间代表了一种用数学模型描述色彩的特定方式。根据色彩空间的不同,色值被定义为三原色的组合,以及这些三原色如何组合产生特定的颜色。到目前为止,我们一直在使用 RGB 色彩空间,这是一种使用红、绿、蓝三个通道组合来表示所有颜色的色彩模型。随着本主题的深入,我们将探索常见的色彩空间。我们还将讨论灰度图像,灰度图像虽然不属于色彩空间,但在图像处理中却非常重要。

将色彩空间与现实生活中的例子进行比较,可以更好地解释色彩空间。想象一下,一个画家试图为一幅画混合和创造新的颜色。画家可以通过选择多种颜料管,并以不同的比例将它们混合在一起,产生多种颜色。颜料混合后可以产生不同的颜色,例如红色和白色混合后产生粉红色,黄色和蓝色混合后产生绿色。同样,不同的色彩空间可以让我们改变色彩的亮度或饱和度,并使用不同的三原色组合创造出新的色彩。

我们将详细讨论最常用的色彩空间。我们首先讨论 RGB 色彩空间。

3.4.1 红绿蓝(RGB)色彩空间

RGB 色彩空间包含表示图像的红色、蓝色和绿色通道。图像是通过将这三种颜色按所需数量相加来生成特定颜色的。要生成的每种颜色的强度决定了生成该特定颜色所需的红、绿、蓝三种颜色的数量。将这三种颜色组合起来,就可以生成图像所需的各种颜色。

RGB 色彩空间中的每个通道都有从 0 到 255 不等的数值,用来描述特定颜色的强度。0 表示没有颜色或完全黑暗,而 255 表示该颜色的最大强度或完全明亮。例如,在 RGB 色彩空间中,纯红色用 (255, 0, 0) 表示,其中红色通道为最大值 (255),绿色和蓝色通道均设置为 0。 同样,纯蓝色用 (0,0,255) 表示,纯绿色可以用 (0,255,0) 表示。

例如,纯黄色用 (255,255,0)表示,即红色通道的值为 255,绿色通道的值为 255,蓝色通道的值为 0。

其他一些颜色的表示方法如下

如果我们想改变颜色,还可以访问和操作每个单独的值。在上表中,我们发现浅灰色表示为 (211,211,211)。如果我们减小这些值,颜色就会开始变深,从而呈现出更深的灰色。

同样,如果我们减小橙色的红色通道(255, 165, 0),例如,将其改为(200, 165, 0),颜色将变得不那么强烈,并转向红色较少的色调,但仍保留其橙色特征。

这些值的另一个重要用途是,我们可以用它们来检测图像中的特定颜色或颜色范围。我们可以利用图像中每个像素的红色值来查找红色物体,如红花。例如,如果图像中的红色值 (R) 大于某个特定的数字(比方说 200),我们就可以说这些像素很可能属于红色物体,我们就可以使用这种技术来检测图像中的红色花朵。

RGB 色彩空间通常不被认为是直观的,因为使用这种色彩空间很难再现色彩。按比例混合红色、蓝色和绿色可能不会产生预期的颜色,而且通常很难再现这三种颜色的精确组合。尽管有其局限性,RGB 色彩空间仍被广泛应用于包括图像处理在内的各种应用中,在我们的学习过程中也会经常用到它。

让我们借助一些代码,尝试将图像的这些通道可视化:

import cv2

img = cv2.imread('../img/dog.jpg')

im1=img.copy()
im2=img.copy()
im3=img.copy()


im1[:,:,0]=0
im1[:,:,1]=0

im2[:,:,2]=0
im2[:,:,1]=0

im3[:,:,2]=0
im3[:,:,0]=0


cv2.imshow("Original Image",img)
cv2.imshow("Red channel",im1)
cv2.imshow("Blue channel",im2)
cv2.imshow("Green channel",im3)

cv2.waitKey(0)
cv2.destroyAllWindows()

前面的代码分别显示图像的三个通道。首先,我们将 im1 中的红色和绿色通道值设置为 0。同样,我们也可以在 im2 和 im3 中将其他两个通道的值设置为 0,从而输出其他两个通道的图像。

RGB 是计算机制图、数字成像和视频制作中广泛使用的色彩模型,用于在电视、计算机显示器和移动设备等电子设备上显示图像。在 OpenCV 中,RGB 也被用于最常见的任务;但在本例中,通道被反转,以创建 BGR 色彩空间。

3.4.2 蓝绿红(BGR)色彩空间

BGR 色彩空间是反转的 RGB 色彩空间。这是 OpenCV 中最常用的色彩空间。与 RGB 色彩空间相比,除了通道的定位外,没有其他区别。OpenCV 使用 BGR 的唯一原因是 BGR 曾被用作某些硬件和软件系统的默认格式,而这一惯例也被沿用到 OpenCV 等一些现代图像处理库中。Matplotlib 使用 RGB 色彩空间,因此在尝试使用 matplotlib 显示 OpenCV 图像之前,我们要确保更改图像的色彩空间。

3.4.3 色相饱和度值(HSV Hue Saturation and Value)色彩空间

色相饱和度和值是该色彩空间的三个组成部分。让我们更好地了解这三个通道:

  • 色相: 色调指的是我们感知到的纯色。色调本质上是一种没有添加任何白色或黑色的纯色。因此,举例来说,所有类型的蓝色,无论是深蓝还是浅蓝,都具有相同的蓝色色调。
    色相值的范围从 0 度到 360 度,代表一整圈的颜色。红色位于 0 度,绿色位于 120 度,蓝色位于 240 度。OpenCV 的 HSV 色彩空间中的色调分量是一个从 0 到 255 的 uint8 值,但实际的色调范围是 0 到 360 度。为了在 8 位整数中适应这一范围,数值被缩减为 0-179,其中每个值对应一个特定的色调。

  • 饱和度: 饱和度表示颜色的强度。饱和度值以 0% 到 100% 的百分比表示。饱和度值为 100%,表示颜色完全饱和,即颜色强度达到最大。饱和度为 0% 则没有颜色,是纯白色像素。

  • 值: 值是在色调中加入白色或黑色的量。它代表颜色的明暗程度。也可以用百分比来表示,范围从 0% 到 100%。0% 表示最暗的颜色(黑色),而 100% 表示最亮的颜色(白色)。

与 RGB 色彩空间不同,HSV 色彩空间不是基于三原色的简单相加。与 RGB 或 BGR 色彩空间相比,HSV 色彩空间的优点是将色彩信息与亮度信息分开。这使得在不改变图像亮度的情况下调整颜色变得更加简单。

现在我们已经探索了两种色彩空间,可以尝试改变图像的色彩空间。我们将使用 cv2.cvtColor 函数来改变图像的色彩空间。

cvtColor()
cv2.cvtColor(src, code, dst, dstCn=0)

参数

  • src:要转换的源图像。

  • code: 表示要执行的转换类型。该参数定义了图像的当前色彩空间,并指定了图像需要转换到的理想色彩空间。.Code "有很多可能的选项。其中几个如下:

    • cv2.COLOR_BGR2HSV:将图像从 BGR 转换为 HSV。
    • cv2.COLOR_BGR2GRAY:将图像从 BGR 转换为灰度。
    • cv2.COLOR_HSV2BGR:将图像从 HSV 转换为 BGR。
    • cv2.COLOR_BGR2RGB:将图像从 BGR 转换为 RGB。
  • dst: 输出变量

  • dstCn: 这是输出图像的通道数。默认值为 0,与输入图像的通道数一致。

import cv2

img_bgr = cv2.imread('../img/dog.jpg')

# BGR to grayscale
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

cv2.imshow("Original Image", img_bgr)
cv2.imshow('Grayscale Image', img_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()

3.4.4 色相饱和亮度(HSL)色彩空间

HSL(Hue Saturation Lightness) 色相饱和亮度是图像处理中使用的另一种色彩模型。该色彩空间与 HSV 色彩空间类似,但在计算亮度方面略有不同。

色相和饱和度通道与 HSV 色彩空间类似。不过,在该空间中,数值通道被亮度通道取代。HSL 中的 L 通道旨在模仿人类感知亮度的方式,与 HSV 中的 V 通道相比,它与人类感知亮度的方式联系更为紧密。相比之下,HSV 空间中的值通道代表 R、G 和 B 颜色分量的最大值:

  • 色调: 色调指的是我们感知到的纯色。这与 HSV 通道的描述类似。
  • 饱和度: 饱和度表示颜色的强度。这也与 HSV 通道中的描述类似。
  • 亮度 明度是衡量颜色亮度或暗度的标准,0% 的明度表示黑色,100% 的明度表示白色。这对于使图像变亮或变暗以及为图像添加创意点缀都很有用。

增加亮度值会使颜色变亮,更接近白色,而减少亮度值则会使颜色变暗。当亮度值为 50%时,颜色保持原样。亮度值低于 50%,颜色会变暗,高于 50%,颜色会变亮。

例如,我们将 HSL 色彩空间中的灰色表示为 HSL:色相 = 0°,饱和度 = 0%,明度 = 50%。

如果我们增加亮度值,灰色就会变浅,更接近白色,但仍可识别为灰色。同样,如果我们降低亮度值,灰色会变得更暗,更接近黑色。

总的来说,HSL 和 HSV 色彩空间都有各自独特的优势,并可根据执行任务的不同情况发挥作用。是否使用它们在很大程度上取决于任务的具体要求。

3.4.5 LAB色彩空间

LAB 色彩空间的设计与人类视觉系统非常相似。该色彩空间模仿人眼感知色彩的方式,因此比其他任何色彩空间都更接近人眼。LAB 色彩空间也被称为 CIE LAB 色彩空间,因为它是由国际照明委员会(CIE)于 1976 年开发的,旨在创建一个标准化的色彩模型。

LAB 色彩空间由三个维度组成:

  • L 通道(亮度): L 通道代表亮度维度。它描述图像的亮度。数值范围为 0 到 100,其中 0 表示亮度最低(黑色),100 表示亮度最高(白色)。
    • a 通道(绿色-红色): 它定义了一侧的纯绿色和另一侧的纯红色。该维度的值范围为 -128 至 +127,定义了绿色和红色通道之间的颜色。负值代表绿色的色调,随着正值的增加,红色的色调也由这些值来定义。
    • b 通道(蓝-黄): 它在一侧定义纯蓝色,在另一侧定义纯红色。这个维度的值范围为 -128 到 +127,定义了蓝色和黄色通道之间的颜色。负值代表蓝色的深浅,随着正值的增加,黄色的深浅也由这些值来定义。

该色彩模型的设计方式使其不受任何特定设备或技术的影响,从而使其更加通用,适用于各个领域。

3.4.6 YCbCr 色彩空间

YCbCr 色彩空间是一种色彩编码系统,它将色彩表示为亮度(luma)和两个色差信号(chroma)的组合。这种色彩空间将亮度(亮度)和色度(色彩)信息分开,可以更有效地压缩图像。

YCbCr 色彩空间与 RGB 色彩空间类似,但它使用的是亮度(Y)、蓝差(Cb)和红差(Cr)分量,而不是红、绿、蓝分量。Y 表示图像的亮度,而 Cb 和 Cr 表示色彩与亮度之间的差异。

  • Y 通道: 该通道表示色彩的亮度,有时也称为亮度通道。
  • YCb 和 Cr 通道: 这些通道代表图像的颜色信息。Cb 通道表示蓝色差异,Cr 通道表示红色差异。

3.4.7 灰度

灰度图像只用一个通道表示,包含 0 到 255 的数值。该值表示像素上的光量。数值为 0 表示像素上没有光,因此像素的颜色为黑色。而 255 表示最大值,其值为白色。介于两者之间的所有值都是不同的灰度。

从技术上讲,灰度并不是一种色彩空间,因为它是图像的单通道表示,不包含任何色彩信息。

在本书的学习过程中,我们会多次将图像转换为灰度图像进行处理。不过,有一点需要记住。在大多数将 RGB 转换为灰度的标准算法中,红色、绿色和蓝色通道的权重并不相等。这是因为人眼对绿光比对红光或蓝光更敏感,所以在转换过程中通常会给绿光更多的权重。一种常用的方法是使用以下公式

灰度 = 0.2989 * 红色 + 0.5870 * 绿色 + 0.1140 * 蓝色

3.5 小结

本章讨论了使用 OpenCV 进行图像处理的几个重要操作。我们从基于平移的操作(如旋转和调整大小)开始,学习了如何操作图像的大小和方向。然后,我们介绍了算术运算,包括加法、减法和除法,以及位运算,如 AND、OR 和 XOR。最后,我们深入学习了图像通道和色彩空间,探索了图像的各种表示方法,以帮助完成图像处理任务。

posted @ 2023-12-21 17:55  磁石空杯  阅读(241)  评论(0编辑  收藏  举报