Skip to content

Latest commit

 

History

History
275 lines (211 loc) · 10.2 KB

5.图像上的算术运算.md

File metadata and controls

275 lines (211 loc) · 10.2 KB

图像上的算术运算

1.图像加法

图像相加:一般用于对同一场景的多幅图像求平均,以便有效地降低(additive)随机噪声。

利用求平均的方法降低噪声信号提高信噪比的做法,只有当噪声可以用同一个独立分布的随机模型描述时才会有效。

作用:图像混合和降噪

使用函数 cv2.add() 将两幅图像进行加法运算,当然也可以直接使用 numpy,res=img1+img。两幅图像的大小,类型必须一致,或者第二个图像可以使一个简单的标量值。

cv2.add(src1, src2, mask) 

参数意义如下:

  • scr1:输入的第一幅图像
  • scr2:输入的第二幅图像
  • mask:可选,掩膜

补充:在有些图像处理的函数中有的参数里面会有mask参数,即此函数支持掩膜操作,首先何为掩膜以及有什么用,如下:

数字图像处理中的掩膜的概念是借鉴于PCB制版的过程,在半导体制造中,许多芯片工艺步骤采用光刻技术,用于这些步骤的图形“底片”称为掩膜(也称作“掩模”),其作用是:在硅片上选定的区域中对一个不透明的图形模板遮盖,继而下面的腐蚀或扩散将只影响选定的区域以外的区域。 图像掩膜与其类似,用选定的图像、图形或物体,对处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。 数字图像处理中,掩模为二维矩阵数组,有时也用多值图像,图像掩模主要用于: ①提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。 ②屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。 ③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。 ④特殊形状图像的制作。

区别:OpenCV 中的加法与 Numpy 的加法是有所不同的。OpenCV 的加法是一种饱和操作,而 Numpy 的加法是一种模操作。

例子:

x = np.uint8([250])
y = np.uint8([10])
print(x+y) # 250+10 = 260 % 256 = 4
print(cv2.add(x,y))  # 250+10 = 260 => 255
[4]
[[255]]

这种差别在你对两幅图像进行加法时会更加明显。OpenCV 的结果会更好一点。所以我们尽量使用 OpenCV 中的函数。

例子

import cv2
import matplotlib.pyplot as plt
import numpy as np

def img_show(name,img):
    """matplotlib图像显示函数
    name:字符串,图像标题
    img:numpy.ndarray,图像
    """
    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    plt.imshow(img,'gray')
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(name,fontproperties='FangSong',fontsize=12)
    

if __name__=="__main__":

    img1 = cv2.imread("art-art-exhibition-art-gallery-2110950.jpg")
    img2 = cv2.imread("art-exhibition-art-gallery-artwork-2110937.jpg")
    print(img1.shape)
    print(img2.shape)
    img3 = img1.copy() # 复制img1
    img3 = img3[:3339,:5008] # 裁剪图像使img3与img2图像大小一致
    print(img3.shape)
    img4 = img2+img3
    img5 = cv2.add(img2,img3)
    # 图像显示
    plt.figure(figsize=(12,8),dpi=80)
    plt.subplot(221)
    img_show('img2',img2)
    plt.subplot(222)
    img_show('img3',img3)
    plt.subplot(223)
    img_show('numpy中img2+img3',img4)
    plt.subplot(224)
    img_show('Opencv中img2+img3',img5)
(3351, 5026, 3)
(3339, 5008, 3)
(3339, 5008, 3)

2.图像混合

cv2.scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst)

可以按下面的公式对图片进行混合操作 $$d s t=\alpha \cdot src 1+ src 2$$

cv2.addWeighted(InputArray src1, double alpha, InputArray src2,double beta, double gamma,OutputArray dst, int dtype=-1)

这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。图像混合的计算公式如下: $$g(x)=(1-\alpha) f_{0}(x)+\alpha f_{1}(x)$$ 通过修改 ${α}$ 的值(0 → 1),可以实现非常酷的混合。现在我们把两幅图混合在一起。第一幅图的权重是 0.6,第二幅图的权重是 0.4。函数 cv2.addWeighted() 可以按下面的公式对图片进行混合操作。 $$ dst=\alpha \cdot src 1+\beta \cdot src2+\gamma $$ 这里$ {γ} $ 的取值为 0。

img1 = cv2.imread("fashion-fun-model-2191055.jpg")
img2 = cv2.imread("delicious-food-food-photography-2111987.jpg")
print(img1.shape)
print(img2.shape)
img3 = img1.copy()
img3 = img3[:4611,:3451]
print(img3.shape)

dst = cv2.addWeighted(img2,0.6,img3,0.4,0)

plt.figure(figsize=(8,20),dpi=80)
plt.subplot(131)
img_show('img2',img2)
plt.subplot(132)
img_show('img3',img3)
plt.subplot(133)
img_show('图像混合',dst)
(6000, 4000, 3)
(4611, 3451, 3)
(4611, 3451, 3)

