当前位置: 首页 > news >正文

小白学OpenCV系列3-图像算数运算

我们之前讲过,图像读取到计算机之后就是一个矩阵,那么它就可以做各种各样的运算,今天就先来讲讲最基础的加减乘除以及位运算,它们是其他高阶运算的基础。

加法

有两种方式可以进行常规的加法运算,一种是通过加法运算符“+”,一种是通过cv2.add()函数。但是由于灰度图的像素值范围通常是[0, 255],如果求和,得到的数值很可能会超过255,因此对超过255的数值,两者的处理方式是不一样的。

加号运算符

使用加法运算符的时候,超过255的数值会对256取模,以便让数值范围重新回到[0,255],我们可以通过下列例子来演示该过程。

import cv2  img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:", img1)  
img2 = cv2.imread("lena.bmp", flags=0)  
print("img2", img2)  
print("img1+img2:", img1 + img2)

img1和img2都是下图的像素值矩阵。
在这里插入图片描述

最终计算的结果如下图所示:
在这里插入图片描述
可以看到图中第一个红框和第二个红框的数值加起来就超过了255,可是最后计算的结果却是68,实际上就是(162+162)mod 256 = 68。

cv2.add函数

使用add函数的时候,对于超过255的数值会截止到255,以便让数值范围仍然在[0,255],我们将上面的代码稍微改一改。

import cv2  img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:\n", img1)  
img2 = cv2.imread("lena.bmp", flags=0)  
print("img2:\n", img2)  
print("cv2.add(img1,img2):\n", cv2.add(img1, img2))

计算的结果如下所示:
在这里插入图片描述
可以看到图中第一个红框和第二个红框的数值加起来就超过了255,可是最后计算的结果却被截止到了255。

加权和

除了上述两种常规加法外,实际上还可以计算图像的加权和,就是在计算两幅图像的像素值之和时,将每幅图像的权重考虑进来,如下式所示:
dst=saturate(src1∗α+scr2∗β+γ) dst=saturate(src1 * \alpha + scr2 * \beta + \gamma) dst=saturate(src1α+scr2β+γ)
最后计算出来的值如果超过了255,同样地会被截止到255,而且src1和src2的大小和类型必须相同才行。我们还是使用上述图片来演示该过程。

import cv2 img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:\n", img1)  
img2 = cv2.imread("lena.bmp", flags=0)  
print("img2:\n", img2)  
print("cv2.addWeighted(img1,2,img2,3,4):\n", cv2.addWeighted(img1, 2, img2, 3, 4))

在这里插入图片描述
我们可以简单地计算下上述的数值是否满足加权求和的规律:45 * 2 + 45 * 3 + 4 = 229,说明加权成功了,而计算后超过255的数值就会被重置为255。

减法

和加法一样,同样有两种方式可以进行常规的减法运算,一种是通过减法运算符“-”,一种是通过cv2.subtract()函数。但是由于灰度图的像素值范围通常是[0, 255],如果求差,得到的数值很可能会小于0,因此对小于0的数值,两者的处理方式也是不一样的。

减法运算符

使用减法运算符的时候,小于0的数值会对256取模,以便让数值范围重新回到[0,255],我们可以通过下列例子来演示该过程。

import cv2  
import numpy as np  img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:\n", img1) 
# ones_like的作用为创建一个形状和img1一样的单位矩阵 
img2 = np.ones_like(img1) * 100  
print("img2:\n", img2)  
print("img1-img2:\n", img1 - img2)

最终计算的结果如下图所示,从中可以看到大于0的数值仍然保持原样,而小于0的数值则对256取模了。
在这里插入图片描述

cv2.subtract函数

使用subtract函数的时候,对于小于0的数值会截止到0,以便让数值范围仍然在[0,255],我们将上面的代码稍微改一改。

import cv2  
import numpy as np  img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:\n", img1)  
# ones_like的作用为创建一个形状和img1一样的单位矩阵 
img2 = np.ones_like(img1) * 100  
print("img2:\n", img2)  
print("cv2.subtract(img1, img2):\n", cv2.subtract(img1, img2))

最终计算的结果如下所示:
在这里插入图片描述

乘法

和加减法一样,同样有两种方式可以进行常规的乘法运算,一种是通过乘法运算符“*”,一种是通过cv2.multiply()函数。和加减法一样,前者对超过255的数值会对256取模,后者则会截止到255。
我们可以使用下列代码来感受二者的区别。

import cv2  
import numpy as np  img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:\n", img1)  
# ones_like的作用为创建一个形状和img1一样的单位矩阵 
img2 = np.ones_like(img1) * 2  
print("img2:\n", img2)  
print("img1 * img2:\n", img1 * img2)  
print("cv2.multiply(img1, img2):\n", cv2.multiply(img1, img2))

最终计算的结果如下所示:
在这里插入图片描述

除法

