OpenCV从入门到精通|OpenCV的核心操作 —— 图像的基本操作+图像上的算术运算

OpenCV的核心操作 —— 图像的基本操作+图像上的算术运算 对图像的基本操作包括访问像素值并对其进行修改、访问像素属性、设置感兴趣区域和分割/合并图像通道,如果我们想用OpenCV写出更好的优化代码,熟练使用Numpy是至关重要的(Numpy是一个用于快速数组计算的优化库)
1. 图像的基本操作 1.1 访问像素值并修改它们
我们可以通过横纵坐标来访问像素值,对于BGR图像而言,它会返回一个由蓝绿红色值组成的数组(对应每种颜色的像素值),对于灰度图而言则只返回其对应的灰度
代码示例

>>> import numpy as np >>> import cv2 as cv >>> img = cv.imread('messi5.jpg') >>> px = img[100,100] >>> print( px ) [157 166 200] # 仅访问蓝色像素 >>> blue = img[100,100,0] >>> print( blue ) 157

当然我们也可以通过这种方法直接为某像素坐标赋值以达到修改像素值的目的
我们刚刚提到了Numpy是一个用于快速数组计算的优化库,而像上面的方法简单地访问每一个像素并对其作出修改时非常缓慢低效的,因此我们常常不用这种方法
但是如果我们需要选择一个区域内的像素,上面的方法还是很有用的,比如我们需要操作前4行后5列等,Numpy数组为我们提供了两个数组方法:arry.item() 和 arry.itemset(),这两个方法常用于访问单个元素,但是他们始终返回标量
# 访问 RED 值 >>> img.item(10,10,2) 59 # 修改 RED 值 >>> img.itemset((10,10,2),100) >>> img.item(10,10,2) 100

1.2 访问像素属性
图像属性包括行数,列数和通道数,图像数据类型,像素数等,我们就是要访问这些东西
图像的形状可通过 img.shape() 访问,它返回行,列和通道数的元组(如果图像是彩色的,当然也很有可能是单通道灰度图)
像素总数可通过访问 img.size()函数的返回值来获取
图像数据类型通过 img.dtype() 获得
注意: img.dtype() 在调试时非常重要,因为OpenCV-Python代码中的大量错误是由无效的数据类型引起的
1.3 设置图像感兴趣区域ROI
在实际操作处理中我们总是需要对一些特定的区域进行处理,比如我们需要对人的行为做一个分析处理,那我们就需要把人所在的区域及其1米内的区域做一个监测以便达到我们的目的而不是搜索整个图像,图像感兴趣区域ROI提高了图像处理的准确性和性能
代码实现把一块儿ROI复制在该图像的另一块儿区域
>>> ball = img[280:340, 330:390] >>> img[273:333, 100:160] = ball

1.4 分割和合并图像通道
有时我们需要对单色通道进行修改,此时便会用到图像通道的分割和合并,例如将BGR图像拆分为单通道
# 把BGR通道分别拆分在b,g,r b,g,r = cv.split(img) # 拆分 >>> img = cv.merge((b,g,r)) # 合并(注意这里以元组的形式传参)

获取和修改单通道的像素
>>> b = img [:, :, 0] >>> img [:, :, 2] = 0 # 注意这里元组中的0和2指的是通道索引

2. 图像上的算术运算 这一部分呈现的是图像上的几种算术运算:加法、减法和按位运算,关于这些运算我们首先要掌握:cv.add() 和 **cv.addWeighted()**这两个功能函数的使用
2.1 图像加法
图像的加法操作我们有两种方法来实现,第一种是直接使用OpenCV内置的cv.add()函数,第二种方式是使用Numpy库通过numpy操作,但无论是哪一种方法,加图和被加图都要具有相同的深度和类型,或者第二个图像可以直接是一个标量
注意:这里有一个很容易忽视的点,通过OpenCV和Numpy进行图像加法运算的区别在于OpenCV加法是饱和运算(比如像素大于255时就令其等于255),而Numpy加法是模运算(像素相加大于255时,这个值要对255进行取模运算)
>>> x = np.uint8([250]) >>> y = np.uint8([10]) >>> print( cv.add(x,y) ) # 250+10 = 260 => 255 [[255]] >>> print( x+y ) # 250+10 = 260 % 256 = 4 [4]

我们发现OpenCV功能将提供更好的结果
2.2 图像融合
图像融合本质上也是图像加法,但是它可以为用于加法的图片设置权重系数,使其具有融合或透明的效果
import cv2 as cv import numpy as npimg1 = cv.imread(r'E:\image\wqw.png') img2 = cv.imread(r'E:\image\qqq.png') dst = cv.addWeighted(img1, 0.9, img2, 0.3, 0) cv.imshow('dst', dst) cv.waitKey(0) cv.destroyAllWindows()

OpenCV从入门到精通|OpenCV的核心操作 —— 图像的基本操作+图像上的算术运算
文章图片

2.3 按位运算
按位运算包括按位AND、OR、NOT和XOR操作,它们在提取图像的任何部分、定义和处理非矩形 ROI 等方面非常有用
我们依旧通过一个例子来学习按位运算:将OpenCV的Logo放在一张图片上,但是它不是一个矩形,所以我们不能使用上面所说的图像感兴趣区域ROI来处理图像,这个时候按位操作就派上用场了
import numpy as np import cv2 from matplotlib import pyplot as plt# 加载两张图片 img1 = cv2.imread(r'E:\image\wqw.png') img2 = cv2.imread(r'E:\image\opencv.png') # 我想把logo放在左上角,所以我创建了ROI # logo left top rows, cols, channel = img2.shape roi = img1[0: rows, 0: cols]# 获得bg # mask of 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中logo的区域涂黑 img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)# 仅从logo图像中提取logo区域 img2_fg = cv2.bitwise_and(img2, img2, mask=mask)# 将logo放入ROI并修改主图像 dst = cv2.add(img1_bg, img2_fg) img1[0:rows, 0:cols] = dst cv2.imshow('res',img1) cv2.waitKey(0) cv2.destroyAllWindows()

emmm不知道为什么我的程序显示不出来抠图的效果,但是代码的思路应该没啥问题
首先要在主图中找到我们放置Logo的那个区域作为ROI,然后再对我们的Logo求其掩码和相反掩码,使ROI区域和Logo的掩码做与运算,即把ROI中要放置Logo的区域涂黑,下一步就是把我们的Logo区域通过掩码从原图中抠出来了,抠出来之后把抠出来的Logp和挖去Logo图像的ROI相加,就得到了最终结果,然后修改原图中的ROI即可
【OpenCV从入门到精通|OpenCV的核心操作 —— 图像的基本操作+图像上的算术运算】(注:文章内容参考OpenCV4.1中文官方文档)
如果文章对您有所帮助,记得一键三连支持一下哦

    推荐阅读