OpenCV计算机视觉实战(5)——图像基础操作全解析
0. 前言
在本节中,将从零开始深入介绍 OpenCV
的核心基础操作——包括像素级别的精细控制与感兴趣区域 (Region of Interest
, ROI
) 截取、BGR
通道的拆分合并与色彩增强,以及多种几何变换(平移、旋转、缩放、翻转等)。通过实战示例与详尽解析,理解其中的设计理念与性能考量。
1. 像素级操作与 ROI
像素级 (Pixel-level
) 操作是图像处理的最底层手段,允许我们直接读取、修改单个像素值,从而实现亮度调节、阈值分割等基础功能,也为更高级的滤波和边缘检测等算法打下基础。本节将介绍如何读取、修改图像中的单个像素或像素块,并演示如何截取感兴趣区域 (Region of Interest
, ROI
) 进行操作。
(1) OpenCV
以 BGR
顺序和行优先 (row-major
) 方式在内存中存储图像,每个像素在 (y, x)
处连续占用三个字节,通过 img[y, x]
进行索引可高效访问:
import cv2
# 读取图像
img = cv2.imread('1.jpeg')
# 读取单个像素(注意 OpenCV 读取为 BGR 顺序)
b, g, r = img[100, 50]
print(f"Position (100,50) - B: {b}, G: {g}, R: {r}")
# 修改单个像素,将其设为红色
img[100, 50] = [0, 0, 255]
关键代码解析:
img[y, x]
:按行列索引获取BGR
三通道值img[y, x] = [B, G, R]
:直接赋值可修改像素颜色
(2) 通过 NumPy
切片提取 ROI
(img[y1:y2, x1:x2]
) 不会拷贝数据,而是获得对原图的视图 (view
),因而在实时目标检测、模板匹配和动态区域增强中具有显著性能优势:
# 截取 ROI 区域(行 200-400, 列 300-500)
roi = img[200:400, 300:500]
# 在 ROI 内画一个绿色矩形
cv2.rectangle(img, (300, 200), (500, 400), (0, 255, 0), 2)
# 将 ROI 复制到左上角
img[0:200, 0:200] = roi[0:200, 0:200]
# 显示与保存
cv2.imshow('Pixel & ROI', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output_pixel_roi.jpg', img)
关键代码解析:
img[y1:y2, x1:x2]
:切片操作截取ROI
,是对原图的视图 (view
),修改会反映到原图cv2.rectangle(img, pt1, pt2, color, thickness)
:在图像上绘制矩形,pt1
、pt2
为矩形左上角和右下角坐标,color
为BGR
(3) 利用位运算 (bitwise_and
, bitwise_not
) 与遮罩,可实现精确的图像叠加和透明度控制,广泛应用于水印嵌入、增强现实标注等场景。例如,在一张背景图上,截取 Logo
区域作为 ROI
,做透明度叠加拼贴:
import cv2
import numpy as np
# 读取背景和 Logo(含 alpha 通道)
bg = cv2.imread('background.jpeg')
logo = cv2.imread('logo.png', cv2.IMREAD_UNCHANGED) # 4 通道:BGRA
# 提取 Logo 的 alpha 通道作为遮罩
b, g, r, a = cv2.split(logo)
mask = cv2.merge([a, a, a]) # 转成 3 通道遮罩
# 确定粘贴位置
h, w = logo.shape[:2]
x, y = 50, 100
roi = bg[y:y+h, x:x+w]
mask = cv2.resize(mask, (roi.shape[1], roi.shape[0]))
# 叠加:先抠出背景,再叠加 Logo
roi_bg = cv2.bitwise_and(roi, cv2.bitwise_not(mask))
mask = cv2.resize(mask, (logo.shape[1], logo.shape[0]))
logo_fg = cv2.bitwise_and(logo[..., :3], mask)
logo_fg = cv2.resize(logo_fg, (roi_bg.shape[1], roi_bg.shape[0]))
combined = cv2.add(roi_bg, logo_fg)
bg[y:y+h, x:x+w] = combined
cv2.imwrite('output_paste.png', bg)
关键代码解析:
cv2.IMREAD_UNCHANGED
:载入带透明通道的图像cv2.bitwise_and(src1, src2)
:按位与,可用于遮罩抠图cv2.add(src1, src2)
:像素级加法,相当于src1 + src2
,支持自动饱和截断cv2.resize(src, (width, height))
:调整图像src
尺寸为(width, height)
2. 图像通道分离与合并
图像通道分离与合并是图像处理中的基本操作,主要用于对彩色图像的不同颜色通道进行单独处理。彩色图像通常由多个颜色通道组成。例如:
RGB
图像:红 (Red
)、绿 (Green
)、蓝 (Blue
) 三个通道CMYK
图像:青色 (Cyan
)、品红 (Magenta
)、黄色 (Yellow
)、黑色 (Key
) 四个通道
(1) RGB
图像由多个通道 (B
、G
、R
)组成,分离通道后能够分别对各色彩分量进行独立处理,用于色彩平衡、滤波和特征提取等任务:
import cv2
import numpy as np
# 读取图像
img = cv2.imread('1.jpeg')
# 分离通道
b_channel, g_channel, r_channel = cv2.split(img)
def enhance(channel):
return cv2.normalize(channel, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
# 分别对各通道进行处理
b_enh = enhance(b_channel)
g_enh = enhance(g_channel)
r_enh = enhance(r_channel)
关键代码解析:
cv2.split(img)
:将H×W×3
彩色图分离成三个单通道图像cv2.normalize(src, dst, alpha, beta, norm_type)
:对像素值做归一化,增强对比度,norm_type
参数常用值cv2.NORM_MINMAX
(2) 将处理后的单通道重新合并 (cv2.merge
) 回 BGR
图像后,即可获得对比度和色调双重优化的结果,广泛用于实时视频色彩分级和创意滤镜特效:
# 合并通道
merged = cv2.merge([b_enh, g_enh, r_enh])
# 显示与保存
cv2.imshow('Original', img)
cv2.imshow('Enhanced Channels', merged)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output_enhanced.jpg', merged)
关键代码解析:
cv2.merge([b, g, r])
:将三个单通道图像按BGR
顺序合并为彩色图
(3) 对各通道应用直方图均衡化或自适应直方图均衡化可在不失真色调的情况下显著提升全局及局部对比度,这在医学影像增强和监控视频优化中尤为关键:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('1.jpeg')
b, g, r = cv2.split(img)
# 直方图统计
hist_b = cv2.calcHist([b], [0], None, [256], [0,256])
hist_g = cv2.calcHist([g], [0], None, [256], [0,256])
hist_r = cv2.calcHist([r], [0], None, [256], [0,256])
# 均衡化
b_eq = cv2.equalizeHist(b)
g_eq = cv2.equalizeHist(g)
r_eq = cv2.equalizeHist(r)
merged_eq = cv2.merge([b_eq, g_eq, r_eq])
cv2.imwrite('output_eq.jpg', merged_eq)
关键代码解析:
cv2.calcHist(images, channels, mask, histSize, ranges)
:计算直方图,常用于分析与绘制cv2.equalizeHist(src)
:对灰度图像做直方图均衡化,提升对比度
3. 几何变换
几何变换通过构建仿射或透视变换矩阵,重新映射像素空间,可实现平移、旋转、缩放、翻转等基础操作,并拓展至更高级的仿射、透视校正等功能,是图像对齐、数据增强的基础。
(1) 平移:使用 2×3
平移矩阵在 x
、y
方向偏移像素,常用于图像拼接和视频帧稳定中消除抖动
import cv2
import numpy as np
img = cv2.imread('1.jpeg')
h, w = img.shape[:2]
# 构造平移矩阵:M = [[1, 0, tx], [0, 1, ty]]
tx, ty = 50, 30
M = np.float32([[1, 0, tx], [0, 1, ty]])
shifted = cv2.warpAffine(img, M, (w, h))
cv2.imshow('Shifted', shifted)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output_shifted.jpg', shifted)
关键代码解析:
np.float32([[1,0,tx],[0,1,ty]])
:构造2×3
平移矩阵,tx
、ty
分别表示在x
、y
方向上的偏移量cv2.warpAffine(src, M, (w, h))
:对图像做仿射变换,输出大小为(w,h)
(2) 旋转:cv2.getRotationMatrix2D
可围绕指定中心生成旋转矩阵,并通过 cv2.warpAffine
应用,绕图像中心或指定点旋转给定角度,插值方式(如 INTER_LINEAR
, INTER_CUBIC
) 决定输出平滑度与性能权衡:
import cv2
img = cv2.imread('1.jpeg')
h, w = img.shape[:2]
center = (w//2, h//2)
# 构造旋转矩阵:M = cv2.getRotationMatrix2D(center, angle, scale)
angle, scale = 45, 1.0
M = cv2.getRotationMatrix2D(center, angle, scale)
rotated = cv2.warpAffine(img, M, (w, h))
cv2.imshow('Rotated', rotated)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output_rotated.jpg', rotated)
关键代码解析:
cv2.getRotationMatrix2D(center, angle, scale)
:返回旋转矩阵,其中angle
为逆时针角度,scale
为缩放因子- 旋转同样调用
cv2.warpAffine
应用矩阵变换
(3) 缩放:cv2.resize
支持显式指定尺寸或按 fx
, fy
缩放因子进行缩放,并根据放大或缩小场景选择 INTER_LINEAR
或 INTER_AREA
插值,以保持图像质量和计算效率:
import cv2
img = cv2.imread('1.jpeg')
# 按比例缩放
fx, fy = 0.5, 0.5 # 宽高均缩小一半
resized = cv2.resize(img, None, fx=fx, fy=fy, interpolation=cv2.INTER_LINEAR)
# 指定大小缩放
new_size = (1000, 600)
resized2 = cv2.resize(img, new_size, interpolation=cv2.INTER_AREA)
cv2.imshow('Resized', resized2)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output_resized.jpg', resized2)
关键代码解析:
cv2.resize(src, dsize, fx, fy, interpolation)
:dsize=None
且给定fx
,fy
时按比例缩放;- 给定
dsize=(width,height)
时缩放到指定大小 interpolation
:常见参数值包括INTER_LINEAR
、INTER_AREA
(4) 翻转:cv2.flip
可在水平、垂直或同时轴向进行镜像,作为简单有效的数据增强手段,在机器学习数据集扩充和用户界面图像校正中广泛应用:
import cv2
img = cv2.imread('1.jpeg')
# flipCode = 0:垂直翻转;>0:水平翻转;<0:同时翻转
flip_vert = cv2.flip(img, 0)
flip_horiz = cv2.flip(img, 1)
flip_both = cv2.flip(img, -1)
cv2.imshow('Flip Vert', flip_vert)
cv2.imshow('Flip Horiz', flip_horiz)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite('output_flip_vert.jpg', flip_vert)
关键代码解析:
cv2.flip(src, flipCode)
:flipCode=0
:沿x
轴翻转(上下翻转)flipCode=1
:沿y
轴翻转(左右翻转)flipCode=-1
:同时沿x
、y
轴翻转
(5) 仿射变换:保持直线平行关系,可实现缩放、剪切、旋转、平移的组合;透视变换:四点对应映射,用于“透视校正”,如白板拍摄矫正、商品海报拍摄矫正:
import cv2
import numpy as np
img = cv2.imread('1.jpeg')
# 假设手工或检测得到四个角点 pts_src
pts_src = np.float32([[100,15], [1200,215], [85,610], [530,780]])
# 设定目标顶点:矩形
width, height = 900, 500
pts_dst = np.float32([[0,0], [width,0], [0,height], [width,height]])
# 计算透视矩阵并变换
M = cv2.getPerspectiveTransform(pts_src, pts_dst)
warp = cv2.warpPerspective(img, M, (width, height))
cv2.imwrite('output_warp.jpg', warp)
关键代码解析:
cv2.getPerspectiveTransform(src, dst)
:计算3×3
透视变换矩阵cv2.warpPerspective(src, M, dsize)
:应用透视变换,实现投影校正
小结
在本文中,我们首先从最底层的像素与 ROI
操作入手,理解了如何高效访问与修改图像数据;继而通过通道分离与合并,掌握了色彩处理与对比度增强的技巧;最后借助仿射与透视变换,实现了从基础平移、旋转到复杂校正的完整流程。
系列链接
OpenCV计算机视觉实战(1)——计算机视觉简介
OpenCV计算机视觉实战(2)——环境搭建与OpenCV简介
OpenCV计算机视觉实战(3)——计算机图像处理基础
OpenCV计算机视觉实战(4)——计算机视觉核心技术全解析