图像基本操作
访问和修改像素值
import numpy as np
import cv2
img = cv2.imread('c:/Users/HP/Downloads/basketball.png')
h,w,c = img.shape
#图像大小
print(h,w,c)
### 841 1494 3
# 通过行和列坐标访问像素值
img[100,100]
### 231
### array([231, 140, 146], dtype=uint8)
# 通过行和列坐标访问像素值
img[100,100]
### array([231, 140, 146], dtype=uint8)
# # 仅访问蓝色通道的像素
blue = img[100,100,0]
print(blue)
### 231
# 修改颜色
img[100,100] = [255,255,255]
print(img[100,100])
### [255 255 255]
Numpy 访问每个像素值并修改其值非常缓慢,
更好的访问和编辑像素的方法:
#访问 红色通道 的值
img.item(10,10,2)
### 131
#修改 红色通道 的值
img.itemset((10,10,2),100)
img.item(10,10,2)
### 100
访问图像属性
print(img.shape)
# 如果图像是灰度图像,则返回的元组仅包含行数和列数,因此它是检查加载的图像是灰度图还是彩色图的一种很好的方法
### (841, 1494, 3)
print(img.size) # 总像素数
### 3769362
print(img.dtype) # 图像数据类型
### uint8
图像中的感兴趣区域
from matplotlib import pyplot as plt
plt.imshow(img)
from matplotlib import pyplot as plt
ball = img[450:600,450:650]
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(ball)
拆分和合并图像通道
b,g,r = cv2.split(img) # 分割为单通道
img = cv2.merge((b,g,r)) # 合并
b = img[:,:,0] # 或者使用numpy.array的切片方法
img[:,:,2] = 0 # 要将所有红色像素设置为零,则无需先拆分通道;Numpy 索引更快
## warning:CV.spilt()是一项代价高昂的操作(就时间而言)。所以只在你需要时再这样做,否则使用 Numpy 索引。
制作图像边界(填充)
import cv2 as CV
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = img
replicate = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_REPLICATE)
reflect = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_REFLECT)
reflect101 = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_REFLECT_101)
wrap = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_WRAP)
constant= CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_CONSTANT,value=BLUE)
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()
图像的算术运算
图像加法
# 可以通过 cv.add()或简单地通过 numpy 操作将两个图像相加,res = img1 + img2;
# 两个图像应该具有相同的深度和类型,或者第二个图像可以是像素值,比如(255,255,255),白色值。
img1 = cv2.imread('c:/Users/HP/Downloads/basketball.png')
img2 = cv2.imread('c:/Users/HP/Downloads/jump.png')
res = img1 + img2
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(res)
图像混合
也是加法,但两幅图像的权重不同,就会给人一种混合或者透明的感觉。图像混合的计算公式如下:
g(x) = (1−α)f0(x) + αf1(x)
函数cv2.addWeighted()可以按下面的公式对图片进行混合操作:
dst = α⋅img1 + β⋅img2 + γ
dst = cv2.addWeighted(img1,0.7, img2,0.3, 0)
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(dst)
按位操作
这包括按位 AND,OR,NOT 和 XOR 运算。它们在提取图像的某一部分(我们将在后面的章节中看到)、定义和使用非矩形 ROI 等方面非常有用。示例:
假如我想加一个OpenCV的 logo在一个图像上,如果只是简单的将两张图像想加,则会改变叠加处的颜色;
如果进行上面所说的混叠操作,则会得到一个有透明效应的结果,但我希望得到一个不透明的logo;
如果logo是一个矩形logo,那可以用上节所讲的ROI来做;
但是OpenCV的logo是不规则形状的,所以用下面的bitwise操作来进行:
#加载两张图片
img1 = cv2.imread('c:/Users/HP/Downloads/basketball.png')
img2 = cv2.imread('c:/Users/HP/Downloads/opencv_logo.png')
#我想在左上角放置一个logo,所以我创建了一个 ROI,并且这个ROI的宽和高为我想放置的logo的宽和高
rows,cols,channels = img2.shape
roi = img1 [0:rows,0:cols]
#现在创建一个logo的掩码,通过对logo图像进行阈值,并对阈值结果并创建其反转掩码
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret,mask = cv2.threshold(img2gray,10,255,cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
#现在使 ROI 中的徽标区域变黑
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(img1_bg)
#仅从徽标图像中获取徽标区域。
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
#在 ROI 中放置徽标并修改主图像
dst2 = cv2.add(img1_bg,img2_fg)
res = img1
res [0:rows,0:cols] = dst2
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(res)