和加减乘法一样,同样有两种方式可以进行常规的除法运算,一种是通过除法运算符“/”,一种是通过cv2.divide()函数。但是前者计算出来的结果会存在小数,而后者则会做相应处理,将结果四舍五入为整数。另外如果除数为0的时候,后者也会将结果置为0,因此一般情况下使用后者会更好一些。我们可以使用下列代码来感受二者的区别。

import cv2  
import numpy as np  img1 = cv2.imread("lena.bmp", flags=0)  
print("img1:\n", img1)  
# ones_like的作用为创建一个形状和img1一样的单位矩阵 
img2 = np.ones_like(img1) * 2  
# zeros_like的作用为创建一个形状和img1一样的零矩阵 
# img2 = np.zeros_like(img1)  
print("img2:\n", img2)  
print("img1 / img2:\n", img1 / img2)  
print("cv2.divide(img1, img2):\n", cv2.divide(img1, img2))

在这里插入图片描述

位运算

在OpenCV中,常见的位运算有以下四种:

  • cv2.bitwise_and:按位与,当两个输入位都是1时,输出才是1,否则为0
  • cv2.bitwise_or:按位或,只要有一个输入位是1,输出就是1,只有当两个都是0时,输出才是0。
  • cv2.bitwise_xor:按位异或,当两个输入位不同时,输出是1,当相同时,输出是0。
  • cv2.bitwise_not:按位取反,如果输入是1,输出是0,如果输入是0,输出是1。

下面我们以按位与为例,来演示一下位运算的用处。假如我们只想要最开始例图中的头部画面,那么就可以利用按位与的性质来实现,其代码如下所示:

import cv2  
import numpy as np  # 读取图片  
img1 = cv2.imread("lena.bmp", flags=0)  
# 建立与之进行按位与的模板  
mask = np.zeros(img1.shape, dtype=np.uint8)  
mask[50: 200, 100: 200] = 255  
mask[50: 250, 50: 100] = 255  
masked_img1 = cv2.bitwise_and(img1, mask)  cv2.imshow("mask_lena", masked_img1)  
cv2.waitKey()  
cv2.destroyAllWindows()

最终我们可以得到如下结果:
在这里插入图片描述

总结

本篇博客主要学习了OpenCV中的算数运算操作,对于加减乘除操作而言,总体规律就是:如果使用运算符号操作,结果需要对256取模,若使用函数操作,结果则被0和255截断。对于位运算而言,很多时候可以用来构建掩膜,以找到我们感兴趣的区域。


文章转载自:

http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://00000000.wckrL.cn
http://www.dtcms.com/a/367176.html

相关文章:

  • jQuery 入门:一份献给初学者的完全指南
  • 怎么做到这一点:让 Agent 可以像人类一样 边听边想、边说,而不是“等一句话 → 一次性返回”
  • 风险慎投!IF 狂跌10分,国人发文超80%,这本SCI的1区TOP还能撑多久?
  • 剧本杀APP系统开发:引领娱乐行业新潮流的科技力量
  • Linux2.6内核进程O(1)调度队列
  • 【OpenHarmony文件管理子系统】文件访问接口mod_fileio解析
  • 【全息投影】全息风扇的未来,超薄化、智能化与交互化
  • “SOD-923”封装系列ESD静电二极管 DC0521D9 ESD9X5.0S
  • 架构-亿级流量性能调优实践
  • 开讲了,全栈经验之谈系列:写给进阶中的小伙伴
  • STM32F103C8T6开发板入门学习——寄存器和库函数介绍
  • 0904网络设备配置与管理第二次授课讲义
  • [科普] 卫星导航系统的授时原理与精度分析
  • Linux tail 命令使用说明
  • 机器学习基础-day04-数学方法实现线性回归
  • 如何在MacOS上卸载并且重新安装Homebrew
  • 基于 GEE 计算温度植被干旱指数 TVDI 并可视化分析
  • LED电路图判断灯在低电平时亮、高电平时灭
  • SpringBoot实现国际化(多语言)配置
  • 【代码随想录算法训练营——Day2】数组——209.长度最小的子数组、59.螺旋矩阵II、区间和、开发商购买土地
  • LinuxC++项目开发日志——高并发内存池(1-定长内存池)
  • 【提示词技巧】顺序位置对效果的影响
  • QT-菜单栏、工具栏和状态栏
  • Qt QJsonObject
  • 我辞职了,接替我的人私底下找我,我直接把她删了。明明有个交接群,她是觉得在群里提问会显得自己不够专业吗? 网友:凭啥惯着
  • Docker(②创造nginx容器)
  • 2025年B端产品经理进阶指南:掌握这些计算机专业技能,决胜职场!
  • 2025职场进阶:B端产品经理必备的计算机专业技能精要
  • 2025 年职场必看:B 端产品经理优化产品的计算机专业技能全解析​
  • 拉格朗日多项式