3.图像相减

图像相减即在两幅图像之间对应像素做减法运算。图像相减可以检测出两幅图像的差异信息,因此这项技术在工业、医学、气象以及军事等领域中都有广泛的应用。 主要应用: (1)去除一幅图像中不需要的图案,如缓慢变化的背景阴影,周期性噪声等; (2)检测同一场景的两幅图像之间的变化 (3)运动检测

cv2.subtract(src1, src2, mask)

参数意义参见cv2.add()。

img1 = cv2.imread("lenaNoise.png")
img2 = cv2.imread("lena.jpg")

img3 = cv2.subtract(img1,img2)

plt.figure(figsize=(10,8),dpi=80)
plt.subplot(231)
img_show('lenaNoise',img1)
plt.subplot(232)
img_show('lena',img2)
plt.subplot(233)
img_show('图像相减',img3)

4.乘法运算

可以用来实现掩模处理,即屏蔽掉图象的某些部分。此外由于时域的卷积和相关运算与频域的乘积运算对应,因此乘法运算有时也被用来做为一种技巧来实现卷积或相关处理。

cv2.multiply(src1, src2)

5.除法运算

可用于校正成像设备的非线性影响,在特殊形态的图像(如断层扫描等医学图像)处理中用到。也可用于校正照明不足或者传感器的非线性影响造成的偏差。

cv2.divide(src1, src2)

6.按位运算

按位操作有:AND,OR,NOT,XOR 等。

  • bitwise_and是对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作,1&1=1,1&0=0,0&1=0,0&0=0
  • bitwise_or是对二进制数据进行“或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“或”操作,1|1=1,1|0=0,0|1=0,0|0=0
  • bitwise_xor是对二进制数据进行“异或”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“异或”操作,1^1=0,1^0=1,0^1=1,0^0=0
  • bitwise_not是对二进制数据进行“非”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作,~1=0,~0=1
cv2.bitwise_and(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray()) # dst = src1 & src2
cv2.bitwise_or(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray()) # dst = src1 | src2
cv2.bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray()) # dst = src1 ^ src2
cv2.bitwise_not(InputArray src, OutputArray dst,InputArray mask=noArray()) # dst = ~src

当我们提取图像的一部分,选择非矩形 ROI 时这些操作会很有用(下一章你就会明白)。下面的例子就是教给我们如何改变一幅图的特定区域。我想把 OpenCV 的标志放到另一幅图像上。如果我使用加法,颜色会改变,如果使用混合,会得到透明效果,但是我不想要透明。如果它是矩形我可以使用 ROI。但是它不是矩形。但是我们可以通过下面的按位运算实现:

img1 = cv2.imread("delicious-food-food-photography-2111987.jpg")
img2 = cv2.imread("opencv-logo.png")

# 创建一个ROI,并放在左上角
rows,cols,channels = img2.shape
roi = img1[0:rows,0:cols]

# 创建一个mask,并创建一个inverse mask
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret,mask = cv2.threshold(img2gray,175,255,cv2.THRESH_BINARY) #阈值处理,后面内容会详细介绍
mask_inv = cv2.bitwise_not(mask)

# logo的白色区域为感兴趣的区域ROI
# 取roi中与mask中不为零的值对应的像素的值,其他值为0
# 注意这里必须有mask=mask或者mask=mask_inv,其中mask=不能忽略
img1_bg = cv2.bitwise_and(roi,roi,mask=mask)
# 取roi中与mask_inv中不为零的值对应的像素的值,其他值为0。
# Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2,img2,mask=mask_inv)

# 将logo中的ROI放到主图像中
dst = cv2.add(img1_bg,img2_fg)
img3 = img1.copy()
img3[0:rows,0:cols] = dst

# 显示图像
plt.figure(figsize=(20,8),dpi=80)
plt.subplot(241)
img_show('img1',img1)
plt.subplot(242)
img_show('img2',img2)
plt.subplot(243)
img_show('roi',roi)
plt.subplot(244)
img_show('mask',mask)
plt.subplot(245)
img_show('mask_inv',mask_inv)
plt.subplot(246)
img_show('img2_fg',img1_bg)
plt.subplot(247)
img_show('img2_fg',img2_fg)
plt.subplot(248)
img_show('图像混合',img3)

7.其他算数运算

cv2.sqrt(InputArray src, OutputArray dst) # 计算每个矩阵元素的平方根
cv2.pow(InputArray src, double power, OutputArray dst) # src的power次幂
cv2.exp(InputArray src, OutputArray dst) # dst = e**src(**表示指数的意思)
cv2.log(InputArray src, OutputArray dst) # dst = log(abs(src))

更多详情请参考opencv官网。