opencv图像处理机器学习真实项目教程(python实现)2图像入门

发布时间 2023-12-21 07:28:56作者: 磁石空杯

本章介绍图像的基本概念和基本操作。 我们将首先提供像素等图像基础知识的清晰定义。 接下来,我们将深入讲解如何使用 OpenCV 库读取、显示和保存图像。 然后我们将继续使用 OpenCV 在图像上绘制形状的实际任务,重点是矩形、圆形和其他基本形状等主题。

主要内容:

  • 图像和像素简介
  • 读取、显示和写入图像
    • Imread
    • Imshow
    • Imwrite
    • Waitkey
  • 用像素处理图像
    • 访问单个像素
    • 访问感兴趣区域 (ROI)
  • 在OpenCV中绘图
    • Line
    • Rectangle
    • Circle
    • Text

2.1 图像和像素简介

什么是图像? 用非技术术语来说,图像是指场景、物体或人的视觉表示,它使我们能够更好地理解周围的世界。在数字环境中,图像是像素的多维阵列。

像素是图像的构建块。 像素是数字图像的最小单位,包含有关其颜色和位置的信息。 当多个像素在二维网格中聚集在一起时,它们就形成了完整的图像。 数字图像中的像素以网格图案排列以创建整体图像。 每个像素都包含特定的颜色信息,它们一起形成完整的图像。

像素通常用于表示灰度或彩色图像。 灰度图像通常表示为二维像素网格,而彩色图像通常表示为多维矩阵。 在灰度图像中,每个像素都分配有0 到 255 之间的值,表示该点图像的强度。 值 0 表示没有强度,导致黑色像素,而值255表示最大强度,导致纯白色像素。

在彩色图像中,每个像素由三个或四个值的组合表示,最常见的颜色空间是 RGB 颜色空间。 在此空间中,使用表示红色、绿色和蓝色通道强度的三个值来表示单个像素。 每个值的范围从 0 到 255,表示像素中存在的每种颜色的数量。 典型的 RGB 像素可以用(红、绿、蓝)格式表示。

例如,具有 (0,0,0) 值的颜色表示黑色,因为所有颜色的强度均为 0,而 (255,255,255) 表示白色图像,因为所有颜色都有最大值。

让我们看几个关于如何在 RGB 颜色空间中表示颜色的示例:

  • (255,0,0) 产生纯红色,因为红色处于最大值,而绿色和蓝色处于 0。
  • (0,255,0) 产生纯绿色。
  • (0,0,255) 产生纯蓝色。
  • (255,255,0) 产生黄色,因为它是红色和绿色的组合。
  • (128,128,128) 代表灰色。
    PPI(即每英寸像素 Pixels per Inch)表示单英寸数字图像中存在的像素数。 较高的 PPI 意味着每英寸有更多的像素,从而产生更平滑、更细致的图像。 相反,较低的 PPI 意味着像素较大且每英寸的像素较少,从而导致图像细节较少且清晰度较差。

分辨率是一个术语,用于描述构成图像的像素总数。 分辨率越高,像素越多,从而产生更详细和高质量的图像。 分辨率通常以每英寸像素 (PPI) 或每英寸点数 (DPI) 来衡量。 当图像的分辨率较低时,意味着像素较少,因此图像的细节较少。

长宽比是指图像的宽度和高度之间的比例关系,它决定了图像的整体形状。 它通常表示为用冒号分隔的两个数字(例如 4:3 或 16:9),表示图像或屏幕的宽度和高度。 例如,纵横比为 4:3 的图像的宽度为每3 个单位的高度对应 4 个单位的长度。 宽高比用于确保在不同设备上显示图像时图像正确适合显示尺寸。

数字图像的像素数量一直在迅速增加。 第一台商用数码相机 Dycam Model 1 的分辨率仅为 0.01兆像素,而当今的高端相机可以捕获分辨率为 100兆像素或更高的图像。

2.2 加载和显示图像

是时候开始处理图像了! 在本书中,当我们引导您完成探索和操作图像的过程时,您将获得实践经验。 在我们继续前进时,请务必自行实现代码示例,因为这将有助于巩固您对我们将要介绍的概念的理解。

2.2.1 Imread()

