OpenCV与NumPy图像基础操作指南:像素处理、属性读取与算术运算
本文详细介绍OpenCV结合NumPy进行图像基础处理的方法。涵盖通过坐标直接读取与修改像素值、高效访问图像属性(尺寸、大小、类型),以及利用NumPy索引优化通道分割与合并。此外,解析图像ROI区域操作、边框添加算法(如复制、反射、常量填充),并对比OpenCV与NumPy在图像相加时的溢出处理差异,最后演示使用addWeighted进行图像混合及局部融合技术。
OpenCV图像基础操作概述
1. 像素基本操作
像素读取与修改方法
1.1 读取、修改像素
通过指定[行, 列]坐标即可访问像素数据。对于多通道图像,该操作返回包含所有通道值的数组;对于单通道图像(如灰度图),则直接返回该坐标的像素值。若需获取特定坐标下某通道的值,可使用[行, 列, 通道索引]的方式进行访问。
>>> import cv2
>>> import numpy as np
>>> img = cv2.imread('messi5.jpg')
>>> px = img[100,100]
>>> print( px )
[157 166 200]
# accessing only blue pixel
>>> blue = img[100,100,0]
>>> print( blue )
157
同样地,可以直接通过坐标赋值来修改像素值。
>>> img[100,100] = [255,255,255]
>>> print( img[100,100] )
[255 255 255]
然而,直接逐个读取和修改像素值的效率较低。为了提高性能,建议使用后续介绍的高效方法。
# accessing RED value
>>> img.item(10,10,2)
59
# modifying RED value
>>> img.itemset((10,10,2),100)
>>> img.item(10,10,2)
100
图像属性读取技巧
1.2 读取图像属性
获取图像尺寸时,返回一个包含(行数, 列数, 通道数)的元组。
>>> print( img.shape )
(342, 548, 3)
获取像素总数,其计算公式为:行数 × 列数 × 通道数。
>>> print( img.size )
562248
查看像素的数据类型。
>>> print( img.dtype )
uint8
图像ROI区域操作
1.3 图像ROI操作
可以直接编辑图像的特定区域。例如,将图像左下角50×50像素的区域复制到左上角。
import cv2
import numpy as np
img = cv2.imread("test.jpg")
print(img.shape)
roiTest = img[475:525, 0:50]
img[0:50, 0:50] = roiTest
cv2.imshow("image",img)
cv2.waitKey(0)

通道分割、合并与优化
1.4 分割、合并通道
当需要对图像的特定通道数据进行单独操作时,通常会用到通道的分割与合并。
>>> b,g,r = cv2.split(img)
>>> img = cv2.merge((b,g,r))
或者
b = img[:,:,0]
假设需要将所有红色通道的数据设置为0,无需先分割通道再编辑。使用 img[:,:,2] = 0 即可实现。需要注意的是,cv2.split操作耗时较长,建议优先使用NumPy索引替代,以获得更好的性能。
图像边框添加算法
1.4 生成图像边框
使用 cv2.copyMakeBorder 函数可以为图像添加边框,该函数支持多种边框算法。
void cv::copyMakeBorder (
InputArray src, //原图
//目标图(cpp版本中,若传入此数据且选BORDER_TRANSPARENT,则此数据被top/bottom/left/right切出来的roi部分不会被做任何修改,此图像大小=dst.rows+top+bottom,dst.cols+left+right)
OutputArray dst,
int top, //top/left/bottom/right 四个方向上的边框像素
int bottom,
int left,
int right,
int borderType, //边框类型见下图
const Scalar & value = Scalar() //边框类型为BORDER_CONSTANT时的边框像素
)

BLUE = [255, 0, 0]
img1 = cv2.imread("test.jpg")
replicate = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img1, 100, 100, 100, 100, cv2.BORDER_CONSTANT, value=BLUE)
print(img1.shape, reflect.shape)
plt.subplot(231), plt.imshow(img1, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()
上述示例直观展示了各种边框的效果。同时可以发现,Python版本的API与C++版本相比,默认初始化了一块大小为原始图像尺寸加上各方向边框尺寸的内存区域,并将其作为内置的dst参数。
输出尺寸:(525, 700, 3) (725, 900, 3)
图像算术运算与混合
2. 图像的基本算术操作
2.1 图像相加
进行图像相加时,两个图像必须具有相同的shape(形状)。或者,可以将图像与一个标量相加,也可以将图像与一个通道数相同的一维数组相加。
OpenCV的相加操作与NumPy在超出数据类型范围时的处理方式不同。
>>> x = np.uint8([250])
>>> y = np.uint8([10])
>>> print( cv2.add(x,y) ) # 250+10 = 260 => 255
[[255]]
>>> print( x+y ) # 250+10 = 260 % 256 = 4
[4]
C++版本的API还支持mask等额外参数。
void cv::add (
InputArray src1,
InputArray src2,
OutputArray dst,
InputArray mask = noArray(),
int dtype = -1
)
2.2 图像混合
OpenCV通过 cv::addWeighted 函数提供了将两个图像混合在一起的方法。
dst=α⋅img1+β⋅img2+γ
img1 = cv2.imread('ml.png')
img2 = cv2.imread('opencv-logo.png')
dst = cv2.addWeighted(img1,0.7,img2,0.3,0)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

此外,通过cv2.seamlessClone函数还能实现更精细的图像局部融合效果。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













