OpenCV:03图像的算数运算

文章目录

  • 图像的算数运算
    • 加法运算
    • 减法运算
    • 乘法运算
    • 除法运算
  • 图片的融合
  • OpenCV的逻辑运算(位运算)
    • 与运算`&`
    • 或运算`|`
    • 非运算`~`
    • 异或运算`~`
  • 作业
    • Version 1
    • Version 2
      • **1.`引入图片`:**
      • **2.`设计一个logo图片`:**
      • **3.`规划一下你的logo需要放在哪块位置,在添加的位置变成黑色`:**
      • **4.`利用add方法,把logo和图片叠加在一起`:**
      • **`整段代码:`**

图像的算数运算

加法运算

关键API:cv2.add(img)

add的规则就是两个图对应的元素相加,如果超过255(像素点的大小0-255),则全部变成255

# 加法运算
import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')


# cv2.add()方法要求两个图的长、宽、通道数都相等,否则会报错 
    # add的规则就是两个图对应的元素相加,如果超过255(像素点的大小0-255),则全部变成255
print(cat.shape)
print(dog.shape)  # 检查两图的长宽及通道数

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式
print(new_dog.shape)

# 将两幅图片相加
new_img = cv2.add(cat,new_dog)
cv2.imshow('new_img',new_img)

cv2.waitKey()
cv2.destroyAllWindows()

图片还可以和单个数字进行运算,如dog += 100
每个和100进行加法运算,超过255的数字,会被截断,相当于%256

# 加法运算
import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')


# cv2.add()方法要求两个图的长、宽、通道数都相等,否则会报错 
    # add的规则就是两个图对应的元素相加,如果超过255(像素点的大小0-255),则全部变成255
# print(cat.shape)
# print(dog.shape)  # 检查两图的长宽及通道数

# 图片还可以和单个数字进行运算
    # 每个和100进行加法运算,超出255的数字,会被截断,相当于%256
dog += 100
print(dog[:3,:3])
    
cv2.waitKey()
cv2.destroyAllWindows()

减法运算

关键API:cv2.subtract(img1,img2)

subtract的规则就是两个图对应的元素相减,如果小于0(像素点的大小0-255),则全部变成0

# 减法运算
import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')


# cv2.subtract()方法要求两个图的长、宽、通道数都相等,否则会报错 
    # subtract的规则就是两个图对应的元素相减,如果小于0(像素点的大小0-255),则全部变成0
print(cat.shape)
print(dog.shape)  # 检查两图的长宽及通道数

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式
print(new_dog.shape)

# 将两幅图片相减 ——> 对应图片的元素(像素)相减,减完小于0,则全部为0
new_img = cv2.subtract(cat,new_dog)
cv2.imshow('new_img',new_img)

cv2.waitKey()
cv2.destroyAllWindows()

乘法运算

关键API:cv2.multiply(img1,img2)

乘法的规则和加法一样:两个图对应的元素相乘,如果超过255(像素点的大小0-255),则全部变成255

# 乘法运算
import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')


# cv2.multiply()方法要求两个图的长、宽、通道数都相等,否则会报错 
    # multiply的规则就是两个图对应的元素相乘,如果超过255(像素点的大小0-255),则全部变成255
print(cat.shape)
print(dog.shape)  # 检查两图的长宽及通道数

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式
print(new_dog.shape)

# 将两幅图片相乘 multiply——> 对应图片的元素(像素)相减,减完小于0,则全部为0
new_img = cv2.multiply(cat,new_dog)
cv2.imshow('new_img',new_img)

cv2.waitKey()
cv2.destroyAllWindows()

除法运算