要开始使用OpenCV处理图像,我们需要使用imread() 函数。通过该函数,我们可以将图像加载到我们的程序中:

cv2.imread(path, flag=cv2.IMREAD_COLOR)

参数:

  • path: 字符串,表示要读取图像的路径。
  • flag: 可选参数, 指定读取图像的方式。
    • cv2.IMREAD_COLOR (1): 以 BGR 格式加载图像。这是该函数的默认格式。
    • cv2.IMREAD_GRAYSCALE (0):以灰度格式加载图像: 以灰度格式加载图像。
    • cv2.IMREAD_UNCHANGED (-1):以原始格式加载图像: 以原始格式加载图像,通常用于包含 alpha 通道。
cv2.imread(path, 0)

这将以灰度格式加载图像。

2.2.2 imshow

cv2.imshow(winname, mat)

参数:

  • Winname:显示图像的窗口名称。
  • Mat: 表示我们要显示的图像的 NumPy 数组。

2.2.3 imwrite

Imwrite 用于将图像保存到系统中。

cv2.imwrite(filename, img, params=None)

参数:

  • Filename:表示要保存的图像路径的字符串
  • Img: 表示我们要写入的图像的NumPy数组。
  • Params: 可选参数,用于指定图像文件的格式和压缩参数。默认值为None。

示例代码

在本练习中,我们将使用之前学习的代码加载图像并显示图像:

import cv2

# Using imread to read out image
img = cv2.imread("../img/dog.jpg")

# Print the shape of the image
print(img.shape)

# Displaying the image
cv2.imshow("Dog Image", img)

# Wait until a key is pressed
cv2.waitKey(0)

# Close all Windows
cv2.destroyAllWindows()

2.2.3 WaitKey

WaitKey是OpenCV程序中的一个函数,用于让用户在特定时间内或按下某个键之前显示一个窗口。如果没有 waitKey,图像或视频会在用户来得及观看之前立即关闭。

它只接受一个整数参数,即窗口保持打开的毫秒数。如果给定的参数为0或根本没有给定参数,函数将等待按键按下后再关闭窗口。

2.2.3 DestroyAllWindows

DestroyAllWindows是一条简单的命令,用于关闭OpenCV在执行代码期间打开的所有窗口。该命令不需要任何参数。

我们已经成功运行了第一段 OpenCV 代码,现在可以读取并显示图像了。

试试看 现在尝试以不同的路径将前面的图像写入光盘。

2.3 用像素操作图像

图像在 Python 中存储为 NumPy 数组,这意味着图像元素可以像 NumPy 数组一样被索引。通过图像索引,我们可以操作图像中的单个像素或某个像素区域。

2.3.1 访问单个像素

要访问图像中的某个像素,我们可以使用类似的 img[row, col] 索引。使用此方法访问像素值将返回一个包含像素值的 NumPy 数组:

import cv2

# Load an image in grayscale mode
img = cv2.imread('../img/dog.jpg')

# Get the pixel value at x=75, y=25
pixel_value = img[25, 75]

#Print this value
print(pixel_value)

#Manipulate value of this pixel
img[25, 75] = 0

#Rechecking value
print(pixel_value)

结果:

[120 165 222]
[0 0 0]

对于RGB图像,前面的代码行将返回包含三个值的数组,而对于灰度图像,它将只返回值,例如30。

我们还可以使用索引修改像素值。我们可以为某个像素赋值,如下所示:

img[5,7] = 255

如果img是灰度图像,这将为像素赋值255。如果图像img是BGR 格式,那么三个颜色通道的值都将设置为 255。

如果我们想在 RGB 图像中设置特定值,可以使用该特定颜色的颜色代码:

img[5,7] = [0,255,0]

这将把绿色通道值设置为 255,其他两个通道设置为 0,从而得到纯绿色像素。

2.3.2 访问感兴趣区域 (ROI Region of Interest)

现在,我们将讨论如何通过使用索引定义感兴趣区域 (ROI) 来操作图像的整个区域。我们经常需要操作图像的特定区域,而不是单个像素或整个图像。

import cv2

# Load image
img = cv2.imread('../img/dog.jpg')

# Define index values
x=50
y=60
w=75
h=75

# Extract ROI from the image
roi = img[y:y+h,x:x+w]

# Print shape of the extracted ROI
print(roi.shape)

