【Opencv-Python 官方教程】6.图像的基本操作

本节目标

  • 获取、修改像素值
  • 获取图像的属性
  • 设置图像区域(ROI)
  • 分割及合并图像通道

本节所涉及的操作主要是关于numpy的,而不是opencv,想要写出高效的opencv代码需要对numpy有很好的了解。

原文地址:Basic Operations on Images


获取并修改像素值

首先加载一个彩色图像

>>> import cv2
>>> import numpy as np

>>> img = cv2.imread('lena.jpg')

可以通过行列的坐标获取像素值。对于BGR图像,它会返回一个数组(array),包含BGR三个通道的值。对于灰度图(grayscale image),仅仅返回相应的亮度值。

>>> px = img[100,100]
>>> print(px)
[111 115 116]
>>>
>>> # 只访问蓝色通道值
>>> blue = img[100,100,0]
>>> print(blue)
111

你可以采用同样的方式修改像素值

>>> img[100,100] = [255,255,255]
>>> print(img[100,100])
[255 255 255]
>>> #可以看到修改是在原地的,inplace,而不是副本修改

warning

numpy是一个经过优化的快速数的组计算的库,所以简单的访问每一个像素值并修改会很慢,所以并不推荐这样做。

Note

上述提到的方法通常被用作选取图像的区域,比如图像的前5行,和后3列。对于单个的图像像素点的访问,numpy数组的方法array.item()array.itemset()通常是更优雅的方式。但是它返回的是一个scalar类型的数据。所以如果你想要互殴所有的B、G、R的值,你需要单独为每个像素点都调用array.item()

更好的访问和修改像素的方法:

扫描二维码关注公众号,回复: 3868997 查看本文章
>>> img.item(10,10,2)
109
>>> img.itemset((10,10,2),100)
>>> img.item(10,10,2)
100

获取图像的属性

图像的属性包括图像的行列数,通道数,图像数据类型,像素点的数量等

图像的形状(长宽、通道)可以通过img.shape得到,它将返回一个元组,包含图像的行列数以及通道数(若是彩色图的话)

>>> print(img.shape)
(529, 560, 3)

Note

若图像是灰度图,返回的元组只包含行列数,所以检查载入的图像是灰度图还是彩色图像是一个有效的方法。

可通过img.size获取图像的总的像素点的数目

>>> print(img.size)
888720

图像的数据类型通过img.dtype查看

>>> print(img.dtype)
uint8
>>> # uint8 表示0到255的整数值

Note

img.dtype在debug的时候是非常有用的,因为大部分的opencv-python代码错误都是因为无效的数据类型造成的。


图像的感兴趣区域(region of interest)

有时,你需要处理某个图像上的区域。比如图像的眼睛的检测,首先,需要进行面部检测,直到检测到脸部。然后搜索整个面部区域检测眼睛。这种方式可以提高准确率(因为眼睛通常都是在面部上的)和性能(因为搜索的范围变小)

ROI也是使用numpy索引。比如这里我选择足球并且将它拷贝到图像的另一个区域。

>>> import cv2
>>> import numpy
>>>
>>> img = cv2.imread('roi.jpg')
>>> ball = img[230:,270:320]
>>> img[220:270,70:120] = ball
>>> cv2.imshow('image',img)
>>> cv2.waitKey()

结果如下所示:

这里写图片描述


分割及合并图像通道

图像的B,G,R三个通道可以在需要的时候被单独拆分,同样独立的通道也可以再被合并到一起组成BGR图像。这可以通过以下方法实现:

>>> b,g,r = cv2.split(img)
>>> img = cv2.merge((b,g,r))
>>> # 其实不用cv2,直接用numpy也可以实现,如下
>>> b = img[:,:,0]

假如你想让所有像素的红色通道值变为0,你需要像上面那样拆分通道,然后将他们置为0,你可以使用numpy的索引更简便的实现。

>>> img[:,:,2] = 0

Warning

cv2.split()是一个时间开销很大的操作,所以若无必要不要轻易使用。numpy索引是一种更有效的方式。


图像边界(Border)

如果你想给图像周围添加一个边框,类似于相框,你可以用cv2.copyMakeBorder()函数。但是边界常常在卷积操作中应用更为多,比如边界填充0值。该函数有以下参数:

  • src,输入的图像
  • top,bottom,left,right,4个方向上边界宽度(像素为单位)
  • borderType,定义需要添加的是什么类型的边界,它有以下值:
    • cv2.BORDER_CONSTANT,常量填充边界,值由下一个参数value指定。
    • cv2.BORDER_REFLECT,将会在边界上进行镜像操作。如fedcba|abcdefgh|hgfedcb
    • cv2.BORDER_REFLECT_101或cv2.BORDER_DEFAULT,和上一个值BORDER_REFLECT类似,仅存在微小变换。如 gfedcb|abcdefgh|gfedcba
    • cv2.BORDER_REPLICATE,使用最后一个元素进行重复填充,如aaaaaa|abcdefgh|hhhhhhh
    • cv2.BORDER_WRAP,不做解释,它是这样的cdefgh|abcdefgh|abcdefg
  • value,边界的颜色值(当boder的type是cv2.BORDER_CONSTANT时)

下面是一个示例代码,展示各种边界类型。

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

BLUE = [255,0,0]

img1 = cv2.imread('opencv_logo.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显示,所以红色和蓝色通道会交换)

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u013095718/article/details/80659233