欢迎来到OpenCV的奇妙世界!如果你已经配置好了OpenCV环境,并对Python和NumPy有了初步了解,那么现在是时候深入学习图像的基本操作了。这些操作是后续进行更复杂图像处理和计算机视觉任务的基石。(部分图片资源来于网络。如有侵权行为,联系我删除)
在本篇博客中,你将学习到:
1.加载、显示和保存图像
2.获取图像属性(高度、宽度、通道等)
3.访问和修改像素值
4.图像ROI提取与操作
5.通道分离与合并
6.图像的算术运算(加法、混合)
准备工作:
确保你已经安装了opencv-python, numpy 和 matplotlib(可选,但推荐用于某些显示场景).
pip install opencv-python numpy matplotlib
让我们开始吧!
1.加载、显示和保存图像
这是与图像打交道最基本的第一步。
1.1加载图像(cv.imread())
OpenCV使用cv2.imread()函数来加载图像。
语法: image = cv2.imreaad(filepath,flags)
参数:
filepath:图像文件的路径(例如 “lena.jpg”, “images/my_photo.png”)
flags(可选):指定加载图像的颜色类型。常用标志有:
cv2.IMREAD_COLOR(或1):加载彩色图像,任何透明度都将被忽略。这是默认标志。图像将是BGR格式
cv2.IMREAD_GRAYSCALE(或0):以灰度模式加载图像。
cv2.IMREAD_UNCHANGED(或-1):加载图像,包括alpha通道(如果存在)。
示例代码:(路径必须是英文路径!)
import cv2
import numpy as np
# 加载彩色图像 (默认)
img_color = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_COLOR)
# 或者简单地:img_color = cv2.imread('path_to_your_image.jpg')
# 加载灰度图像
img_gray = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 检查图像是否加载成功
if img_color is None:
print("错误:无法加载彩色图像,请检查路径!")
else:
print("彩色图像加载成功!")
if img_gray is None:
print("错误:无法加载灰度图像,请检查路径!")
else:
print("灰度图像加载成功!")
这是一张彩色图与灰度图,你可以尝试加载它们。
1.2显示图像(cv2.imshow())
语法:cv2.imshow(window_name, image)
参数:
- window_name: 显示图像的窗口名称(字符串)。
- image: 要显示的图像 (NumPy 数组)。
为了让窗口保持显示直到用户按下某个键,我们通常配合使用 cv2.waitKey()。为了在关闭窗口后释放资源,使用 cv2.destroyAllWindows()。
- cv2.waitKey(delay): 等待指定的毫秒数,如果在这期间按下任何键,则返回该键的 ASCII 码。如果参数为 0,则无限期等待按键。
- cv2.destroyAllWindows(): 关闭所有由 OpenCV 创建的窗口。
- cv2.destroyWindow(window_name): 关闭指定的窗口。
示例程序:(路径必须是英文路径!)
import cv2
img = cv2.imread('path_to_your_image.jpg')
if img is not None:
cv2.imshow('My Image Window', img) # 显示图像
cv2.waitKey(0) # 等待用户按键 (0 表示无限等待)
cv2.destroyAllWindows() # 关闭所有窗口
else:
print("图像未加载,无法显示。")
显示效果如下:
1.3保存图像(cv2.imwrite())
cv2.imwrite() 函数用于将图像保存到文件。
- 语法: cv2.imwrite(filepath, image)
- 参数:
- filepath: 保存图像的文件路径和名称 (例如 “output.png”, “processed/image_gray.jpg”)。文件扩展名决定了图像的格式。
- image: 要保存的图像 (NumPy 数组)。
示例代码:(路径必须是英文路径!)
import cv2
img = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE)
if img is not None:
# 保存灰度图像为 PNG 格式
success = cv2.imwrite('grayscale_image.png', img)
if success:
print("图像成功保存为 grayscale_image.png")
else:
print("保存图像失败!")
else:
print("图像未加载,无法保存。")
2.获取图像属性
加载到内存中的图像(NumPy 数组)有很多有用的属性。
- image.shape: 返回一个包含图像行数(高度)、列数(宽度)和通道数的元组。
- 对于彩色图像 (BGR),它返回 (高度, 宽度, 3)。
- 对于灰度图像,它返回 (高度, 宽度),因为只有一个通道。你可以通过 img.ndim 查看维度数量。
- image.size: 返回图像的像素总数 (高度 * 宽度 * 通道数)。
- image.dtype: 返回图像的数据类型(例如 uint8,表示无符号8位整数,像素值范围 0-255)。
示例程序:(路径必须是英文路径!)
import cv2
# 加载彩色图像
img_color = cv2.imread('path_to_your_image.jpg')
if img_color is not None:
print("彩色图像属性:")
print(" 形状 (Shape):", img_color.shape) # (高度, 宽度, 通道数)
print(" 总像素数 (Size):", img_color.size)
print(" 数据类型 (dtype):", img_color.dtype)
height, width, channels = img_color.shape
print(f" 高度: {height}px, 宽度: {width}px, 通道数: {channels}")
print("-" * 20)
# 加载灰度图像
img_gray = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE)
if img_gray is not None:
print("灰度图像属性:")
print(" 形状 (Shape):", img_gray.shape) # (高度, 宽度)
print(" 总像素数 (Size):", img_gray.size)
print(" 数据类型 (dtype):", img_gray.dtype)
height_gray, width_gray = img_gray.shape
print(f" 高度: {height_gray}px, 宽度: {width_gray}px, 通道数: 1 (隐式)")
彩色图像属性: 形状 (Shape): (1404, 1000, 3) 总像素数 (Size): 4212000 数据类型 (dtype): uint8 高度: 1404px, 宽度: 1000px, 通道数: 3 | |
灰度图像属性: 形状 (Shape): (1404, 1000) 总像素数 (Size): 1404000 数据类型 (dtype): uint8 高度: 1404px, 宽度: 1000px, 通道数: 1 (隐式) |
3.像素访问和修改
我们可以直接访问和修改图像中的特定像素值。记住,OpenCV 加载的彩色图像默认是 BGR 顺序(蓝、绿、红)。
3.1访问像素值
你可以像访问 NumPy 数组元素一样访问像素。坐标通常是 [行(y), 列(x)]。
示例代码:
import cv2
import numpy as np
img = cv2.imread('path_to_your_image.jpg')
if img is not None:
# 获取坐标 (100, 50) 处的像素值 (假设图像足够大)
# 对于彩色图像,返回一个 BGR 值的数组
(b, g, r) = img[100, 50]
print(f"像素 (100, 50) - B: {b}, G: {g}, R: {r}")
# 对于灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 先转换为灰度图
gray_pixel_value = img_gray[100, 50]
print(f"灰度图像像素 (100, 50) - 强度: {gray_pixel_value}")
# 更高效的方式访问单个通道 (例如,只获取蓝色通道的值)
blue_channel_value = img[100, 50, 0] # 0 代表蓝色通道
print(f"像素 (100, 50) - 仅蓝色通道: {blue_channel_value}")
像素 (100, 50) – B: 163, G: 193, R: 228 灰度图像像素 (100, 50) – 强度: 200 像素 (100, 50) – 仅蓝色通道: 163 |
3.2修改像素值
同样,你可以给像素赋新值。
示例代码:
import cv2
import numpy as np
img = cv2.imread('path_to_your_image.jpg')
if img is not None:
# 将左上角 10x10 的区域变为红色
# 注意:这里的赋值顺序是 BGR,所以红色是 [0, 0, 255]
img[0:10, 0:10] = [0, 0, 255] # 红色
cv2.imshow('Modified Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.图像ROI提取与操作
ROI 指的是图像中的感兴趣区域。我们经常需要对图像的特定部分进行操作,而不是整个图像。NumPy 的切片功能使得提取 ROI 非常简单。
示例代码:
import cv2
import numpy as np
img = cv2.imread('path_to_your_image.jpg')
if img is not None:
# 提取区域从 y=50 到 y=150,x=70 到 x=170
# 注意:OpenCV (和 NumPy) 坐标是 (y, x) 或 (row, col)
roi = img[50:150, 70:170] # 切片 [startY:endY, startX:endX]
cv2.imshow('Original Image', img)
cv2.imshow('ROI', roi)
# 我们可以对 ROI 进行操作,例如将其复制到图像的另一位置
# 假设我们要将这个提取的区域复制到图像的左上角 (确保目标区域大小与 ROI 相同)
img[0:100, 0:100] = roi # 将 roi 粘贴到 (0,0) 到 (100,100) 的区域
cv2.imshow('Image with Copied ROI', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print("图像加载失败。")
5.通道分离与合并
彩色图像通常有多个颜色通道(例如 B, G, R)。有时我们需要单独处理这些通道,或者将单独的通道合并成一个彩色图像。
5.1通道分离(cv2.split())
cv2.split() 函数将一个多通道图像分离成多个单通道图像。
示例代码:
import cv2
img_color = cv2.imread('path_to_your_image.jpg')
if img_color is not None:
b, g, r = cv2.split(img_color) # 分离通道
# 显示各个通道 (它们将以灰度图形式显示,因为它们是单通道的)
cv2.imshow('Blue Channel', b)
cv2.imshow('Green Channel', g)
cv2.imshow('Red Channel', r)
cv2.resizeWindow('Blue Channel', 400, 400)
cv2.resizeWindow('Green Channel', 400, 400)
cv2.resizeWindow('Red Channel', 400, 400)
# 查看某个通道的属性
print("蓝色通道的形状:", b.shape) # (高度, 宽度)
# 例如,让图像只保留红色通道,其他通道设为0
zeros = np.zeros(img_color.shape[:2], dtype="uint8")
red_only_image = cv2.merge([zeros, zeros, r])
cv2.imshow('Red Only Image', red_only_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print("无法加载图像。")
注意: cv2.split() 是一个相对耗时的操作。如果只是为了访问某个特定通道的像素,使用 NumPy 索引会更高效: b_channel = img_color[:, :, 0] g_channel = img_color[:, :, 1] r_channel = img_color[:, :, 2]
5.2通道合并(cv2.merge())
cv2.merge() 函数将多个单通道图像合并成一个多通道图像。
import cv2
import numpy as np
img_color = cv2.imread('path_to_your_image.jpg')
if img_color is not None:
b, g, r = cv2.split(img_color)
# 合并通道回彩色图像 (注意顺序 B, G, R)
merged_img = cv2.merge([b, g, r])
cv2.imshow('Merged Image', merged_img)
# 示例:创建一个只有蓝色和绿色的图像,红色通道为0
zeros = np.zeros_like(b) # 创建一个与b通道形状和类型相同的全0数组
blue_green_img = cv2.merge([b, g, zeros])
cv2.imshow('Blue-Green Image', blue_green_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
6. 图像的算术运算
OpenCV 允许对图像进行多种算术运算。这里我们关注加法和混合。
6.1 图像加法 (cv2.add())
你可以使用 cv2.add() 将两张图像相加。OpenCV 的加法是饱和运算(Saturating operation),这意味着如果结果超过最大值(通常是255),则会被截断到最大值。而 NumPy 的加法是模运算(Modulo operation),例如 250 + 10 = 260 % 256 = 4。
示例代码:
import cv2
import numpy as np
# 创建两个简单的图像 (确保它们大小和类型相同)
img1 = np.full((100, 100, 3), (50, 100, 150), dtype=np.uint8) # 某种颜色
img2 = np.full((100, 100, 3), (220, 180, 120), dtype=np.uint8) # 另一种颜色
# OpenCV 加法 (饱和运算)
cv_added_img = cv2.add(img1, img2)
# 例如,对于蓝色通道: 50 + 220 = 270,饱和后变为 255
# 对于绿色通道: 100 + 180 = 280,饱和后变为 255
# 对于红色通道: 150 + 120 = 270,饱和后变为 255
# NumPy 加法 (模运算)
np_added_img = img1 + img2
# 例如,对于蓝色通道: (50 + 220) % 256 = 270 % 256 = 14
cv2.imshow('Image 1', img1)
cv2.imshow('Image 2', img2)
cv2.imshow('OpenCV Add', cv_added_img)
print("OpenCV Add (pixel [0,0]):", cv_added_img[0,0]) # 应该接近 [255, 255, 255]
cv2.imshow('NumPy Add', np_added_img)
print("NumPy Add (pixel [0,0]):", np_added_img[0,0]) # 可能会有小于255的值
cv2.waitKey(0)
cv2.destroyAllWindows()
通常,进行图像处理时,OpenCV 的饱和运算更符合我们的直觉。
6.2图像混合/融合 (cv2.addWeighted())
这是一种特殊的加法,可以给两张图像分配不同的权重,实现图像的混合或透明效果。公式如下: g(x) = (1 – α)f₀(x) + αf₁(x) 或者更通用的 OpenCV 函数形式: dst = cv2.addWeighted(src1, alpha, src2, beta, gamma) 其中 dst = alpha * src1 + beta * src2 + gamma。alpha 和 beta 是权重,gamma 是一个标量,加到每个和上。
示例代码:
import cv2
import numpy as np
# 创建两个简单的图像 (确保它们大小和类型相同)
img1 = np.full((100, 100, 3), (50, 100, 150), dtype=np.uint8) # 某种颜色
img2 = np.full((100, 100, 3), (220, 180, 120), dtype=np.uint8) # 另一种颜色
# 确保图像加载成功且大小相同
if img1 is None or img2 is None:
print("错误:一张或两张图片加载失败!")
elif img1.shape != img2.shape:
print("错误:两张图片的大小必须相同才能混合!")
# 可以先调整大小: img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))
else:
# 混合图像:img1 权重 0.7, img2 权重 0.3, gamma 为 0
blended_img = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)
cv2.imshow('Image 1', img1)
cv2.imshow('Image 2', img2)
cv2.imshow('Blended Image', blended_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
总结与下一步
恭喜你!你已经学习了 OpenCV 中最核心的图像基本操作。这些操作是你进行更高级图像处理任务(如颜色空间转换、几何变换、阈值处理等)的基础。
练习建议:
- 尝试加载你自己的图片,将其转换为灰度图,然后保存。
- 选择一张彩色图片,提取其 R 通道,并将该通道显示出来。
- 在一张图片中选取一个 ROI,然后将其复制到图片的其他位置。
- 尝试用 cv2.addWeighted() 将两张你喜欢的图片以不同的权重混合起来,观察效果。
继续前进,探索 OpenCV 更强大的功能吧!希望这篇博客对你有所帮助!记得多动手实践,这是掌握 OpenCV 的最佳途径。祝学习愉快!