图像的基本表示方法
1.二值图像
- 仅仅包含黑白两色
- 图像划分为小方块,白色像素点为1,黑色像素点为0
2.灰度图像
- 采用了更多数值以体现不同颜色
- 通常处理256个灰度级,以[0,255]表示,”255“为纯白色,”0“为纯黑色。
3.彩色图像
- 不同的色彩空间具有不同的表示方式,以常用的RGB色彩空间学习。
- 在RGB色彩空间中,存在R(red,红色)通道、G(green,绿色)通道和B(blue,蓝色)通道。通道值为[0,255]之间。用三个色彩通道组合表示颜色
- 一共256×256×256=16777216种颜色
- 在OpenCV中,通道的顺序是B→G→R;RGB色彩空间的通道顺序则为R→G→B。
像素处理
1.二值图像及灰度图像
- OpenCV中最小的数据类型是无符号的8位数,以0和255表示二值图像。
- 一个OpenCV灰度图像是一个二维数组
例子:Numpy生成8×8的数组,模拟黑色图像,访问、修改。
import cv2
import numpy as np
img = np.zeros((8,8), dtype=np.uint8)
print("img=\n", img)
cv2.imshow("one", img)
cv2.waitKey()
print("读取像素点img[0,3]=", img[0, 3])
img[0,3] = 255
print("修改后img=\n", img)
print("读取像素点img[0,3]=", img[0, 3])
cv2.imshow("two", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
代码分析:
- 使用函数zeros()生成8×8大小且值都为0的二维数组,数值类型是np.uint8。
- img[0,3]访问img第0行第3列的像素点,序号都从0开始。
例子:读取灰度图像,访问、修改
import cv2
from lib import path #无需理会
img = cv2.imread(path.get_graph_path("Image.jpg"), 0)
cv2.imshow("demo", img)
for i in range(10, 100):
for j in range(80, 100):
img[i, j] = 255
cv2.imshow("after", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
2.彩色图像
RGB模式的彩色图像在读入OpenCV内进行处理时,会按照行方向一次读取该RGB图像的B通道,G通道,R通道的像素点,并将像素点以行为单位存储在ndarray的列中。例如,R行×C列的元素RGB图像,在OpenCV内以BGR模式的三维数组形式存储,
B G R
B G R
B G R
B G R
B G R
B G R
B G R
image[0, 0, 0]可以访问image的B通道内第0行第0列上的像素点
- 第一个索引表示第0行
- 第二个索引表示第0列
- 第三个索引表示第0个颜色通道
例子:生成三维数组,观察三个通道值的变化
import cv2
import numpy as np
# ------------- Channel Blue -------------
blue = np.zeros((300, 300, 3), dtype=np.uint8)
blue[:, :, 0] = 255
print("blue=\n", blue)
cv2.imshow("blue", blue)
# ------------- Channel Green -------------
green = np.zeros((300, 300, 3), dtype=np.uint8)
green[:, :, 1] = 255
print("green=\n", green)
cv2.imshow("green", green)
# ------------- Channel Red -------------
red = np.zeros((300, 300, 3), dtype=np.uint8)
red[:, :, 2] = 255
print("red=\n", red)
cv2.imshow("red", red)
# ------------- Close Windows -------------
cv2.waitKey()
cv2.destroyAllWindows()
例子:
import cv2
import numpy as np
img = np.zeros((300, 300, 3), dtype=np.uint8)
img[:, 0:100, 0] = 255
img[:, 100:200, 1] = 255
img[:, 200:300, 2] = 255
cv2.imshow("img", img)
# ------------- Close Windows -------------
cv2.waitKey()
cv2.destroyAllWindows()
例子:numpy生成3D 数组。模拟BGR模式的彩色图像,访问、修改。
import numpy as np
img = np.zeros((2, 4, 3), dtype=np.uint8)
print("img=\n", img)
print("读取像素点img[0,3]", img[0, 3])
print("读取像素点img[1,2,3]", img[1, 2, 2])
img[0, 3] = 255
img[0, 0] = [66, 77, 88]
img[1, 1, 1] = 3
img[1, 2, 2] = 4
img[0, 2, 0] = 5
print("修改后 img\n", img)
print("读取修改后像素点 img[1,2,2]", img[1, 2, 2])
结果:
img=
[[[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]][[0 0 0]
[0 0 0]
[0 0 0]
[0 0 0]]]
读取像素点img[0,3] = [0 0 0]
读取像素点img[1,2,3] = 0
修改后 img=
[[[ 66 77 88]
[ 0 0 0]
[ 5 0 0]
[255 255 255]][[ 0 0 0]
[ 0 3 0]
[ 0 0 4]
[ 0 0 0]]]
读取修改后像素点 img[1,2,2] = 4
例子:读取一幅彩色图像,访问、修改。
import cv2
from lib import path
img = cv2.imread(path.get_graph_path("Image.jpg"))
cv2.imshow("img", img)
print("access img[0,0] : ", img[0, 0])
print("access img[0,0,0] : ", img[0, 0, 0])
print("access img[0,0,1] : ", img[0, 0, 1])
print("access img[0,0,2] : ", img[0, 0, 2])
print("access img[50,0] : ", img[50, 0])
print("access img[100,0] : ", img[100, 0])
# area 1
for i in range(0, 50):
for j in range(0, 100):
for k in range(0, 3):
img[i, j, k] = 255 # white
for i in range(50, 100):
for j in range(0, 100):
img[i, j] = [128, 128, 128] # grey
for i in range(100, 150):
for j in range(0, 100):
img[i, j] = 0
cv2.imshow("after", img)
print("after img[0,0] : ", img[0, 0])
print("after img[0,0,0] : ", img[0, 0, 0])
print("after img[0,0,1] : ", img[0, 0, 1])
print("after img[0,0,2] : ", img[0, 0, 2])
print("after img[50,0] : ", img[50, 0])
print("after img[100,0] : ", img[100, 0])
cv2.waitKey()
cv2.destroyAllWindows()
结果:
access img[0,0] : [ 63 130 157]
access img[0,0,0] : 63
access img[0,0,1] : 130
access img[0,0,2] : 157
access img[50,0] : [100 200 224]
access img[100,0] : [189 254 255]
after img[0,0] : [255 255 255]
after img[0,0,0] : 255
after img[0,0,1] : 255
after img[0,0,2] : 255
after img[50,0] : [128 128 128]
after img[100,0] : [0 0 0]
3.使用 numpy.array 访问像素
numpy.array提供了item()和itemset()函数来访问和修改像素点,这两个函数结果优化处理,比使用索引快得多。
1.二值图像和灰度图像
item() : 更加高效得访问像素点,语法格式为
item(行, 列)
itemset() : 修改像素值,语法格式为
itemset(索引值, 新值)
例子:
import numpy as np
img = np.random.randint(10, 99,size=[5, 5], dtype=np.uint8)
print("img=\n", img)
print("read pixel img.item(3,2)=", img.item(3, 2))
img.itemset((3, 2), 255)
print("wrote img=\n", img)
print("wrote pixel img.item(3,2)=", img.item(3, 2))
结果:
img=
[[95 36 19 45 31]
[91 48 54 30 64]
[31 29 45 10 70]
[47 28 63 70 43]
[84 91 63 86 52]]
read pixel img.item(3,2)= 63
wrote img=
[[ 95 36 19 45 31]
[ 91 48 54 30 64]
[ 31 29 45 10 70]
[ 47 28 255 70 43]
[ 84 91 63 86 52]]
wrote pixel img.item(3,2)= 255
例子:生成一个灰度图像,让其中像素值均为随机数。
import numpy as np
import cv2
img = np.random.randint(0, 255, size=[255, 255], dtype=np.uint8)
cv2.imshow("demo", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
例子:读取一个灰度图像,访问,修改。
import numpy as np
import cv2
img = np.random.randint(0, 255,size=[255,255],dtype=np.uint8)
print("Before (img.item(3,2):", img.item(3, 2))
img.itemset((3, 2), 255)
print("After (img.item(3,2):", img.item(3, 2))
cv2.imshow("before", img)
# area
for i in range(50, 100):
for j in range(80,130):
img.itemset((i, j), 255)
cv2.imshow("after", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
Before (img.item(3,2): 13
After (img.item(3,2): 255
2.彩色图像
item() : 更加高效得访问RGB图像像素点,语法格式为
item(行, 列, 通道)
itemset() : 修改RGB图像得像素值,语法格式为
itemset(三元组索引值, 新值)
例子:numpy随机数生成3D数组, 模拟RGB色彩空间图像,用item()和Itemset()访问和修改。
import numpy as np
img = np.random.randint(0, 255, size=(2, 4, 3), dtype=np.uint8)
print("img=\n", img)
print("img[1, 2, 0]=", img.item(1, 2, 0))
print("img[0, 2, 1]=", img.item(0, 2, 1))
print("img[1, 0, 2]=", img.item(1, 0, 2))
img.itemset((1, 2, 0), 255)
img.itemset((0, 2, 1), 255)
img.itemset((1, 0, 2), 255)
print("After:")
print("img[1, 2, 0]=", img.item(1, 2, 0))
print("img[0, 2, 1]=", img.item(0, 2, 1))
print("img[1, 0, 2]=", img.item(1, 0, 2))
结果:
img=
[[[ 64 239 138]
[122 64 107]
[238 78 73]
[130 91 117]][[153 130 52]
[191 173 161]
[ 76 246 223]
[167 10 241]]]
img[1, 2, 0]= 76
img[0, 2, 1]= 78
img[1, 0, 2]= 52
After:
img[1, 2, 0]= 255
img[0, 2, 1]= 255
img[1, 0, 2]= 255
例子:生成彩色图像,让其中像素值均为随机数。
import cv2
import numpy as np
img = np.random.randint(0, 255, size=[255, 255, 3], dtype=np.uint8)
cv2.imshow("demo", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
例子:读取一个灰度图像,访问,修改。
import cv2
import numpy as np
from lib import path
img = cv2.imread(path.get_graph_path("Image.jpg"))
cv2.imshow("demo", img)
print("读取像素点img[0, 0, 0]=", img[0, 0, 0])
print("读取像素点img[0, 0, 1]=", img[0, 0, 1])
print("读取像素点img[0, 0, 2]=", img[0, 0, 2])
for i in range(0, 50):
for j in range(0, 100):
for k in range(0, 3):
img[i, j, k] = 255
cv2.imshow("after", img)
cv2.waitKey()
cv2.destroyAllWindows()
print("修改后像素点img[0, 0, 0]=", img[0, 0, 0])
print("修改后像素点img[0, 0, 1]=", img[0, 0, 1])
print("修改后像素点img[0, 0, 2]=", img[0, 0, 2])
结果:
读取像素点img[0, 0, 0]= 63
读取像素点img[0, 0, 1]= 130
读取像素点img[0, 0, 2]= 157
修改后像素点img[0, 0, 0]= 255
修改后像素点img[0, 0, 1]= 255
修改后像素点img[0, 0, 2]= 255
4.感兴趣区域(ROI)
我们对图像感兴趣的某个特定区域成为感兴趣区域(Region of Interest, ROI)。在设定ROI后,就可以对该区域进行整体操作。例如,将A(ROI)赋值给B,可以将B赋值给C(ROI)。从而达到区域C复制区域A的目的。
例子:ROI为 img[200:400, 200:400]
import numpy as np
import cv2
img = np.zeros((1000, 1000), dtype=np.uint8)
cv2.imshow("demo_0", img)
img[200:400, 200:400] = 255
cv2.imshow("demo_1", img)
a = img[200:400, 200:400]
img[200:400, 600:800] = a
cv2.imshow("demo_2", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
例子:获得lena脸部信息
from lib import path
import cv2
img = cv2.imread(path.get_graph_path("img.png"), cv2.IMREAD_UNCHANGED) # cv2.IMREAD_UNCHANGED=-1,保持原格式不变
print()
face = img[65:270, 200:350]
cv2.imshow("original", img)
cv2.imshow("face", face)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
例子:对脸部进行打码。
from lib import path
import numpy as np
import cv2
img = cv2.imread(path.get_graph_path("img.png"), cv2.IMREAD_UNCHANGED) # cv2.IMREAD_UNCHANGED=-1,保持原格式不变
cv2.imshow("original", img)
face = np.random.randint(0, 256, (205, 150, 3))
img[65:270, 200:350] = face
cv2.imshow("result", img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
例子:讲ROI复制到其他图像内
from lib import path
import numpy as np
import cv2
lena = cv2.imread(path.get_graph_path("img.png")) # 默认转为BGR图像
gold = cv2.imread(path.get_graph_path("Image.jpg"))
lena[0:100, 370:470] = gold[0:100, 0:100]
cv2.imshow("combined", lena)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
5.通道操作
在OpenCv,通道按照B→G→R顺序存储。
在图像处理过程中, 可以根据需要对通道进行拆分和合并。
通道拆分
1.通过索引拆分
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
例子:演示通道拆分及通道值改变对彩色图像的影响
import cv2
from lib import path
img = cv2.imread(path.get_graph_path("img.png"))
cv2.imshow("img", img)
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
cv2.imshow("b", b)
cv2.imshow("g", g)
cv2.imshow("r", r)
img[:, :, 0] = 0
cv2.imshow("imgb0", img)
img[:, :, 1] = 0
cv2.imshow("imgg0", img)
img[:, :, 2] = 0
cv2.imshow("imgr0", img)
cv2.waitKey()
cv2.destroyAllWindows()
2.通过函数拆分
b, g, r = cv2.split(img)
等价:
b = cv2.split(img)
g = cv2.split(img)
r = cv2.split(img)
例子:使用函数拆分
import cv2
from lib import path
img = cv2.imread(path.get_graph_path("img.png"))
b, g, r = cv2.split(img)
cv2.imshow("B", b)
cv2.imshow("G", g)
cv2.imshow("R", r)
cv2.waitKey()
cv2.destroyAllWindows()
通道合并
通道合并是通道拆分的逆过程,通过合并通道可以将三个通道的灰度图像构成一幅彩色图像。
函数cv2.merge()
import cv2
from lib import path
img = cv2.imread(path.get_graph_path("img.png"))
b, g, r = cv2.split(img)
bgr = cv2.merge([b, g, r])
rgb = cv2.merge([r, g, b])
cv2.imshow("img", img)
cv2.imshow("bgr", bgr)
cv2.imshow("rgb", rgb)
cv2.waitKey()
cv2.destroyAllWindows()
6.获取图像属性
属性:
- shape:彩色图像(行,列,通道),二值图像或灰度图像(行,列)
- size:返回图像的像素数目。像素数目=行×列×通道
- dtype:返回图像的数据类型
例子:观察图像的常用属性
import cv2
from lib import path
gray = cv2.imread(path.get_graph_path("img.png"), 0)
color = cv2.imread(path.get_graph_path("img.png"))
print("Gray attribute:")
print("shape:", gray.shape)
print("size:", gray.size)
print("dtype:", gray.dtype)
print("\nColor attribute:")
print("shape:", color.shape)
print("size:", color.size)
print("dtype:", color.dtype)
Gray attribute:
shape: (373, 497)
size: 185381
dtype: uint8Color attribute:
shape: (373, 497, 3)
size: 556143
dtype: uint8