图像的基础操作
获取图像的像素值并修改
首先读入一副图像:
python
import numpy as np
import cv2
# 1.获取并修改像素值
# 读取一副图像, 根据像素的行和列的坐标获取它的像素值, 对于RGB图像而言, 返回RGB的值, 对于灰度图则返回灰度值
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
px = img[200, 100]
print(px) # [24 18 11]
blue = img[200, 100, 0]
print(blue) # 24
# 修改101行,101列的像素值
img[101, 101] = [255,255,255]
print(img[101,101])
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
获取像素值及修改的更好方法:
python
import numpy as np
import cv2
# numpy是经过优化了的进行快速矩阵运算的包, 所以不推荐逐个获取像素值并修改能矩阵运算就不要用循环。
# 例如前5行的后3列, 用numpy的array.item()和array.itemset()会更好。 但是返回是标量, 如果想获得所有RGB
# 的值, 需要使用array.item()分割他们。
img = cv2.imread('./resource/image/1.jpg')
print(img.item(10, 10, 2))
img.itemset((10, 10, 2), 100)
print(img.item(10, 10, 2))
获取图像的属性信息
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
img.shape: 图像的形状(包括行数,列数,通道数的元组)
img.size : 图像的像素数目
img.dtype :图像的数据类型
python
import numpy as np
import cv2
# 图像属性包括: 行, 列, 通道, 图像数据类型, 像素数目等
# 如果图像是灰度图, 返回值仅有行数和列数, 所以通过检查返回值可以判断是灰度图还是彩色图
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
print(img.shape) # 彩色图(1080, 1920, 3)
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_GRAYSCALE)
print(img.shape) # 灰度图(1080, 1920)
# img.size 获取图像像素数
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
print(img.size) # 6220800
print(img.dtype)# uint8
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_GRAYSCALE)
print(img.size) # 2073600
print(img.dtype)# uint8
图像的ROI区域
ROI(regionofinterest),感兴趣区域。机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI。在Halcon、OpenCV、Matlab等机器视觉软件上常用到各种算子(Operator)和函数来求得感兴趣区域ROI,并进行图像的下一步处理。
python
import numpy as np
import cv2
img = cv2.imread('./resource/image/4.jpg')
ball = img[20:70,30:80] # 获取一块图像
img[40:90,50:100] = ball # 指定位置绘制一块图像
cv2.imshow('image', img)
cv2.waitKey(0)&0xFF
cv2.destroyAllWindows()
图像通道的拆分及合并
有时需要对 BGR 三个通道分别进行操作。这时就需要把 BGR 拆
分成单个通道。有时需要把独立通道的图片合并成一个 BGR 图像。
注:cv2.split()是比较耗时的操作,尽量使用numpy索引操作。
python
import numpy as np
import cv2
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
# split函数,拆分图像数据
(b,g,r) = cv2.split(img)
img2 = cv2.merge([b,g,r]) # 合并数据
print(r.shape)
print(g.shape)
print(b.shape)
# Numpy索引拆分图像数据
img = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
b = img[:,:,0] # 拆分b通道
g = img[:,:,1] # 拆分g通道
r = img[:,:,2] # 拆分r通道
# 通道像素赋值
img[:,:,2]= 0 #
print(r.shape)
print(g.shape)
print(b.shape)
img3 = cv2.merge([b,g,r])
cv2.imshow('img', img)
cv2.imshow('img2', img2)
cv2.imshow('img3', img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像扩边填充
如果想在图像周围创建一个边,就像相框一样,你可以使用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
- cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要
-
value 边界颜色,如果边界的类型是 cv2.BORDER_CONSTANT
python
import numpy as np
import cv2
from matplotlib import pyplot as plt
# 边界填充
img = cv2.imread('./resource/image/opencv-logo2.png')
# BORDER_REPLICATE:复制法,复制最边缘的像素
# BORDER_REFLECT:反射法
# BORDER_REFLECT101:反射法
# BORDER_WRAP:外包装
# BORDER_CONSTANT:常量法
blue = [255, 0, 0]
replicate = cv2.copyMakeBorder(img, 10, 10, 10, 10, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, 10, 10, 10,10, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, 10, 10, 10, 10, cv2.BORDER_REFLECT101)
wrap = cv2.copyMakeBorder(img, 10, 10, 10, 10, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=blue)
plt.subplot(231), plt.imshow(img, 'gray'), plt.title('original'), plt.xticks([]),plt.yticks([])
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('replicate'), plt.xticks([]),plt.yticks([])
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('reflect'), plt.xticks([]),plt.yticks([])
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('reflect101'), plt.xticks([]),plt.yticks([])
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('warp'), plt.xticks([]),plt.yticks([])
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('constant'), plt.xticks([]),plt.yticks([])
plt.show()
图像上的算术运算
图像上的算术运算有:加法,减法,位运算等
涉及的函数有:cv2.add(), cv2().addWeighted()等
图像的加法
可以使用函数 cv2.add() 将两幅图像进行加法运算,当然也可以直接使
用 numpy, res=img1+img2。两幅图像的大小,类型必须一致,或者第二个
图像可以是一个简单的标量值。
注意: OpenCV 中的加法与 Numpy 的加法是有所不同的。 OpenCV 的加法
是一种饱和操作,而 Numpy 的加法是一种模操作。如下例子所示:
python
x = np.uint8([250])
y = np.uint8([10])
print(cv2.add(x, y)) # 250 + 10 = 260 > 255, uint8 最大值255
# 输出结果[[255]]
print(x + y) # 250_10=260%255=4
# 输出结果[[4]]
图像的混合
其实也是加法运算,但不同的是两幅图像的权重不同,给人一种混合或透明的感觉。图像混合计算公式如下:
g ( x ) = ( 1 − α ) f 0 ( x ) + α f 1 ( x ) g(x) = (1-\alpha)f_0(x) + \alpha f_1(x) g(x)=(1−α)f0(x)+αf1(x)
通过修改 α \alpha α的值(0-1),可以实现不同权重的混合。
d s t = α ∗ i m g 1 + β ∗ i m g 2 + γ dst = \alpha*img1 + \beta*img2+\gamma dst=α∗img1+β∗img2+γ
这里 γ \gamma γ的值为0。
dst2 = cv2.addWeighted(img1, 0.3, img2, 0.7, 0)
python
import numpy as np
import cv2
from matplotlib import pyplot as plt
img1 = cv2.imread('./resource/image/1.jpg', cv2.IMREAD_COLOR)
img2 = cv2.imread('./resource/image/2.jpg', cv2.IMREAD_COLOR)
dst1 = img1 + img2
dst2 = cv2.addWeighted(img1, 0.3, img2, 0.7, 0)
plt.subplot(231), plt.imshow(img1), plt.title('img1')
plt.subplot(232), plt.imshow(img2), plt.title('img2')
plt.subplot(233), plt.imshow(dst1), plt.title('img1+img2')
plt.subplot(234), plt.imshow(dst2), plt.title('addWeighted(img1+img2)')
plt.show()
图像的位运算
图像的按位操作有: AND, OR, NOT, XOR 等。当我们提取图像的一部分,选择非矩形 ROI 时这些操作会很有用。下面的例子就是教给我们如何改变一幅图的特定区域。
- cv2.bitwise_and() 与
- cv2.bitwise_or() 或
- cv2.bitwise_not() 非
- cv2.bitwise_xor() 异或
python
import numpy as np
import cv2
img1 = cv2.imread('./resource/image/1.jpg')
img2 = cv2.imread('./resource/image/opencv-logo.png')
# 放置logo在左上角
rows, cols, channels = img2.shape
roi = img1[0:rows,0:cols]
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY) # 二值化处理
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
img2_fg = cv2.bitwise_and(img2, img2, mask=mask_inv)
dst = cv2.add(img1_bg, img2_fg)
img1[0:rows, 0:cols] = dst
cv2.imshow('logo', img2)
cv2.imshow('gray', img2gray)
cv2.imshow('mask', mask)
cv2.imshow('mask_inv', mask_inv)
cv2.imshow('bg', img1_bg)
cv2.imshow('fg', img2_fg)
cv2.imshow('res', img1)
cv2.waitKey(0)
cv2.destroyAllWindows()