【OpenCV】【入门】3.NumPy与OpenCV

软件环境

本系列文章中所提到的接口及代码在以下环境中得到过验证:

Python == 3.8.5
opencv-contrib-python == 4.5.5.64
numpy == 1.23.2

前言

【OpenCV】【入门】3.NumPy与OpenCV_第1张图片

NumPy (Numerical Python) 是一个开源 Python 库,几乎用于所有科学和工程领域。它是在 Python 中处理数值数据的通用标准,也是科学 Python 和 PyData 生态系统的核心。 NumPy API 广泛用于 Pandas、SciPy、Matplotlib、scikit-learn、scikit-image 和大多数其他数据科学和科学 Python 包中。
NumPy 库包含多维数组和矩阵数据结构(您将在后面的部分中找到有关此的更多信息)。它提供了 ndarray,一个齐次的 n 维数组对象,以及对其进行有效操作的方法。 NumPy 可用于对数组执行各种数学运算。它为 Python 添加了强大的数据结构,以保证使用数组和矩阵进行高效计算,并且它提供了一个庞大的高级数学函数库,可对这些数组和矩阵进行操作。

以上是NumPy官网对其的介绍。使用Python运行OpenCV的程序时,OpenCV使用NumPy数组存储图像数据。基于NumPy可以很方便的执行基于数组的图像运算,比如图像的加法运算、加权加法运算和位运算等。本文对学习过程中遇到的一些常见操作做记录及分享。

数据类型

在Python中可以很方便的使用 type() 函数来查看一个变量或者是对象的类型。通过以下代码可以验证OpenCV的图像数据在Python中是使用NumPy数组来存储的:
【OpenCV】【入门】3.NumPy与OpenCV_第2张图片

测试图片翻前几篇笔记来获取或者是用自己的图片

import cv2

img = cv2.imread('test0.jpg')
print(type(img))

在这里插入图片描述
在该结论的基础上我们可以利用NumPy的API进一步查看图像数据的存储结构:

import cv2
import numpy as np

img = cv2.imread('test0.jpg')	# 读取图像

print(type(img))	# 获取图像的存储数据类型
print(img.shape)	# 获取图像数组的形状
print(np.dtype(img[0][0][0]))	# 打印图像数组的第一个元素的数据类型

在这里插入图片描述
根据上述的实验的结果,我们对OpenCV的数据存储方式有了进一步的了解。实际上NumPy支持的数据类型比Python内置的类型要更多,基本上可以和C语言的数据类型对应上,其中部分类型对应为Python内置的类型。

数据类型别名 说明
np.bool_ 布尔型数据类型(True 或者 False),存储为字节
np.int_ 默认的整数类型(类似于C语言中的long,int32或int64)
np.intc 与 C 的 int 类型一样,一般是 int32 或 int 64
np.int8 整数(-128 to 127)
np.int16 整数(-32768 to 32767)
np.int32 整数(-2147483648 to 2147483647)
np.int64 整数(-9223372036854775808 to 9223372036854775807)
np.uint8 无符号整数(0 to 255)
np.uint16 无符号整数(0 to 65535)
np.uint32 无符号整数(0 to 4294967295)
np.uint64 无符号整数(0 to 18446744073709551615)
np.float_ float64 类型的简写
np.float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
np.float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
np.float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
np.complex_ complex128 类型的简写,即 128 位复数
np.complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
np.complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)

图像运算

注意:进行运算的两张图片必须大小与类型一致(或者第二个图像可以是一个简单的标量值),否则会出现下列异常
在这里插入图片描述

1、加法运算

加法“+”运算符和cv2.add()函数可用于执行图像加法运算。区别:
(1) 两个像素相加 + 大于256,则会将其按256取模
(2) 两个像素相加 cv2.add() 大于256,则取255(白色)

import cv2

img1 = cv2.imread('test0.jpg')
img2 = cv2.imread('test1.png')

img3 = img1 + img2             # 两个像素相加 + 大于256,则会将其按256取模
img4 = cv2.add(img1, img2)     # 两个像素相加 cv2.add() 大于256,则取255(白色)

cv2.imshow('test0', img1)
cv2.imshow('test1', img2)

cv2.imshow('test0 + test1', img3)
cv2.imshow('test0 add test1', img4)

cv2.waitKey(0)
cv2.destroyAllWindows()

【OpenCV】【入门】3.NumPy与OpenCV_第3张图片

2、减法运算

import cv2

img1 = cv2.imread('test0.jpg')
img2 = cv2.imread('test1.png')

img3 = img1 - img2
img4 = cv2.subtract(img1, img2)

cv2.imshow('test0', img1)
cv2.imshow('test1', img2)

