python怎么编辑图片_OpenCV-Python系列之图像的基本操作

在上个教程中,我们介绍了使用鼠标画笔的功能。本次教程,我们将要谈及OpenCV图像处理的基本操作。

本教程我们需要介绍的是:

· 查看图像的像素值并修改它们

· 查看图像属性

· 查看感兴趣区域(ROI)

· 分割并合并图像

本次教程的所有操作基本上都和Numpy相关,而不是与OpenCV相关。要使用OpenCV编写更好的优化代码,需要Numpy的丰富知识。

查看和修改像素值

我们要想查看一幅图像中某一个像素点的像素值,首先需要进行定位,将其坐标标定,我们先来看一个彩色图像(仍然是我们的猫咪,本次教程它是我们的主角):

8182d5a5cfb553013836c9b094ed50a395a8a7bb.png

现在我想查看某一个坐标的像素值,我们在pycharm中输入代码:import cv2

import numpy as np

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

#获取像素值

px = img[200,200]

print(px)

代码为查看图像坐标(200,200)处的像素值,我们来看结果:45e02a5450792d6f2d68ea5772ea694af26afb85.png

在之前的教程中我们谈到,OpenCV对于图像的读取并非是RGB通道,而是BGR通道,那么程序输出的[178,189,186]则分别对应于BGR的像素,我们可以进行验证:import cv2

import numpy as np

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

#获取像素值

px = img[200,200]

B = img[200,200,0]

G = img[200,200,1]

R = img[200,200,2]

print(px,B,G,R)51c82644f5f0d9e06d1161be4f7c96ab9d7db90b.png

现在我们假设,如果图像并非彩色,而是黑白的灰度图像,那么将会怎么输出?先进行实验:2282f96cd35246a86200fcc83faa561cd3a399c2.png

我们仍然用刚刚的代码进行实验(前提是图像已经灰度化处理,这在后面会讲到),效果:84aa4672e5e334daca0af9e9465cd4e586af4d18.png

可以看到,BGR的像素一致,我们得出一个结论:对于灰度图像,其输出的像素值本质上为它的亮度强度值,值的范围为0-255之间,当为0时,则全部为黑色,相反则为白色。

接下来我们来修改像素值,将指定坐标的像素值用一个数组进行赋值:import cv2

import numpy as np

img = cv2.imread("cat1.jpg")

#获取像素值

px = img[200,200]

print(px)

img[200,200] = [225,225,225]

print(img[200,200])

查看输出:0961f3e1aabf846ab96769d2978696f0670dd250.png

可以看到,初始像素值跟修改之后的像素值。

一般来说,数组通常选择的是某一片区域,比如头几行或者最后几列。而对于某个像素点的访问,Numpy数组方法,array.item() 和array.itemset()有着更好的作用。但是它返回的是一个标量。所以如果我们想访问所有的B, G, R值,就需要分开调用array.item(),我们来看代码(仍然以坐标200,200为例):import cv2

import numpy as np

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

#获取像素值

px = img[200,200]

print(px)

print(img.item(200,200,0))

我们用item输出像素的B值,也就是蓝色像素的数值:10f5a9d662991851ba547a45fc2d2a3cf8882692.png

实验可以看到,跟之前的效果是一样的。

对于指定坐标的赋值,我们使用itemset函数可以精确到某个像素,比如现在我只对蓝色像素的数值进行改变:import cv2

import numpy as np

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

#获取像素值

px = img[200,200]

print(px)

print(img.item(200,200,0))

img.itemset((200,200,0),100)

print(img.item(200,200,0))945abc48ed0c9ef1e0726c673f9ee248dcaf2802.png

可以看到,对于指定的颜色通道的赋值时完全可以的。

查看图像属性

现在将要对图像的各个属性进行研究,图像属性包括行数,列数和通道数;图像数据类型;像素数;等等。

对于一个图像,我们使用shape可以返回行数、列数以及颜色通道的元数:import cv2

import numpy as np

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

print(img.shape)a8a738bea478372e8d3dfa9625edc6a8e49287e5.png

输出的第三个数值代表的是图像的BGR三个通道的元数,也就是3。现在我们使用灰度图像做实验:import cv2

import numpy as np

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

img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

print(img.shape)

灰度图像在之后的教程中会进行讲解,这里先用做实验:feca0d2086491bb099decf932f9c19462c399999.png

可以看到,如果图像是灰度的,则返回的元组仅包含行数和列数,因此这是检查加载的图像是灰度还是彩色的好方法。

