在学习opencv前,我们首先要安装opencv的库函数。
conda install opencv-python
然后就会出现报错:
PackagesNotFoundError: The following packages are not available from current channels:
Current channels:
To search for alternate channels that may provide the conda package you’re
looking for, navigate to https://anaconda.org and use the search bar at the top of the page.
这个大概就是现在opencv库不支持这样安装了,需要我们找到对应的版本进行安装
conda install --channel https://conda.anaconda.org/menpo opencv
安装过程出错PermissionError
大概原因是有一些文件被anaconda(或其他一些进程)锁定,opencv可能需要读写这个文件
关闭anaconda,spyder的所有相关进程。
先在Anaconda Prompt窗口输入如下命令:
conda update --all
然后就会出现一些要更新的包,下载的包什么的,反正全部yes就行了
再在Anaconda Prompt窗口输入如下命令:
conda install --channel https://conda.anaconda.org/menpo opencv
过一会儿也会让你输入[y/n]:
直接y就行了。等命令执行完anaconda也就安装好cv2库了
Anaconda的代码提醒太慢了,我还是用pycharm,上面的只是给使用Anaconda的童鞋们看的。
import cv2
img = cv2.imread("D:/conda programs/snack2.png") # 读取图像文件(完整文件名)
# cv2.namedWindow("she") # 为窗口命名(其实不需要,下面显示图像的时候也要给窗口命名)
cv2.imshow("she", img) # 显示图像。第一个参数是窗口名,第二个参数就是刚才读入的图像
cv2.waitKey(0) # 参数为窗口等待时间,如果没有这行代码没有,会直接一闪而过。
# 当该参数值小于0时,为等待单击。 参数大于0时,为等待时间。 参数等于0或没有参数则无限等待。
cv2.destroyAllWindows() # 销毁所有窗口,不再占用内存。
注意:python读取和保存文件名中间的分割符与Windows默认的“\”不一样,python读取保存图像中间的分隔符为“/”或“\”
便可以显示图片啦!(姐姐)
cv2.imwrite("C:/Users/Zhang-Lei/Desktop/snack.png", img) # 保存图像。参数为要保存的完整文件名和读入的图像
我将上面的图像转为灰度图,保存为"C:/Users/Zhang-Lei/Desktop/snack_gray.png",然后读取其中某个点的像素值
img = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack_gray.png")
pixel = img[100, 100]
print(pixel)
结果:
结果为什么会是三个数字呢?
opencv读取图像时会改变图片的格式。
那么如何读取图像时不改变图片格式呢?
读取图像时加入参数cv2.IMREAD_UNCHANGED
img = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack_gray.png", cv2.IMREAD_UNCHANGED)
pixel = img[100, 100]
print(pixel)
img = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack.png")
blue_pixel = img[100, 100, 0] # 第三个参数代表通道数,0表示blue通道
green_pixel = img[100, 100, 1] # 1表示green通道
red_pixel = img[100, 100, 2] # 2表示red通道
print(blue_pixel, '\n', green_pixel, '\n', red_pixel)```
img[100, 100, 0] = 255
img[100, 100, 1] = 255
img[100, 100, 2] = 255
print(img[100, 100])
分别将三个通道的像素值都设置为255
img[100, 100] = [0, 0, 0]
print(img[100, 100])
同时将三通道的像素值都设置为0
img[100:150, 100:150] = [255, 255, 255]
cv2.imshow("she", img)
cv2.waitKey()
cv2.destroyAllWindows()
显示结果:
区域内的所有通道像素值都是255,因此该区域为白色。
blue = img.item(100, 100, 0)
green = img.item(100, 100, 1)
red = img.item(100, 100, 2)
print(blue, '\n', green, '\n', red)
注意,彩色图不可以直接使用item查看三通道的像素值,否则会报错,报错如下:
incorrect number of indices for array
img.itemset((100, 100, 0), 255)
img.itemset((100, 100, 1), 255)
img.itemset((100, 100, 2), 255)
print(img.item(100, 100, 0))
print(img.item(100, 100, 1))
print(img.item(100, 100, 2))
img = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack.png")
print(img.shape)
print(img.size)
print(img.dtype)
结果:
关于数据类型,整型浮点型里面还有细分,这里就不多说了。
cv2.imshow("face", img[100:400, 200:400])
cv2.waitKey()
cv2.destroyAllWindows()
下面我们将脸部图像复制到图像的下方
img[500:800, 200:400] = img[100:400, 200:400]
cv2.imshow("demo", img)
cv2.waitKey()
cv2.destroyAllWindows()
b, g, r = cv2.split(img)
cv2.imshow("blue", b)
cv2.imshow("green", g)
cv2.imshow("red", r)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
可以看到,b, g, r三通道的图像都被提取了出来
注意:cv.spilt()是一项代价高昂的操作(就时间而言)。所以只有在你需要时才这样做,否则就使用 Numpy 索引。
即:
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
new_img = cv2.merge((b, g, r))
cv2.imshow("new", new_img)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
可以看到,三通道的图片合并在一起成了一张新图片。
应用于在图像周围创建边框,例如相框效果。
cv2.copyMakeBorder(src, top, bottom, left, right, borderType, [value])
borderType的类型可以是如下几种:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack_gray.png")
Blue = [0, 0, 255]
replicate = cv2.copyMakeBorder(img, 100, 100, 100, 100, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, 100, 100, 100, 100, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, 100, 100, 100, 100, cv2.BORDER_DEFAULT)
wrap = cv2.copyMakeBorder(img, 100, 100, 100, 100, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, 100, 100, 100, 100, cv2.BORDER_CONSTANT, value=Blue)
plt.figure(figsize=(12, 12))
plt.subplot(2, 3, 1)
plt.imshow(img)
plt.title("Original")
plt.subplot(2, 3, 2)
plt.imshow(replicate)
plt.title("Replicate")
plt.subplot(2, 3, 3)
plt.imshow(reflect)
plt.title("Reflect")
plt.subplot(2, 3, 4)
plt.imshow(reflect101)
plt.title("Reflect101")
plt.subplot(2, 3, 5)
plt.imshow(wrap)
plt.title("Wrap")
plt.subplot(2, 3, 6)
plt.imshow(constant)
plt.title("Constant")
plt.show()
结果:
可以看到除了第一张初始图象外,其他五张的边界都发生了一些变化。
结果图像=图像1+图像2
通过 OpenCV 函数,cv2.add()或简单地通过 numpy 操作将两个图像相加,res = img1 + img2。两个图像应该具有相同的深度和类型,或者第二个图像可以是像素值,比如(255,255,255),白色值。
图像操作代码示例:
img = cv2.imread('C:/Users/Zhang-Lei/Desktop/snack_gray.png')
img_add1 = cv2.add(img, img)
img_add2 = img + img
cv2.imshow('original', img)
cv2.imshow('add1', img_add1)
cv2.imshow('add2', img_add2)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
注意:注OpenCV相加操作和 Numpy 相加操作之间存在差异。OpenCV 添加是饱和操作,而 Numpy 添加是模运算。要注意的是,两种加法对于结果溢出的数据,会通过某种方法使其在限定的数据范围内。
代码示例:
import cv2
import numpy as np
x = np.uint8([250])
y = np.uint8([10])
print(cv2.add(x, y))
print(x + y)
结果:
cv2.add()操作中:250+10 = 260 > 255 => 255
直接相加操作中:(250+10)% 256 = 4
结果图像=图像1*系数1+图像2*系数2+亮度调节量
cv.addWeighted(src1, alpha, src2, beta, gamma)
注意:参数gamma不能省略
也就是将图像相加,但是对图像赋予不同的权重,从而给出混合感或透明感。
注意:这里想要混合的两个图像尺寸,类型必须完全相同,否则将报错。
报错如下:
error: (-209:Sizes of input arguments do not match) The operation is neither ‘array op array’ (where arrays have the same size)
代码示例:
img1 = cv2.imread('C:/Users/Zhang-Lei/Desktop/5.jpg')
img2 = cv2.imread('C:/Users/Zhang-Lei/Desktop/6.jpg')
res = cv2.addWeighted(img1, 0.3, img2, 0.7, 0)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('res', res)
cv2.waitKey()
cv2.destroyAllWindows()
可以看到,两个图像按照一定的比例融合在一起。
这包括按位 AND(与),OR(或),NOT(非) 和 XOR(异或) 运算。它们在提取图像的某一部分、定义和使用非矩形 ROI 等方面非常有用。
假如我想加一个OpenCV的 logo在一个图像上,如果只是简单的将两张图像想加,则会改变叠加处的颜色。如果进行上面所说的混叠操作,则会得到一个有透明效应的结果,但我希望得到一个不透明的logo。如果logo是一个矩形logo,那可以用上节所讲的ROI来做。但是OpenCV的logo是不规则形状的,所以用下面的bitwise操作来进行。
img1 = cv2.imread('C:/Users/Zhang-Lei/Desktop/snack.png')
img2 = cv2.imread('C:/Users/Zhang-Lei/Desktop/opencv.jpg')
rows, cols, channels = img2.shape
roi = img1[:rows, :cols]
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 200, 255, cv2.THRESH_BINARY) # 二值化,使ROI中的徽标区域变黑
cv2.imshow('mask', mask)
cv2.waitKey()
cv2.destroyAllWindows()
mask_inv = cv2.bitwise_not(mask) # 非运算,黑白反转
cv2.imshow('mask_inv', mask_inv)
cv2.waitKey()
cv2.destroyAllWindows()
img1_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)
img2_fg = cv2.bitwise_and(img2, img2, mask=mask_inv)
cv2.imshow('img1_bg', img1_bg) # 仅从徽标图像中获取徽标区域。
cv2.imshow('img2_fg', img2_fg) # 在ROI 中放置徽标并修改主图像
cv2.waitKey()
cv2.destroyAllWindows()
res = cv2.add(img1_bg, img2_fg)
img1[:rows, :cols] = res
cv2.imshow('res', res)
cv2.imshow('img1', img1)
cv2.waitKey()
cv2.destroyAllWindows()
可见,我在蛇姐的图片上做了一个不透明的opencv的logo。
BGR = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack.png")
RGB = cv2.cvtColor(BGR, cv2.COLOR_BGR2RGB) # BGR图像转RGB图像
cv2.imshow("BGR", BGR)
cv2.imshow("RGB", RGB)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
BGR = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack.png")
GRAY = cv2.cvtColor(BGR, cv2.COLOR_BGR2GRAY) # BGR图像转灰度图
cv2.imshow("BGR", BGR)
cv2.imshow("GRAY", GRAY)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
BGR = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack.png")
GRAY = cv2.cvtColor(BGR, cv2.COLOR_BGR2GRAY) # BGR图像转灰度图
BGR2 = cv2.cvtColor(GRAY, cv2.COLOR_GRAY2BGR) # 灰度图转BGR图像
cv2.imshow("GRAY", GRAY)
cv2.imshow("BGR2", BGR2)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
这在图像上可能看不出什么变化,但我们可以答应出图像的尺寸看看它们之间的区别。
print(GRAY.shape)
print(BGR2.shape)
BGR = cv2.imread("C:/Users/Zhang-Lei/Desktop/snack.png")
GRAY = cv2.cvtColor(BGR, cv2.COLOR_BGR2GRAY) # BGR图像转灰度图
RGB2 = cv2.cvtColor(GRAY, cv2.COLOR_GRAY2RGB) # 灰度图转RGB图像
cv2.imshow("GRAY", GRAY)
cv2.imshow("RGB2", RGB2)
cv2.waitKey()
cv2.destroyAllWindows()
结果:
与上面灰度图转BGR图像同理,从图像上看不出变化,但通道数为3。