Image Basic Operations|Day 3
第一次学习OpenCV,在这里将学习如何利用OpenCV对图像进行基础操作。
1. 图像的基础操作
图像的基本操作包括:
• 获取像素值并修改
• 获取图像的属性(信息)
• 图像的 ROI
• 图像通道的拆分及合并
1.1 获取并修改像素值
可以根据像素的行和列的坐标来获取它的像素值。对 BGR 图像而言,返回值为 B,G,R 的值。对灰度图像而言,则会返回他的灰度值。
import cv2
import numpy as np
# 首先读入一幅图像
img=cv2.imread('image.jpg')
px=img[100,100]
print px
blue=img[100,100,0]
print blue
## [57 63 68]
## 57
可以通过类似的方式修改像素值。
import cv2
import numpy as np
img=cv2.imread('image.jpg')
img[100,100]=[255,255,255]
print img[100,100]
## [255 255 255]
使用 Numpy 的 array.item()
和 array.itemset()
获取每一个像素值。使用 array.item()
分割所有 B,G,R 的值。
import cv2
import numpy as np
img=cv2.imread('image.jpg')
print img.item(10,10,2)
img.itemset((10,10,2),100)
print img.item(10,10,2)
## 50
## 100
1.2 获取图像属性
图像的属性包括:行,列,通道,图像数据类型,像素数目等。img.shape
可以获取图像的形状。他的返回值是一个包含行数,列数,通道数的元组,如果图像是灰度图,返回值仅有行数和列数。img.size
可以返回图像的像素数目。img.dtype
返回的是图像的数据类型。
import cv2
import numpy as np
img=cv2.imread('image.jpg')
print img.shape
## (280, 450, 3)
print img.size
## 378000
print img.dtype
## uint8
1.3 图像 ROI
ROI(图像感兴趣区域)
有时候我们需要对一幅图像的特定区域进行操作。ROI 也是使用 Numpy 索引来获得的。
我们选择图像中的某部分并把他拷贝到图像的其他区域。
import cv2
import numpy as np
img=cv2.imread('image.jpg')
px=img[280:340,330:390]
img[273:333,100:160]=px
1.4 拆分及合并图像通道
对 BGR 三个通道分别进行操作,则需要把 BGR 拆分成单个通道。也可以把独立通道的图片合并成一个 BGR 图像。
把独立通道的图片合并成一个 BGR 图像。
import cv2
import numpy as np
img=cv2.imread('image.jpg')
b,g,r=cv2.split(img)
img=cv2.merge(b,g,r)
或者
b=img[:,:,0]
使所有像素的红色通道值都为 0,直接使用 Numpy 索引。
import cv2
import numpy as np
img=cv2.imread('image.jpg')
img[:,:,2]=0
1.5 为图像扩边(填充)
在图像周围创建一个边。可以使用 cv2.copyMakeBorder()
函数。这个函数经常在卷积运算或 0 填充时被用到。
函数包含以下参数:
• src 输入图像
• top, bottom, left, right 对应边界的像素数目。
• borderType 要添加那种类型的边界,类型如下:
cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要下一个参数(value)。
cv2.BORDER_REFLECT 边界元素的镜像。比如: fedcba|abcdefgh|hgfedcb
cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT 跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba
cv2.BORDER_REPLICATE 重复最后一个元素。例如: aaaaaa|abcdefgh|hhhhhhh
cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh|abcdefgh|abcdefg
• value 边界颜色,如果边界的类型是 cv2.BORDER_CONSTANT
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
BLUE=[255,0,0]
img1=cv2.imread('image.png')
replicate = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_WRAP)
constant= cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,value=BLUE)
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
# 由于是使用 matplotlib 绘制,所以交换 R 和 B 的位置,OpenCV 中是按 BGR,matplotlib 中是按 RGB 排列
2. 图像上的算术运算
图像上的算术运算,加法,减法,位运算等。函数有:cv2.add()
,cv2.addWeighted()
等。
2.1 图像加法
使用函数 cv2.add()
将两幅图像进行加法运算。可以直接使用 numpy,res=img1+img。两幅图像的大小,类型必须一致,或者第二个图像可以使一个简单的标量值。
OpenCV 中的加法与 Numpy 的加法是有所不同的。OpenCV 的加法是一种饱和操作,而 Numpy 的加法是一种模操作。
x = np.uint8([250])
y = np.uint8([10])
print cv2.add(x,y) # 250+10 = 260 => 255
[[255]]
print x+y # 250+10 = 260 % 256 = 4
[4]
2.3 图像混合
图像混合其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。
图像混合的计算公式如下:g (x) = (1 − α) f0 (x) + αf1 (x)。通过修改 α 的值(0 → 1),可以实现混合。
函数 cv2.addWeighted()
可以按此公式(dst = α · img1 + β · img2 + γ)对图片进行混合操作。
现在把两幅图混合在一起。第一幅图的权重是 0.7,第二幅图的权重是 0.3。这里 γ 的取值为 0。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
img1=cv2.imread('img1.png')
img2=cv2.imread('img2.jpg')
dst=cv2.addWeighted(img1,0.7,img2,0.3,0)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindow()
2.3 按位运算
按位操作有:AND,OR,NOT,XOR 等。可以提取图像非矩形 ROI 部分。
按位运算实现:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
# 加载图像
img1 = cv2.imread('img1.jpg')
img2 = cv2.imread('img2.png')
# 把图像的某部分放在左上角,首先创建一个ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
# 现在为图像创建一个mask 并创建它的反向mask
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
# 现在在 ROI 中涂黑图像区域
# 取 roi 中与 mask 中不为零的值对应的像素的值,其他值为 0
# 注意这里必须有 mask=mask 或者 mask=mask_inv, 其中的 mask= 不能忽略
img1_bg = cv2.bitwise_and(roi,roi,mask = mask)
# 取 roi 中与 mask_inv 中不为零的值对应的像素的值,其他值为 0。
# 从徽标图像中只取徽标区域
img2_fg = cv2.bitwise_and(img2,img2,mask = mask_inv)
# 把图像放在 ROI 和修改主图像
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv2.imshow('res',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()