图像的基础操作

  • 获取像素值并修改
  • 获取图像的属性(信息)
  • 图像的 ROI()
  • 图像通道的拆分及合并
  • BGR转RGB
  • 图像扩边(边界填充)

一、获取并修改像素值

注意: Numpy 是经过优化了的进行快速矩阵运算的软件包。所以我们不推荐逐个获取像素值并修改,这样会很慢,能有矩阵运算就不要用循环。

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


img=cv2.imread('cat.jpg')


px=img[100,100]
print (px)

blue=img[100,100,0]
print (blue)


# 你可以以类似的方式修改像素值。
import cv2
import numpy as np

img=cv2.imread('cat.jpg')
img[100,100]=[255,255,255]
print (img[100,100])
## [255 255 255]

注意: 上面提到的方法被用来选取矩阵的一个区域,比如说前 5 行的后 3列。对于获取每一个像素值,也许使用 Numpy 的 array.item() 和 array.itemset() 会更好。但是返回值是标量。如果你想获得所有 B,G,R 的值,你需要使用 array.item() 分割他们。

获取像素值及修改的更好方法。

import cv2
import numpy as np

img=cv2.imread('cat.jpg')
print (img.item(10,10,2))
img.itemset((10,10,2),100)
print (img.item(10,10,2))

二、获取图像属性

  • 图像的属性包括:行,列,通道,图像数据类型,像素数目等
import cv2
import numpy as np

img=cv2.imread('cat.jpg')

# img.shape 可以获取图像的形状。他的返回值是一个包含行数,列数,通道数的元组。
# 注意:如果图像是灰度图,返回值仅有行数和列数。可通过检查这个返回值就可以知道加载的是灰度图还是彩色图。
print(img.shape)

# img.size 可以返回图像的像素数目
print(img.size)

# img.dtype 返回的是图像的数据类型
# 注意:在debug时 img.dtype 非常重要。因为在 OpenCV-Python 代码中经常出现数据类型的不一致。
print(img.dtype)

三、图像ROI

图像的 ROI(region of interest) 是指图像中感兴趣区域、在 OpenCV 中图像设置图像 ROI 区域,实现只对 ROI 区域的操作。

  • 有时你需要对一幅图像的特定区域进行操作。例如我们要检测一副图像中眼睛的位置,我们首先应该在图像中找到脸,再在脸的区域中找眼睛,而不是直接在一幅图像中搜索。这样会提高程序的准确性和性能。
  • ROI 也是使用 Numpy 索引来获得的。现在我们被选择部分并把他拷贝到图像的其他区域。
import cv2
import numpy as np

img=cv2.imread('dog.jpg')

roi =img[280:340,330:390]
img[273:333,100:160]=roi

plt.figure(figsize = (15, 5))
plt.subplot(1, 2, 1), plt.imshow(img), plt.axis('off'), plt.title("img")
plt.subplot(1, 2, 2), plt.imshow(roi), plt.axis('off'), plt.title("roi")

python RGB占内存最小 python处理rgb_bc

四、拆分及合并图像通道

注意:

  • 日常开发和交流时,我们习惯将图片的颜色通道按照RGB(red, green, blue)进行排列。OpenCV却没有按照这个顺序读入图片,而是采用了BGR格式。使用matplotlib来显示图像,默认是RGB顺序,所以图像显示有所差异。
  • 但你还是可以根据像素的行和列的坐标获取他的像素值。只不过对 BGR 图像而言,返回值为 B,G,R 的值。

为什么OpenCV选择BGR颜色空间呢?

参考这篇文章:https://link.jianshu.com/?t=https://www.learnopencv.com/why-does-opencv-use-bgr-color-format/.

早期的OpenCV开发者选择BGR颜色格式的原因在于主流的摄像头制造商和软件供应商都普遍使用这种格式,比如说在Windows中,当使用 COLORREF 指定颜色值时,使用BGR格式0x00bbggrr。 BGR是历史的选择,我们现在必须适应它。

BGR转RGB方法

  • 方法一
b,g,r=cv2.split(img)
img2=cv2.merge((r.g.b))
  • 方法二
img2=img[: , : , : : -1]

有时我们需要对 BGR 三个通道分别进行操作。这是你就需要把 BGR 拆分成单个通道。有时你需要把独立通道的图片合并成一个 BGR 图像。

使用OpenCV读取在matplotlib上显示和转化为RGB后在matplotlib上显示对比

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


img=cv2.imread('cat.jpg')


# BGR转RGB的两种方法
#方法一   cv2.split() 是一个比较耗时的操作。只有真正需要时才用它,能用Numpy 索引就尽量用。
b,g,r=cv2.split(img)
img2=cv2.merge((r,g,b))

#方法二
#img2=img[: , : , : : -1]


plt.figure(figsize = (10, 10))

#使用OpenCV读取在matplotlib上显示
plt.subplot(1, 2, 1), plt.imshow(img), plt.axis('off'), plt.title("BGR")

# 转化为RGB之后显示在matplotlib上显示
plt.subplot(1, 2, 2), plt.imshow(img2), plt.axis('off'), plt.title("RGB")

python RGB占内存最小 python处理rgb_bc_02

import cv2
import numpy as np

img=cv2.imread('cat.jpg')

b=img[:,:,0]

# 假如你想使所有像素的红色通道值都为 0,你不必先拆分再赋值。你可以直接使用 Numpy 索引,这会更快。
img[:,:,2]=0

五、图像扩边(边界填充)

为什么需要扩充?

在图像处理过程中,因为卷积算子(后面会讲到)有一定大小,所以就会导致图像一定范围的边界不能被处理,这时就需要将边界进行适当扩充。

如果你想在图像周围创建一个边,就像相框一样,你可以使用 cv2.copyMakeBorder()函数。这经常在卷积运算或 0 填充时被用到。这个函数包括如下参数:

  • src 输入图像
  • top, bottom, left, right 对应边界的像素数目。
  • value 边界颜色,如果边界的类型是 cv2.BORDER_CONSTANT
  • borderType 要添加那种类型的边界,类型如下:
  1. cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要下一个参数(value)。
  2. cv2.BORDER_REFLECT 边界元素的镜像。比如: fedcba|abcdefgh|hgfedcb
  3. cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba
  4. cv2.BORDER_REPLICATE 重复最后一个元素。例如: aaaaaa|abcdefgh|hhhhhhh
  5. cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh|abcdefgh|abcdefg
import cv2
import numpy as np
from matplotlib import pyplot as plt

BLUE=[255,0,0]
img1=cv2.imread('cat.jpg')

# BORDER_REPLICATE:复制法,也就是复制最边缘像素。
replicate = cv2.copyMakeBorder(img1,50,50,50,50,cv2.BORDER_REPLICATE)

# BORDER_REFLECT:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb  
reflect = cv2.copyMakeBorder(img1,50,50,50,50,cv2.BORDER_REFLECT)

# BORDER_REFLECT_101:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
reflect101 = cv2.copyMakeBorder(img1,50,50,50,50,cv2.BORDER_REFLECT_101)

# BORDER_WRAP:外包装法cdefgh|abcdefgh|abcdefg  
wrap = cv2.copyMakeBorder(img1,50,50,50,50,cv2.BORDER_WRAP)

# BORDER_CONSTANT:常量法,常数值填充。 
constant= cv2.copyMakeBorder(img1,50,50,50,50,cv2.BORDER_CONSTANT,value=BLUE)

plt.figure(figsize = (25,10))
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 排列。

python RGB占内存最小 python处理rgb_opencv_03