文章目录
认识Numpy.array
Python中提供了list容器,可以当作数组使用。但列表中的元素可以是任何对象,因此列表中保存的是对象的指针,这样一来,为了保存一个简单的列表[1,2,3]。就需要三个指针和三个整数对象。对于数值运算来说,这种结构显然不够高效。
Python虽然也提供了array模块,但其只支持一维数组,不支持多维数组,也没有各种运算函数。因而不适合数值运算。
而NumPy的出现弥补了这些不足。(——摘自张若愚的《Python科学计算》)
简单来说,Numpy是用来处理多维数组的,也可以理解为线性代数的矩阵,通常为列表嵌套列表或多个列表的形式,来看看Numpy.array。
import numpy as np
import cv2
# 生成一个随机灰度图
# 使用NumPy库生成一个随机的256x256的二维数组
image_gray = np.random.randint(0,256,size=[256,256],dtype=np.uint8)
cv2.imshow('image_gray', image_gray)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像的运算
加法运算
计算机一般使用八个比特位来表示灰度图像,定义矩阵类型为为八位无符号整型数时,范围为0-255。
cv2.add加法操作要求两个图片的长宽相同,通道数相同,或者第二个图是一个标量。
运算符+
两个图对应位置的元素相加,超出255的数字,会被截断,相当于% 256。
cv2.add()
两个图对应位置的元素相加,如果超过255,全部变成255。
import numpy as np
import cv2
# 定义两个随机的3*3矩阵,范围为0-255
img1 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
img2 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
print("img1=\n",img1)
print("img2=\n",img2)
print("img1 + img2=\n",img1+ img2)
print("------------")
print("cv2.add(img1,img2)=\n",cv2.add(img1,img2))
cv.addWeighted()
图像融合本质上也是图像加法,但是它可以为用于加法的图片设置权重系数,最后决定哪张图片占得比重更大。
一般格式:
cv2.add Weighted(image1, weight1, Image2, weight2, gammaValue)
参数:
- image1:第一个图像数组输入。
- weight 1:输入图像中第一个图像元素的权重。建议范围[0,1]之间,实质上是第一个图的每个元素乘权重。
- image2:第二个图像数组输入。
- weight 2:输入图像中第一个图像元素的权重。
- gammaValue:偏差,例如若相加的图片太亮,参数给-100,表示每个值都减100。
import numpy as np
import cv2
img1 = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-C.jpg")
print(img1.shape)
img2 = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-D.jpg")
print(img2.shape)
dst = cv2.addWeighted(img1, 0.4, img2, 0.6, 0)
cv2.imshow('img1',img1)
cv2.imshow('img2',img2)
cv2.imshow('dst', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
减法运算
操作要求两个图片的长宽相同,通道数相同。
运算符-
两个图对应位置的元素相减,小于0的数字,会被截断,相当于% 255 +1。
cv2.subtract()
两个图对应位置的元素相减,小于0的数字,全部变成0。
import numpy as np
import cv2
# 定义两个随机的3*3矩阵,范围为0-255
img1 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
img2 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
print("img1=\n",img1)
print("img2=\n",img2)
print("img1 - img2=\n",img1 - img2)
print("------------")
print("cv2.subtract(img1,img2)=\n",cv2.subtract(img1,img2))
乘法运算
矩阵乘法
np.dot()主要用于矩阵的乘法运算,其中包括:向量内积、多维矩阵乘法等等。乘法符合线性代数中矩阵的乘法规则.
向量内积
向量其实是一维的矩阵,两个向量进行内积运算时,需要保证两个向量包含的元素个数是相同的。
运算:每个元素对应相乘,再相加所得.
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7])
y = np.array([2, 3, 4, 5, 6, 7, 8])
result = np.dot(x, y)
print(result) # 结果:(1*2)+(2*3)+(3*4+(4*5)+(5*6)+(6*7)+(7*8) = 168
多维矩阵乘法
注意:
1.数组的运算是元素级的,数组相乘的结果是各对应元素的积组成的数组,而对于矩阵而言,需要求的是点积
2.两个矩阵(x, y)如果可以进行乘法运算,需要满足以下条件:
A为 m×n 阶矩阵,B为 n×p 阶矩阵,
则相乘的结果 result 为 m×p 阶矩阵。
运算:A的第一行乘B的第一列得到第一个元素…
arr5=np.array([[2,3],[4,5]])
arr6=np.array([[6,7],[8,9]])
print(np.dot(arr5,arr6))
[[36 41]
[64 73]]
矩阵点乘cv2.multiply()
运算:两对应元素相乘.
当结果大于255时,类似于cv2.add()函数,计算机会进行截断,取最大值255.
import numpy as np
import cv2
# 定义两个随机的3*3矩阵,范围为0-255
img1 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
img2 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
print("img1=\n",img1)
print("img2=\n",img2)
print("cv2.multiply(img1,img2)=\n",cv2.multiply(img1,img2))
除法运算
矩阵的点除运算cv2.divide()
当定义随机矩阵为八位整型数时,做除运算时会主动取整.
import numpy as np
import cv2
# 定义两个随机的3*3矩阵,范围为0-255
img1 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
img2 = np.random.randint(0,256,size=[3,3],dtype=np.uint8)
print("img1=\n",img1)
print("img2=\n",img2)
print("cv2.divide(img1,img2)=\n",cv2.divide(img1,img2))
逻辑运算
图像由像素组成,每个像素可以用十进制整数表示,十进制整数又可以转化为二进制数,所以图像也可以做位运算。
功能 | 函数 |
---|---|
按位与 | cv2.bitwise_and() |
按位或 | cv2.bitwise_or() |
按位取反 | cv2.bitwise_not() |
按位异或 | cv2.bitwise_xor() |
掩膜
当计算机处理图像时,有些内容需要处理,有些内容不需要处理。能够覆盖原始图像,仅暴露原始图像“感兴趣区域”(ROI)的模板图像就叫做掩模。
掩模(mask),也叫做掩码,在程序中用二值图像来表示:0值(纯黑)区域表示被遮盖的部分,255值(纯白)区域表示暴露的部分(某些场景下也会用0和1当作掩模的值),通过对二进制进行按位操作可获得感兴趣或待处理的区域.
按位与
按位与就是按照二进制位进行判断,如果同一位的数字都是1,则运算结果的相同位数字取1,否则取0。(记作有0为0)
OpenCV提供 bitwise_and() 方法来对图像做位与运算。
与运算:
格式:
dst = cv2.bitwise_and(src1, src2[, mask])
参数:
- dst: 运算之后的结果图像
- src1: 第一幅图像
- src2: 第二幅图像
- mask:(可选)掩模
与运算有两个特点✨:
- 如果某像素与纯白色像素做与运算,结果仍然是某像素的原值
- 如果某像素与纯黑色像素做与运算,结果为纯黑像素
结论or应用:
如果原图像与掩模进行与运算,原图像仅会保留掩模中白色区域所覆盖的内容,其他区域全部变成黑色。
import cv2
import numpy as np
img = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-C.jpg") # 原始图像
mask = np.zeros(img.shape, np.uint8) # 构造图像大小相等的掩模图像
mask[102:203, : , : ] = 255 # 横着的白色区域
mask[ : , 102:203, : ] = 255 # 竖着的白色区域
img_and = cv2.bitwise_and(img, mask) # 与运算
cv2.imshow("img", img) # 展示图像
cv2.imshow("mask", mask) # 展示掩模图像
cv2.imshow("img_and", img_and) # 展示与运算结果
cv2.waitKey() # 按下任何键盘按键后
cv2.destroyAllWindows() # 释放所有窗体
按位或
按位或就是按照二进制位进行判断,如果同一位的数字都是0,则运算结果的相同位数字取0,否则取1。(记作有1为1)
OpenCV提供 bitwise_or() 方法来对图像做位或运算。
或运算:
格式:
dst = cv2.bitwise_or(src1, src2[, mask])
参数:
- dst: 运算之后的结果图像
- src1: 第一幅图像
- src2: 第二幅图像
- mask:(可选)掩模
或运算有两个特点(同与运算相反)✨:
- 如果某像素与纯白色像素做或运算,结果为纯白色像素
- 如果某像素与纯黑色像素做或运算,结果仍然是某像素的原值
结论or应用:
如果原图像与掩模进行或运算,原图像仅会保留掩模中黑色区域所覆盖的内容,其他区域全部变成白色.
import cv2
import numpy as np
img = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-C.jpg") # 原始图像
mask = np.zeros(img.shape, np.uint8) # 构造图像大小相等的掩模图像
mask[102:203, : , : ] = 255 # 横着的白色区域
mask[ : , 102:203, : ] = 255 # 竖着的白色区域
img_or = cv2.bitwise_or(img, mask)
cv2.imshow("img", img) # 展示图像
cv2.imshow("mask", mask) # 展示掩模图像
cv2.imshow("img_or", img_or) # 展示与运算结果
cv2.waitKey() # 按下任何键盘按键后
cv2.destroyAllWindows() # 释放所有窗体
按位非
非运算是一种单目运算,仅需一个数字参与运算就可以得出结果。如果运算数某位上数字是0,则运算结果的相同位的数字就取1,如果这一位的数字是1,则运算结果的相同为的数字取0。注意OpenCV中的范围为0~255,1111 1111 表示255,255为0,0为255
OpenCV提供 bitwise_not() 方法来对图像做非运算。
非运算:
输入 | 输出 |
---|---|
0 | 1 |
1 | 0 |
格式:
dst = cv2.bitwise_not(src[, mask])
参数:
- dst: 运算之后的结果图像
- src: 图像
- mask:(可选)掩模
非运算的特点✨:
- 在进行非运算时,等同于用255-img(图像),
- 相片底片的颜色与图像的原色是正好相反的,即反色,又被称为补色,图像的反色与原色叠加后,可以变为纯白色。因此,为了得到一幅图像的底片效果,只需用255(纯白色)减去这幅图像中的每一个像素的BGR值,或者用非运算也可以.
import cv2
import numpy as np
img = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-C.jpg") # 原始图像
img_not = cv2.bitwise_not(img)
cv2.imshow("img_or", np.hstack((img,img_not)))
img_sub = 255-img
cv2.imshow("img_sub", np.hstack((img,img_sub)))
cv2.waitKey() # 按下任何键盘按键后
cv2.destroyAllWindows() # 释放所有窗体
按位异或
如果两个运算数同一位上的数字相同,则运算结果的相同位数字取0,否则取1。
OpenCV提供 bitwise_xot() 方法来对图像做异或运算。
异或运算:
格式:
dst = cv2.bitwise_xor(src1, src2[, mask])
参数:
- dst: 运算之后的结果图像
- src1: 第一幅图像
- src2: 第二幅图像
- mask:(可选)掩模
异或运算有两个特点:
- 如果某像素与纯白色像素做异或运算,结果为原像素的取反结果
- 如果某像素与纯黑色像素做异或运算,结果仍然是某像素的原值
- 异执行一次异或运算得到一个结果,再对这个结果执行第二次异或运算,则又会还原成最初的值。利用这个特点可以实现对图像内容的加密和解密。
结论or应用:
如果原图像与掩模进行异或运算,掩模白色区域所覆盖的内容呈现取反结果,黑色区域覆盖的内容保持不变。
import cv2
import numpy as np
img = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-C.jpg") # 原始图像
mask = np.zeros(img.shape, np.uint8) # 构造图像大小相等的掩模图像
mask[102:203, : , : ] = 255 # 横着的白色区域
mask[ : , 102:203, : ] = 255 # 竖着的白色区域
img_xor = cv2.bitwise_xor(img, mask)
cv2.imshow("img", img) # 展示图像
cv2.imshow("mask", mask) # 展示掩模图像
cv2.imshow("img_or", img_xor) # 展示与运算结果
cv2.waitKey() # 按下任何键盘按键后
cv2.destroyAllWindows() # 释放所有窗体
import cv2
import numpy as np
# 对图像进行加密、解密
# 利用random.randint()方法创建一个随机像素值图像作为密钥图像,
# 让密钥图像与原始图像做异或运算得出加密运算,再使用密钥图像对加密图像进行解密。
def encode(img, img_key): # 加密、解密方法
result = img = cv2.bitwise_xor(img, img_key) # 两图像做异或运算
return result
img = cv2.imread(r"C:\Users\lyx15\Pictures\OIP-C.jpg") # 原始图像
rows, colmns, channel = img.shape # 原图像的行数、列数和通道数
# 创建与图像大小相等的随机像素图像,作为密钥图像
img_key = np.random.randint(0, 256, (rows, colmns, 3), np.uint8)
cv2.imshow("1", img) # 展示图像
cv2.imshow("2", img_key) # 展示秘钥图像
result = encode(img, img_key) # 对图像进行加密
cv2.imshow("3", result) # 展示加密图像
result = encode(result, img_key) # 对图像进行解密
cv2.imshow("4", result) # 展示解密图像
cv2.waitKey() # 按下任何键盘按键后
cv2.destroyAllWindows() # 释放所有窗体
————————————————
参考文章:
博主「Daetalus」NumPy简明教程
博主「zhaoweiwei369」dot()
偏应用文章推荐:
博主「趴抖」 图像的基本操作+图像上的算术运算