cv2.imshow('test0 - test1', img3)
cv2.imshow('test0 subtract test1', img4)

cv2.waitKey(0)
cv2.destroyAllWindows()

【OpenCV】【入门】3.NumPy与OpenCV_第4张图片

3、乘法&除法

乘法运算

multiply()遵循饱和运算规则,比如uint8类型的数据如果超过255会被截断到255。

img_ret = cv2.multiply(img,img2)
img_ret = img*img2

除法运算

当除数为0时,其计算结果记为0,如果被除数和除数都为0,结果也仍然为0,有0参与的除法运算都为0

img_ret = cv2.divide(img,img2)
img_ret = img/img2

4、位操作

OpenCV提供了与、或、取反和异或操作。
(1) cv2.bitwise_and()
(2) cv2.bitwise_or()
(3) cv2.bitwise_not()
(4) cv2.bitwise_xor()

import cv2
import numpy as np

white = (255,255,255)

rectangle = np.zeros((300,300,3),dtype='uint8')
cv2.rectangle(rectangle, (25,25), (275,275), white, -1)

circle = np.zeros((300,300,3), dtype='uint8')
cv2.circle(circle, (150,150), 150, white, -1)

cv2.imshow('Circle', circle)
cv2.imshow('Rectangle', rectangle)


# AND,与操作,有黑就变黑
image1 = cv2.bitwise_and(rectangle, circle)
# OR,或操作,有白就变白
image2 = cv2.bitwise_or(rectangle, circle)
# NOT, 非操作,颜色取反
image3 = cv2.bitwise_not(circle)
# XOR,异或操作,黑白变白,黑黑和白白变黑
image4 = cv2.bitwise_xor(rectangle, circle)

cv2.imshow('and', image1)
cv2.imshow('or', image2)
cv2.imshow('not', image3)
cv2.imshow('xor', image4)

cv2.waitKey(0)
cv2.destroyAllWindows()

【OpenCV】【入门】3.NumPy与OpenCV_第5张图片

像素操作

图像的像素级操作包括读某个或某些像素值、以及写像素值。因为在OpenCV-Python中图像是以numpy数组形式表示的,所以可以使用下标索引的方式来访问像素。

1、NumPy的数组的访问方式

在做像素操作前需要先搞清楚下标索引的方法,下面以一个宽高为16×10的灰度图(单通道)为例:
【OpenCV】【入门】3.NumPy与OpenCV_第6张图片
在图片中x轴方向的大小为0 ~ 15,y轴方向的大小为0 ~ 9且是向下的,我们通常描述一个二维空间的位置是以(x,y)的坐标形式表示,比如图中a点坐标为(x,y)=(9,1),图中b点坐标为(x,y)=(2,7),但是在numpy中如果用下标方法表示时,比如a点并不是表示成img[9,1],而是第0个参数为行数,第1个参数为列数,所以a点应该表示成img[1,9],同样b点则是以img[7,2]表示的。
下面用代码验证下,先创建一个10行16列的二维数组:

import numpy as np 
import cv2

img = np.arange(0, 160, step=1,dtype=np.uint8)
img = img.reshape(10,16)
print('img.shape',img.shape)
print(img)

【OpenCV】【入门】3.NumPy与OpenCV_第7张图片

接下来访问a点(x,y)=(9,1)和b点(x,y)=(2,7),读出这2个位置的值:

print('a点,img[1,9]:',img[1,9])
print('b点,img[7,2]:',img[7,2])

结果:

a点,img[1,9]: 25
b点,img[7,2]: 114

2、读取&修改像素值

【OpenCV】【入门】3.NumPy与OpenCV_第8张图片
使用系统自带的画图板可以取到鼠标所指的像素坐标。上图中鼠标所在位置为x=156,y=121,我们可以通过图像的索引img[121,156],img[121,156]获取到该像素的值,验证下是否和观察的一致:

import cv2

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

pixel = img[121, 156]
print('img[121,156]:', pixel)

运行结果(显示的顺序为BGR色彩空间):
在这里插入图片描述
与画图板的拾色器取到的数据一致:
【OpenCV】【入门】3.NumPy与OpenCV_第9张图片

3、切片、截取部分区域

image = image[a: b, c: d]

其中
a: 左上角距离顶部
b: 左下角距离顶部
c: 左上角距离左边距离
d: 右上角距离左边距离

即矩形区域左上角点的坐标及右下角点的坐标,示意图如下:
【OpenCV】【入门】3.NumPy与OpenCV_第10张图片

参考

https://numpy.org/doc/stable/user/absolute_beginners.html
https://blog.csdn.net/weixin_43843069/article/details/121745292
http://www.juzicode.com/opencv-python-pixel-operation/

你可能感兴趣的:(教程,知识分享,opencv,numpy,python)