回顾
- opencv-python 笔记(一):读取、写入、转换
准备
import cv2 as cv
# 说明见笔记(一)
def image_show(window_name, img, window_option=False):
"""图片展示"""
if window_option:
cv.namedWindow(window_name, cv.WINDOW_NORMAL) # 设定窗口尺寸可调节
cv.imshow(window_name, img)
while True:
key = cv.waitKey(0) & 0xFF # 监控键盘输入返回值
if key in (255, 27): # 关闭为-1 但经过 “& 0xFF” 后为 255, 27为 Esc
cv.destroyAllWindows()
break
elif key == ord("s"):
cv.imwrite(window_name + ".png", img)
cv.destroyAllWindows()
break
img = cv.imread("desert.png") # 读取图片
image_show("desert", img)
获取图片属性
In [0]: img.shape # 查看 img 的大小
Out[0]: (690, 690, 3)
In [1]: img.size # 像素总数
Out[1]: 1428300
In [2]: img.dtype # 图片数据类型
Out[2]: dtype('uint8')
Note: 灰度图像只会返回 长宽,没有通道,例如 (690, 690)。因此可用此方法检验图片为 RGB 还是 灰度
获取&修改像素
- 获取像素
In [3]: px = img[100, 100] # 取第 100 行索引,第 100 列索引的一维数组
In [4]: print(px) # 因 cv.imread() 默认 BGR 格式,因此分别三个像素值分别为 blue/green/red
Out[4]: [40 74 90]
- 修改像素
In [5]: img[100] = [255, 255, 255] # 第 100 行索引所有像素组都赋值白色像素 [255, 255, 255]
In [6]: img[:, 100]= [0, 255, 0] # 第 100 列索引所有像素组都赋值绿色像素 [0, 255, 0]
In [7]: image_show("desert1", img)
# 更好的获取和修改像素的方式
In [8]: img.item(10, 10, 2) # 读取第 10 行索引,第 10 列索引,第 2 索引位红色像素值
Out[8]: 58
In [9]: img.itemset((10, 10, 2), 100) # 修改为 100
In [10]: img.item(10, 10, 2)
Out[10]: 100
- ROI
# 将人的区域复制到另一个同样大小的区域
In [11]: img = cv.imread("desert.png")
In [12]: img[315: 405, 450:520] = img[330:420, 380:450]
In [13]: image_show("desert2", img)
- 切割&合并
img = cv.imread("desert.png")
b, g, r = cv.split(img) # 将 BGR 图像切割成 3 通道
img3 = cv.merge((r, g, b)) # 将 3 通道 合并成 RGB 图像
image_show("desert3", img3)
- 边框
import cv2 as cv
from matplotlib import pyplot as plt
BLUE = [255, 0, 0]
img1 = cv.imread('img_opencv.png')
image_show(img1)
# =============================================================================
# dst = cv.copyMakeBorder(src, dst, top, bottom, left, right, borderType, value)
# src : 输入图像
# dst : 输出图像
# top, bottom, left, right : 对应方向上的边框像素宽度
# borderType : 边框类型
# - cv.BORDER_CONSTANT
# 添加一个常数颜色值作为边界颜色。常数值在 value 参数中指定
# - cv.BORDER_REFLECT
# 镜面反射作为边框元素,排列方式例如:fedcba|abcdefgh|hgfedcb
# - cv.BORDER_REFLECT_101 or cv.BORDER_DEFAULT
# 与上一个略有不同, 排列方式例如:gfedcb|abcdefgh|gfedcba
# - cv.BORDER_REPLICATE
# 用最后一个元素作为边框,排列方式例如:aaaaaa|abcdefgh|hhhhhhh
# - cv.BORDER_WRAP
# 无法解释,排列方式例如:cdefgh|abcdefgh|abcdefg
# value : 若边框类型指定 cv.BORDER_CONSTANT 时的常数值
# =============================================================================
# 尝试使用各类边框类型,上下左右边框宽度皆为 10
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)
# 原图与 6 种边框类型图拼接成两行三列一起输出图片, 并去除 x、y 轴刻度线
plt.subplot(231), plt.imshow(img1), plt.title('ORIGINAL'), plt.xticks([]), plt.yticks([])
plt.subplot(232), plt.imshow(replicate), plt.title('REPLICATE'), plt.xticks([]), plt.yticks([])
plt.subplot(233), plt.imshow(reflect), plt.title('REFLECT'), plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(reflect101), plt.title('REFLECT_101'), plt.xticks([]), plt.yticks([])
plt.subplot(235), plt.imshow(wrap), plt.title('WRAP'), plt.xticks([]), plt.yticks([])
plt.subplot(236), plt.imshow(constant), plt.title('CONSTANT'), plt.xticks([]), plt.yticks([])
plt.show() # 具体效果还是看图吧
参考资料
OpenCV 官方文档 Basic Operations on Images