关键API:cv2.divide(img1,img2

除法的规则和减法一样:两个图对应的元素相除,如果小于0(像素点的大小0-255),则全部变成0

# 加法运算
import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')


# cv2.divide()方法要求两个图的长、宽、通道数都相等,否则会报错 
    # divide的规则就是两个图对应的元素相除,如果小于0(像素点的大小0-255),则全部变成0
print(cat.shape)
print(dog.shape)  # 检查两图的长宽及通道数

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式
print(new_dog.shape)

# 将两幅图片相除 divide——> 对应图片的元素(像素)相减,减完小于0,则全部为0
new_img = cv2.divide(cat,new_dog)
cv2.imshow('new_img',new_img)

cv2.waitKey()
cv2.destroyAllWindows()

图片的融合

关键API:addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
其中:

  • src1:第一幅图片
  • alpha:第一幅图片的权重
  • scr2:第二幅图片
  • beta:第二幅图片的权重
  • gamma:偏差
# 图像的融合
# 不是简单的加法,相当于拿图片进行了线性运算:new_img = img1 * w1 +img2 * w2 + bias(w1、w1为权重,bias为偏差)
    #我们可以通过控制权重,来调整最终融合之后的图片里面哪一张图片所占比重更大
        #比如猫和狗融合的图片,我想让狗显示的更清晰,那我就可以加大狗的比重,减少猫的比重
        
# 关键API:addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) ——> src1:第一幅图片 alpha:第一幅图片的权重 scr2:第二幅图片 beta:第二幅图片的权重 gamma:偏差

import cv2
import numpy as np

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式

new_img = cv2.addWeighted(cat,0.3,new_dog,1,0) # 如果想把图片调暗,那么可以把gamma改成负数

cv2.imshow('new_img',new_img)

cv2.waitKey()
cv2.destroyAllWindows()


OpenCV的逻辑运算(位运算)

与运算&

204 & 213 = 196,先将204和213转化为二进制,再把结果的二进制转化为十进制,即为196

两个数与运算后会变小,如204 & 213 = 196 ; 150 & 140 = 132

# 与运算
import cv2
import numpy as np

# 创建窗口
cv2.namedWindow('new_img',cv2.WINDOW_NORMAL)

# 更改窗口大小—>在窗口属性为‘WINDOW_AUTOSIZE’自动设置时无效果
cv2.resizeWindow('new_img',800,600) # resizeWindow(winname, width, height)

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式

# 与操作 ——> 要求两幅图形状相同
cat_and = cv2.bitwise_and(cat,new_dog)

# 观察像素变换结果
print(cat[:2,:2])
print('---------------------')
print(dog[:2,:2])
print('---------------------')
print(cat_and[:2,:2])

# 展示图片
cv2.imshow('new_img',np.hstack((cat,cat_and)))

cv2.waitKey()
cv2.destroyAllWindows()

结果:

cat:
[[[195 216 244]
  [194 215 243]]

 [[194 215 243]
  [193 214 242]]]
---------------------
dog:
[[[ 84 102 125]
  [ 79 100 122]]

 [[ 85 102 123]
  [ 84 103 124]]]
---------------------
cat_and
[[[ 64  64 116]
  [ 66  68 114]]

 [[ 64  70 115]
  [ 64  70 112]]]


或运算|

两个数进行或运算

# 或运算
import cv2
import numpy as np

# 创建窗口
cv2.namedWindow('new_img',cv2.WINDOW_NORMAL)

# 更改窗口大小—>在窗口属性为‘WINDOW_AUTOSIZE’自动设置时无效果
cv2.resizeWindow('new_img',800,600) # resizeWindow(winname, width, height)

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式

# 或操作 ——> 要求两幅图形状相同
cat_or = cv2.bitwise_or(cat,new_dog)

# 观察像素变换结果
print(cat[:2,:2])
print('---------------------')
print(dog[:2,:2])
print('---------------------')
print(cat_or[:2,:2])

# 展示图片
cv2.imshow('new_img',np.hstack((cat,new_dog,cat_and)))

cv2.waitKey()
cv2.destroyAllWindows()

结果:

[[[195 216 244]
  [194 215 243]]

 [[194 215 243]
  [193 214 242]]]
---------------------
[[[ 84 102 125]
  [ 79 100 122]]

 [[ 85 102 123]
  [ 84 103 124]]]
---------------------
[[[215 254 253]
  [207 247 251]]

 [[215 247 251]
  [213 247 254]]]


非运算~

如~255 = 0, ~195 = 60,在opencv中取非就是相当于用255减去取非的数

# 非运算
import cv2
import numpy as np

# 创建窗口
cv2.namedWindow('new_img',cv2.WINDOW_NORMAL)

# 更改窗口大小—>在窗口属性为‘WINDOW_AUTOSIZE’自动设置时无效果
cv2.resizeWindow('new_img',800,600) # resizeWindow(winname, width, height)

# 读取图片
cat = cv2.imread('./cat.jpeg')

# 非操作 ——> 相当于255 - cat 并且会返回运算的结果
cat_not = cv2.bitwise_not(cat)

# 观察像素变换结果
print(cat[:2,:2])
print('---------------------')
print(cat_not[:2,:2])

# 展示图片
cv2.imshow('new_img',np.hstack((cat,cat_not)))

cv2.waitKey()
cv2.destroyAllWindows()

结果:

cat:
[[[195 216 244]
  [194 215 243]]

 [[194 215 243]
  [193 214 242]]]
---------------------
cat_not:
[[[60 39 11]
  [61 40 12]]

 [[61 40 12]
  [62 41 13]]]


异或运算~

# 异或运算
import cv2
import numpy as np

# 创建窗口
cv2.namedWindow('new_img',cv2.WINDOW_NORMAL)

# 更改窗口大小—>在窗口属性为‘WINDOW_AUTOSIZE’自动设置时无效果
cv2.resizeWindow('new_img',800,600) # resizeWindow(winname, width, height)

# 读取图片
cat = cv2.imread('./cat.jpeg')
dog = cv2.imread('./dog.jpeg')

# 由于dog的大小比cat大,因此我们使用numpy切片的方法把dog切成和cat一样的大小
new_dog = dog[0:1078,0:1095] # numpy的切片方式

# 或操作 ——> 要求两幅图形状相同
cat_xor = cv2.bitwise_xor(cat,new_dog)

# 观察像素变换结果
print(cat[:2,:2])
print('---------------------')
print(dog[:2,:2])
print('---------------------')
print(cat_xor[:2,:2])

# 展示图片
cv2.imshow('new_img',np.hstack((cat,new_dog,cat_xor)))

cv2.waitKey()
cv2.destroyAllWindows()

结果:

[[[195 216 244]
  [194 215 243]]

 [[194 215 243]
  [193 214 242]]]
---------------------
[[[ 84 102 125]
  [ 79 100 122]]

 [[ 85 102 123]
  [ 84 103 124]]]
---------------------
[[[151 190 137]
  [141 179 137]]

 [[151 177 136]
  [149 177 142]]]


以上的 位运算API 中,还有一个可选参数 ——> 掩码mask
掩码mask ——> 我们的bitewise_操作(无论是andornotxor操作都有的参数)

以与运算bitwise_and(src1, src2[, dst[, mask]])为例:
作用:前面的两个参数src1src2正常地做与运算,将结果和掩码mask再做与运算(无论是什么位运算,都统统和掩码mask做与运算)

按位运算:如果是True,则显示原来的值(返回原图);如果是False,则为0(黑色)

可参考 作业 ——> Version2 ——>3


以上例程中,我们想要对两幅不一样的图片进行位运算时,都需要将大的图片"切片"成和小图一样的大小,用到的是numpy中的ndarray方法,其实略为繁琐,在下一章我们将使用图像变换的cv2.resize()方法,会更加简便操作!


作业

Version 1

在图片上加上自己设计的Logo,建议Logo简单一点

我们把logo设计为白底,红蓝绿三个颜色的三角形

用到图片的融合API:cv2.addWeighted()

import cv2
import numpy as np

# 导入背景图
cat = cv2.imread('./cat.jpeg')

# 创建一个纯白的背景图 用于画logo
logo = np.ones((480,640,3),np.uint8) * 255 # 行(宽):640  列(高):480

# 绘制直线——> 三角形的边
logo = cv2.line(img,(160,320),(480,320),(0,0,255),5,16)
logo = cv2.line(img,(160,320),(320,100),(0,255,0),5,16)
logo = cv2.line(img,(480,320),(320,100),(255,0,0),5,16)

new_cat = cv2.resize(cat , (640,480))
print(new_cat.shape)
print(logo.shape)


# 融合两张图片 ——> 前提是两张图片大小必须相等!
new_img = cv2.addWeighted(new_cat,0.7,logo,0.3,0)

cv2.imshow('logo',new_img)

cv2.waitKey(0)
cv2.destroyAllWindows()

其中:
画出的logo:
OpenCV:03图像的算数运算_第1张图片
我们用的底图:
OpenCV:03图像的算数运算_第2张图片
结果:
OpenCV:03图像的算数运算_第3张图片


Version 2

在图片上加上自己设计的Logo,建议Logo简单一点

我们把logo设计为红绿两个颜色的正方形拼接

用到的图像处理API:cv2.bitwise_and(roi, roi,mask = m)cv2.add(src1,src2) # 要求两幅图大小一样

操作步骤:

  1. 引入图片
  2. 设计一个logo图片
  3. 规划一下你的logo需要放在哪块位置,在添加的位置变成黑色
  4. 利用add方法,把logo和图片叠加在一起

具体操作:

1.引入图片

# 导入图片
cat = cv2.imread('./cat.jpeg')

OpenCV:03图像的算数运算_第4张图片


2.设计一个logo图片

# 创建logo
logo = np.zeros((200,200,3),np.uint8)

# 绘制logo ——> 对图像进行切片,换成另一种颜色
logo[20:120,20:120] = [0,0,255] # 红色
logo[80:180,80:180] = [0,255,0] # 绿色

OpenCV:03图像的算数运算_第5张图片


3.规划一下你的logo需要放在哪块位置,在添加的位置变成黑色

用到了掩码mask

掩码mask ——> 我们的bitewise_操作(无论是andornotxor操作都有的参数)

以与运算bitewise_and为例:
作用:前面的两个参数src1src2正常地做与运算,将结果和掩码mask再做与运算(无论是什么位运算,都统统和掩码mask做与运算)

按位运算:如果是True,则显示原来的值(返回原图);如果是False,则为0(黑色)

# 掩码mask ——> 我们的bitewise_操作(无论是and、or、not、xor操作都有的参数) 以与运算and为例
    # 作用:前面的两个参数src1和src2正常地做与运算,将结果和掩码mask再做与运算(无论是什么位运算,都统统和掩码mask做与运算)
        #按位运算:如果是True,则显示原来的值(返回原图);如果是False,则为0(黑色)
        
# 我们用掩码的目的是:把logo中不必要的像素(纯黑的部分)剔除,使和背景融合的只有有用的部分
mask = np.zeros((200,200),np.uint8) # 需要设置为和logo一样的大小才能做掩码 注意:掩码是黑白的!(做与运算时要求对象是二维的,不能是三维的)
mask[20:120,20:120] = 255 # 改成白色
mask[80:180,80:180] = 255 # 改成白色    # 白色"与"上任何东西都是白色,做mask运算时这部分就是原来的颜色
cv2.imshow('mask',mask)

# 取反
m = cv2.bitwise_not(mask) # 将logo部分变成黑色 ——> 用该图去和logo做与运算,就可以把logo中有用的部分抠出来
cv2.imshow('m',m)

OpenCV:03图像的算数运算_第6张图片


4.利用add方法,把logo和图片叠加在一起

# 选择cat中添加logo的位置 ——> 感兴趣区域roi
roi = cat[0:200,0:200] # 为浅拷贝:相当于从cat中截取了一块图片出来,改变这一小块中的值,原始的cat也会改变

# roi 与 m 进行与操作 ——> 相当于在roi中抠出了logo的位置(变成黑色)
temp = cv2.bitwise_and(roi, roi,mask = m) # 自己和自己进行"与"操作还是自己

# 做个加法:temp中间是黑的,logo周围是黑的,两个图片相加:黑的地方值为0,相加不影响像素,即把两张图完好地叠在一起了!
dst = cv2.add(temp,logo)
cv2.imshow('temp',temp)


# 在cat上还原 ——> 把图片覆盖上去即可
cat[0:200,0:200] = dst
cv2.imshow('dst',dst)


cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV:03图像的算数运算_第7张图片

OpenCV:03图像的算数运算_第8张图片


整段代码:

# 写代码前思路要清晰
# 1. 引入图片
# 2. 设计一个logo图片
# 3. 规划一下你的logo需要放在哪块位置,在添加的位置变成黑色
# 4. 利用add方法,把logo和图片叠加在一起


# 导入图片
cat = cv2.imread('./cat.jpeg')

# 创建logo
logo = np.zeros((200,200,3),np.uint8)

# 绘制logo ——> 对图像进行切片,换成另一种颜色
logo[20:120,20:120] = [0,0,255] # 红色
logo[80:180,80:180] = [0,255,0] # 绿色

cv2.imshow('logo',logo)
cv2.imshow('cat',cat)

# 掩码mask ——> 我们的bitewise_操作(无论是and、or、not、xor操作都有的参数) 以与运算and为例
    # 作用:前面的两个参数src1和src2正常地做与运算,将结果和掩码mask再做与运算(无论是什么位运算,都统统和掩码mask做与运算)
        #按位运算:如果是True,则显示原来的值(返回原图);如果是False,则为0(黑色)
        
# 我们用掩码的目的是:把logo中不必要的像素(纯黑的部分)剔除,使和背景融合的只有有用的部分
mask = np.zeros((200,200),np.uint8) # 需要设置为和logo一样的大小才能做掩码 注意:掩码是黑白的!(做与运算时要求对象是二维的,不能是三维的)
mask[20:120,20:120] = 255 # 改成白色
mask[80:180,80:180] = 255 # 改成白色    # 白色"与"上任何东西都是白色,做mask运算时这部分就是原来的颜色
cv2.imshow('mask',mask)

# 取反
m = cv2.bitwise_not(mask) # 将logo部分变成黑色 ——> 用该图去和logo做与运算,就可以把logo中有用的部分抠出来
cv2.imshow('m',m)

# 选择cat中添加logo的位置 ——> 感兴趣区域roi
roi = cat[0:200,0:200] # 为浅拷贝:相当于从cat中截取了一块图片出来,改变这一小块中的值,原始的cat也会改变

# roi 与 m 进行与操作 ——> 相当于在roi中抠出了logo的位置(变成黑色)
temp = cv2.bitwise_and(roi, roi,mask = m) # 自己和自己进行"与"操作还是自己

# 做个加法:temp中间是黑的,logo周围是黑的,两个图片相加:黑的地方值为0,相加不影响像素,即把两张图完好地叠在一起了!
dst = cv2.add(temp,logo)
cv2.imshow('temp',temp)


# 在cat上还原 ——> 把图片覆盖上去即可
cat[0:200,0:200] = dst
cv2.imshow('dst',dst)


cv2.waitKey(0)
cv2.destroyAllWindows()

你可能感兴趣的:(opencv,python,numpy)