通过size可以返回当前图像的所有的像素点的总数:import cv2

import numpy as np

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

print(img.size)75403cc9347c0404836874e9b1eea49ca37056b2.png

图像的数据类型可以通过dtype获得:import cv2

import numpy as np

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

print(img.dtype)b7172df9e329ba41a99fd3086f8bce59ef86ac0f.png

imread函数默认读取图像的格式就是uint8,所以返回的全部都是这个格式。在以后我们学习深度学习框架时会发现,uint8的图像数据格式用来进行模型训练时,做数据归一化(预处理阶段)会导致精度缺失,最后导致分割精度下降。当然这是后话,我们现在不提。

如果我们想修改图像的格式,我们需要用到astype函数,现在将图像修改为float32格式的(这种格式的图像被广泛的应用于深度学习的模型训练):import cv2

import numpy as np

img = cv2.imread("cat.jpg").astype(np.float32)

print(img.dtype)85720caed9593d16f653fd8fa6892463af8770d4.png

dtype在调试时非常重要,因为OpenCV-Python代码中的大量错误是由无效的数据类型引起的,我们在以后的学习中会经常遇到这些问题。

图像ROI

对于图像中的特定区域的选取我们称之为ROI,其实际上就是对图像的xy坐标进行操作,我们来看示例:import cv2

import numpy as np

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

husky = img[1:240,60:270]

cv2.imshow("img",husky)

cv2.waitKey(0)

cv2.destroyAllWindows()02e695b3a9aa6fe2ae9240b8fddc4cffa9658d8b.png

本质相当于截取某一部分图片,现在我们来做一些有意思的操作,将截取部分覆盖到图像的其他地方,本质相当于前面讲过的像素修改:import cv2

import numpy as np

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

husky = img[1:240,60:270]

img[61:300,270:480] = husky

cv2.imshow("img",img)

cv2.waitKey(0)

cv2.destroyAllWindows()1609a296f9951c9ea660b425f71f3f938aefbecf.png

分割和合并图像通道

有时我们需要在B,G,R通道图像上单独进行操作。 在这种情况下,需要将BGR图像分割为单个通道。需要使用split函数与merge函数,它们的作用分别为分离和合并:

b,g,r = cv2.split(img) #拆分图像通道

img = cv2.merge((b,g,r))

此操作可以将BGR三通道分离出来,从而可以对某一通道进行操作,比如现在我们将R像素全部设置为0:import cv2

import numpy as np

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

b,g,r = cv2.split(img) #拆分图像通道

img[:,:,2] = 0

r = img[:,:,2]

img = cv2.merge((b,g,r))

cv2.imshow("img",img)

cv2.waitKey(0)

cv2.destroyAllWindows()

r则为R通道,看效果:f2ca5791b20581556989193bccbf52d60f9a0597.png

将红色通道去除后,我们的猫咪变的有点绿了。当然,大家还可以进行其他的通道的实验。

图像边框填充

如果要在图像周围创建边框(如相框),则可以使用函数cv2.copyMakeBorder()。它在卷积运算(很重要),零填充等方面有更多应用。此函数采用以下参数:

cv2.copyMakeBorder(src, top, bottom, left, right, borderType[, dst[, value]])

· src - 输入图像

· top,bottom,left,right - 相应方向上像素数的边框宽度

· value : cv2.BORDER_CONSTANT,cv2.BORDER_REFLECT,cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT ,cv2.BORDER_REPLICATE,cv2.BORDER_WRAP

·03789077d4c5ff366c26dffc1dc64e2cfbcc9b4b.png

cv2.BORDER_REFLECT_101或cv2.BORDER_DEFAULT - 与上面相同,但略有改动,如下所示:gfedcb | abcdefgh | gfedcba

cv.BORDER_REPLICATE - 最后一个像素在整个过程中被复制,像:aaaaaa |abcdefgh|hhhhhhh这样

cv.BORDER_WRAP - 对称方向 像素互换 就像: cdefgh|abcdefgh|abcdefg 这样。

我们来看代码:import cv2

from matplotlib import pyplot as plt

BLUE = [255,0,0]

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

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()

实验效果:c374f21d367178adce0dfcea436b48b380cd82e9.png

对于五个参数都进行了实验,可以看到明显的不同,当然,在这里为了方便图片对比显示,我们使用了matplotlib库,不过这属于python的知识,在这里就不一一介绍讲解了,大家也可以修改代码用OpenCV进行其他参数输出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值