1. 知识点
- 算术操作;
- 像素算术操作。
2. NumPy算术操作 和 OpenCV像素运算
2.1 加法
2.1.0 cv.add 函数
代码语言:javascript复制cv.add(src1,src2[,dst[,mask[,dtype]]])
2.1.1 代码测试
- 读取图片butterfly和lena;
- 获取两张图片[0,100]位置的像素值;
- 使用加法、np.add、cv.add进行算术操作。
import cv2 as cv
import numpy as np
def sums_add():
img1 = cv.imread('./images/butterfly.jpg')
img2 = cv.imread('./images/lena.jpg')
print('img1',img1[0,100])
print('img2',img2[0,100])
print('加法',img2[0,100] img1[0,100])
print('np.add',np.add(img2[0,100], img1[0,100]))
print('cv.add',cv.add(img2[0,100], img1[0,100]))
if __name__ == "__main__":
sums_add()
2.1.2 测试结果
2.2 减法
2.2.0 cv.subtract 函数
代码语言:javascript复制cv.subtract(src1,src2[,dst[,mask[,dtype]]])
2.2.1 代码测试
代码语言:javascript复制import cv2 as cv
import numpy as np
def sums_subtract():
img1 = cv.imread('./images/butterfly.jpg')
img2 = cv.imread('./images/lena.jpg')
print('img1',img1[0,100])
print('img2',img2[0,100])
print('减法',img2[0,100] - img1[0,100])
print('np.subtract',np.subtract(img2[0,100], img1[0,100]))
print('cv.subtract',cv.subtract(img2[0,100], img1[0,100]))
if __name__ == "__main__":
sums_subtract()
2.2.2 测试结果
2.3 乘法
2.3.0 cv.multiply函数
代码语言:javascript复制cv.multiply(src1,src2[,dst[,scale[,dtype]]])
2.3.1 代码测试
代码语言:javascript复制import cv2 as cv
import numpy as np
def sums_multiply():
img1 = cv.imread('./images/butterfly.jpg')
img2 = cv.imread('./images/lena.jpg')
print('img1',img1[0,100])
print('img2',img2[0,100])
print('乘法',img2[0,100] * img1[0,100])
print('np.multiply',np.multiply(img2[0,100], img1[0,100]))
print('cv.multiply',cv.multiply(img2[0,100], img1[0,100]))
if __name__ == "__main__":
sums_multiply()
2.3.2 测试结果
2.4 除法
2.4.0 cv.divide 函数
代码语言:javascript复制cv.divide(src1,src2[,dst[,scale[,dtype]]])
2.4.1 代码测试
代码语言:javascript复制import cv2 as cv
import numpy as np
def sums_divide():
img1 = cv.imread('./images/butterfly.jpg')
img2 = cv.imread('./images/lena.jpg')
print('img1',img1[0,100])
print('img2',img2[0,100])
print('除法',img2[0,100] * img1[0,100])
print('np.divide',np.divide(img2[0,100], img1[0,100]))
print('cv.divide',cv.divide(img2[0,100], img1[0,100]))
if __name__ == "__main__":
sums_divide()
2.4.2 测试结果
2.5 注意
注意:
- OpenCV加法和Numpy加法之间有区别。OpenCV加法是饱和运算,而Numpy加法是模运算。
- 保证不越界,cv.add、cv.subtract、cv.multiply、cv.divide取值范围 [0,255]。
3. 图像像素运算
3.1 实例
- 读取要图像像素运算的原图片 opencv-logo-white;
- 复制一个和原图形状一致的矩阵,数组元素以 0 来填充;由于图像像素运算两个图像必须是一样大小,所以直接复制一个形状一致的矩阵。
- 修改矩阵每个元素的颜色为 (110,0,250);
- 图像像素加法运算【cv.add】,由于保证不越界,因此相加大于255的值最后的值都是255,如果三通道都是255就是白色;
- 图像像素减法运算【cv.subtract】,由于保证不越界,因此相减小于0的值最后的值都是0,如果三通道都是0就是黑色;
- 图像像素乘法运算【cv.multiply】,由于保证不越界,因此相乘大于255的值最后的值都是255,如果三通道都是255就是白色,由于复制图片的颜色是(110,0,250),所以除黑色外的颜色就是(255,0,255);
- 图像像素除法运算【cv.divide】,由于保证不越界,同时元素的dtype=np.uint8,所以原图像除以(110,0,250),所有元素值都基本是(0,0,0)【黑色】。
import cv2 as cv
import numpy as np
def sums_image():
image1 = cv.imread("./images/opencv-logo-white.png")
image2 = np.zeros_like(image1)
image2[:] = (110,0,250)
cv.imshow('image1', image1)
cv.imshow('image2', image2)
# 图像像素加法运算
add_img = cv.add(image1, image2)
cv.imshow('add_img', add_img)
# 图像像素减法运算
subtract_img = cv.subtract(image1, image2)
cv.imshow('subtract_img', subtract_img)
# 图像像素乘法运算
multiply_img = cv.multiply(image1, image2)
cv.imshow('multiply_img', multiply_img)
# 图像像素除法运算
divide_img = cv.divide(image1, image2)
cv.imshow('divide_img', divide_img)
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == "__main__":
sums_image()
3.2 实例结果
4. NumPy 算术运算进行图像操作
4.1 实例
代码语言:javascript复制import cv2 as cv
import numpy as np
def numpy_image():
image1 = cv.imread("./images/opencv-logo-white.png")
image2 = np.zeros_like(image1)
image2[:] = (110,0,250)
cv.imshow('image1', image1)
cv.imshow('image2', image2)
# 图像像素加法运算
add_img = np.add(image1, image2)
cv.imshow('add_img', add_img)
# 图像像素减法运算
subtract_img = np.subtract(image1, image2)
cv.imshow('subtract_img', subtract_img)
# 图像像素乘法运算
multiply_img = np.multiply(image1, image2)
cv.imshow('multiply_img', multiply_img)
# 图像像素除法运算
divide_img = np.divide(image1, image2)
cv.imshow('divide_img', divide_img)
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == "__main__":
numpy_image()
4.2 实例结果
4.3 总结
- OpenCV和Numpy的加法运算不同,OpenCV的加法运算是饱和运算,而Numpy的加法运算是模运算。
- 饱和运算最大的特点是不讲究溢出位,执行结果与底层关系不大;假设变量的类型是8位无符号整型,那么最大数是255,如果在数学上相加的结果大于255,那么饱和运算返回结果就是255。
- 模运算考虑溢出位,执行结果需要向计算机底层原理——二进制的方面思考;假设变量的类型是8位无符号整型,那么最大数是255(对应二进制11111111),如果在数学上相加的结果大于255,那么就会发生溢出,仅仅保留容器范围内的二进制位。
- 由于饱和运算和模运算的不同,可以看到做相同操作后,两种运算得到的图像差距较大!
5. NumPy 数据类型
名称 | 说明 |
---|---|
bool_ | 布尔型数据类型(True 或者 False) |
int_ | 默认的整数类型(类似于 C 语言中的 long,int32 或 int64) |
intc | 与 C 的 int 类型一样,一般是 int32 或 int 64 |
intp | 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64) |
int8 | 字节(-128 to 127) |
int16 | 整数(-32768 to 32767) |
int32 | 整数(-2147483648 to 2147483647) |
int64 | 整数(-9223372036854775808 to 9223372036854775807) |
uint8 | 无符号整数(0 to 255) |
uint16 | 无符号整数(0 to 65535) |
uint32 | 无符号整数(0 to 4294967295) |
uint64 | 无符号整数(0 to 18446744073709551615) |
float_ | float64 类型的简写 |
float16 | 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位 |
float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位 |
float64 | 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位 |
complex_ | complex128 类型的简写,即 128 位复数 |
complex64 | 复数,表示双 32 位浮点数(实数部分和虚数部分) |
complex128 | 复数,表示双 64 位浮点数(实数部分和虚数部分) |
总结
- OpenCV加法和Numpy加法之间有区别。OpenCV加法是饱和运算,而Numpy加法是模运算。
- 饱和运算最大的特点是不讲究溢出位,执行结果与底层关系不大;假设变量的类型是8位无符号整型,那么最大数是255,如果在数学上相加的结果大于255,那么饱和运算返回结果就是255。
- 模运算考虑溢出位,执行结果需要向计算机底层原理——二进制的方面思考;假设变量的类型是8位无符号整型,那么最大数是255(对应二进制11111111),如果在数学上相加的结果大于255,那么就会发生溢出,仅仅保留容器范围内的二进制位。
- 保证不越界,cv.add、cv.subtract、cv.multiply、cv.divide取值范围 [0,255]。
- 由于图像像素运算两个图像必须是一样大小。
- 注意:OpenCV 元素的 dtype 是 np.uint8【无符号整数(0 to 255)】;Numpy 直接定义整数元素的 dtype 是 np.int32【整数(-2147483648 to 2147483647)】。