# Assigning a colour to a different ROI
img[100:150,150:200] = (255,255,0)

cv2.imshow('Extracted ROI rectangle', roi)
cv2.imshow('Image with ROI colour', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.4 在OpenCV中绘图

在本节中,我们将学习如何使用 OpenCV 绘制形状。我们可以使用 OpenCV 设计各种形状,包括线、圆、矩形和多边形,还可以自定义它们的大小和颜色。使用 OpenCV 还可以在照片上添加文字。形状有多种用途,包括注释照片和强调照片的特定区域。

首先,我们将创建一张空白画布,在上面绘制各种形状。或者,也可以加载一张图片,然后在上面绘制形状。

为了创建绘制形状的画布,我们可以使用 NumPy 创建一个 NumPy 数组。然后,我们可以使用各种方法在 NumPy 画布上绘图:

canvas = np.zeros((600, 600, 3), dtype=np.uint8)

我们使用 np.zeros 函数创建画布。这是一个 NumPy 函数,用于创建一个具有特定形状和数据类型的 NumPy 数组。在本例中,我们创建了一个具有 "np.uint8 "数据类型的形状数组(600,600,3)。该数据类型对应于 8 位无符号整数,取值范围为 0 至 255。

2.4.1 线条(Line)

我们使用 cv2.line 命令在图像上创建线条。该命令提供多个参数,让我们可以自定义线条,以满足我们的特定需求和要求。

参数:

  • Img: 绘制线条的图像。
  • Pt1:线条的起始坐标: 线条的起始坐标。格式为 tuple (x,y)。
  • Pt2: 线条的终点坐标。格式为 tuple (x,y)。
  • Color:线条的颜色。采用元组(B、G、R)格式。
  • 厚度(Thickness): 线条的厚度(像素)。这是一个可选参数,默认值为 1。
  • lineType(线条类型 线条的类型。我们将不使用此参数,可将其保留为默认值。
  • Shift(移位): 线条坐标中的小数位数。我们将不使用此参数,默认值为 0。
cv2.line(img, pt1, pt2, color, thickness=1, lineType = cv2.LINE_8, shift = 0)

实例:

import numpy as np
import cv2

# Create a black canvas
canvas = np.zeros((600, 500, 3), dtype=np.uint8)

# Define the vertices of the triangle
p1 = (250, 100)
p2 = (100, 400)
p3 = (400, 400)

# Draw the lines using cv2.line()
cv2.line(canvas, p1, p2, (0, 255, 0), 1)
cv2.line(canvas, p3, p1, (255, 0, 0), 3)
cv2.line(canvas, p2, p3, (255, 255, 255), 10)

# Display the image
cv2.imshow("Triangle", canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()

参考资料

2.4.2 矩形(rectangle)

在 OpenCV 中,绘制矩形与绘制直线类似。我们可以使用 cv2.rectangle 命令在 OpenCV 中创建矩形:

Cv2.rectangle(img, pt1, pt2, color, thickness=1, lineType=cv2.LINE_8, shift=0)

参数:

  • Img: 绘制的图像。
  • Pt1:矩形的左上角点: 矩形的左上角点。格式为 tuple (x,y)。
  • Pt2: 矩形的右下角点: 矩形的右下角点。格式为 tuple (x,y)。
  • Color:矩形的颜色将采用元组(B、G、R)格式。
  • 厚度(Thickness): 以像素为单位的矩形边框厚度。这是一个可选参数,默认值为 1。如果矩形的厚度为负值,则会填充矩形。
  • lineType:线条类型: 线条的类型。我们将不使用此参数,因此可将其保留为默认值。
  • Shift(移位): 线条坐标中的小数位数。我们将不使用该参数,默认值为 0。
    现在,根据前面的解释,让我们尝试创建这幅图像:
import numpy as np
import cv2

# Create a black image
img = np.zeros((600, 500, 3), dtype=np.uint8)

# Draw the figure using rectangles and lines
# Face
cv2.rectangle(img, (150, 150), (350, 400), (242, 199, 155), thickness=-1)  

# Cap
cv2.rectangle(img, (100, 50), (400, 150), (198, 131, 56), thickness=-1) 

# Mouth
cv2.rectangle(img, (200, 310), (300, 330), (128, 0, 128), thickness=2) 

# Draw the eyes on the face as X shapes
cv2.line(img, (195, 200), (212, 228), (0, 0, 0), thickness=2)
cv2.line(img, (212, 200), (195, 228), (0, 0, 0), thickness=2)
cv2.line(img, (288, 200), (305, 228), (0, 0, 0), thickness=2)
cv2.line(img, (305, 200), (288, 228), (0, 0, 0), thickness=2)

# Display the image
cv2.imshow('Robo', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.4.3 circle

cv2.circle() 函数用于在图像上绘制圆形:

cv2.circle(img, center, radius, color, thickness=1, lineType = cv2.LINE_8, shift=0)

参数

  • Img: 绘制的图像。
  • Center: 圆的中心点。格式为 tuple (x,y)。
  • Radius: 圆的半径
  • Color:圆的颜色。格式为元组(B、G、R)。
  • Thickness: 圆边框的厚度,以像素为单位: 圆边框的厚度,单位为像素。这是一个可选参数,默认值为 1。如果矩形的厚度为负值,它将填充圆。
  • lineType:线条类型: 线条的类型。我们将不使用此参数,因此可将其保留为默认值。
  • Shift(移位): 线条坐标中的小数位数。我们将不使用此参数,默认值为 0。
    让我们尝试自己创建几个圆:
import numpy as np
import cv2

# Create an empty canvas
canvas = np.zeros((500, 500, 3), dtype=np.uint8)

# Define the center point
center = (250, 250)

# Define the radii of the circles
radius1 = 50
radius2 = 100
radius3 = 150

# Define the colors of the circles
color1 = (0, 0, 255) 
color2 = (255, 0, 0) 
color3 = (0, 255, 0) 

# Define the thickness of the circles
thickness1 = -1 
thickness2 = 2
thickness3 = 10

# Draw the circles on the canvas
cv2.circle(canvas, center, radius1, color1, thickness1)
cv2.circle(canvas, center, radius2, color2, thickness2)
cv2.circle(canvas, center, radius3, color3, thickness3)

# Display the image
cv2.imshow("Image", canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.4.4 文本(Text)

我们使用函数 cv2.putText() 为图像添加文本:

cv2.putText(img, text, org, fontFace=’cv2.FONT_HERSHEY_SIMPLEX’, fontScale=0, color=(0,0,0), thickness=1, lineType=’cv2.LINE_AA’, bottomLeftOrigin=False)

参数:

  • Img: 绘制的图像。
  • Text:文本: 要绘制的文本字符串。
  • org:文本左下角的坐标: 文本左下角的坐标。
  • fontFace:文本的字体类型。这是可选参数,默认值为 cv2.FONT_HERSHEY_SIMPLEX。
  • fontScale:字体缩放比例: 字体比例系数,乘以特定字体的基本尺寸。这是一个可选参数,默认值为 1。
  • Color(颜色):文本的颜色。将采用元组(B、G、R)格式。这是一个可选参数,默认值为 (0,0,0)。
  • 厚度(Thickness): 文本中线条的粗细。这是一个可选参数,默认值为 1。如果粗细为负值,它将填充文本。
  • lineType:线条类型: 线条的类型。我们将不使用此参数,可将其保留为默认值。
  • bottomLeftOrigin: 这是一个标志,用于指示文本的位置。这是一个可选参数,默认值为 "False(假)",这将使文本位于左上角。默认值为 True 时,文本将位于左下角。
import numpy as np
import cv2

# create a blank image
img = np.zeros((600, 500, 3), dtype=np.uint8)

# define the text to be displayed
text = "Hello World!"

# set the text color and position
color = (255, 0, 0)
pos = (50, 200)

# display the text using cv2.putText()
cv2.putText(img, text, pos, cv2.FONT_HERSHEY_SIMPLEX, 2, color, 3)

cv2.imshow("Image with text", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.5 总结

本章扎实地介绍了图像的基本概念和基本操作。我们定义了像素等关键概念,并讲解了如何使用 OpenCV 库读取、显示和保存图像。此外,我们还探讨了在图像上绘制形状的实际任务,重点是矩形和圆形等基本形状。这一基础对于将来构建更复杂的图像处理应用程序非常宝贵。