数据图像格式
cv2.IMREAD_COLOR
: 彩色图像
cv2.IMREAD_GRAYSCALE
: 灰度图像
读取图像方法
img = cv2.imread('cat.jpg')
输出图像
img
[out]:
#[h,w,c]
array([
[[100,100,100],[200,200,200],[300,300,300]…,[900,900,900]],
[[111,111,111],[222,222,222],[333,333,333]…,[999,999,999]],
[[123,123,123],[234,234,234],[345,345,345]…,[789,789,789]]
],dtype=unit8)
显示图像
cv2.imshow('image_name',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像数据大小与格式
img.shape
[out]:
(414,500,3)
#也就是上面的[h,w,c],c就是代表BGR
读取为灰度图
img = cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)
img
[out]:
array([
[100,200,300,…,900],
[111,222,333,…,999],
…
[123,456,789,…,012]
],dtype=unit8)
保存图像
cv2.imwrite('mycat.png',img)
查看图像的格式
type(img)
[out]:numpy.ndarray
查看图像的大小
img.size
[out]:
207000
查看图像的dtype
img.dtype
[out]:
dype('unit8')
读取视频
cv2.VideoCapture可以捕获摄像头,用数字来控制不同的设备,例如0,1。
如果是视频文件,直接指定好路径即可。
vc = cv2.VideoCapture('test.mp4')
# 检查是否打开正确
if vc.isOpened():
open, frame = vc.read()
else:
open = False
#%%
while open:
ret, frame = vc.read()
if frame is None:
break
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('result', gray)
if cv2.waitKey(100) & 0xFF == 27:
break
vc.release()
cv2.destroyAllWindows()
截取部分图像数据
img = cv2.imread('cat.jpg`)
cat = img[0:200,0:200]
cv_show('cat',cat)
颜色通道提取
b,g,r = cv2.split(img)
b
[out]:
array([[160, 164, 169, ..., 185, 184, 183],
[126, 131, 136, ..., 184, 183, 182],
[127, 131, 137, ..., 183, 182, 181],
...,
[198, 193, 178, ..., 206, 195, 174],
[176, 183, 175, ..., 188, 144, 125],
[190, 190, 157, ..., 200, 145, 144]], dtype=uint8)
颜色的合并
img = cv2.merge((b,g,r))
只保留R(其余通道置为0)
cur_img = img.copy()
cur_img[:,:,0] = 0
cur_img[:,:,1] = 0
cv_show('R',cur_img)
边界填充(周围扩大一圈)
# 先定义一下填充的大小
top_size,bottom_size,left_size,right_size = (50,50,50,50)
# 不同的填充方法
replicate = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderType=cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size,cv2.BORDER_CONSTANT, value=0)
<img src="http://img.yibogame.com/uPic/2022-04-18-21-54-56-1650290096178-2022-04-18-18-58-55-1650279535945-output.png" alt="image-20220418205212143" />
BORDER_REPLICATE
:复制法,也就是复制最边缘像素。
BORDER_REFLECT
:反射法,对感兴趣的图像中的像素在两边进行复制例如:fedcba|abcdefgh|hgfedcb
BORDER_REFLECT_101
:反射法,也就是以最边缘像素为轴,对称,gfedcb|abcdefgh|gfedcba
BORDER_WRAP
:外包装法cdefgh|abcdefgh|abcdefg
BORDER_CONSTANT
:常量法,常数值填充。
数值计算
img_cat = cv2.imread('cat.jpg')
img_dog = cv2.imread('dog.jpg')
img_cat[:5,:,0]
[out]:
array([[142, 146, 151, ..., 156, 155, 154],
[107, 112, 117, ..., 155, 154, 153],
[108, 112, 118, ..., 154, 153, 152],
[139, 143, 148, ..., 156, 155, 154],
[153, 158, 163, ..., 160, 159, 158]], dtype=uint8)
img_cat2= img_cat +10
img_cat[:5,:,0]
[out]:
array([[152, 156, 161, ..., 166, 165, 164],
[117, 122, 127, ..., 165, 164, 163],
[118, 122, 128, ..., 164, 163, 162],
[149, 153, 158, ..., 166, 165, 164],
[163, 168, 173, ..., 170, 169, 168]], dtype=uint8)
#相当于 %(取余) 256
(img_cat + img_cat2)[:5,:,0]
[out]:
array([[ 38, 46, 56, ..., 66, 64, 62],
[224, 234, 244, ..., 64, 62, 60],
[226, 234, 246, ..., 62, 60, 58],
[ 32, 40, 50, ..., 66, 64, 62],
[ 60, 70, 80, ..., 74, 72, 70]], dtype=uint8)
cv2.add(img_cat,img_cat2)[:5,:,0]
[out]:
array([[255, 255, 255, ..., 255, 255, 255],
[224, 234, 244, ..., 255, 255, 255],
[226, 234, 246, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255]], dtype=uint8)
图像融合
img_cat + img_dog
[out]:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-111-ffa3cdc5d6b8> in <module>()
----> 1 img_cat + img_dog
ValueError: operands could not be broadcast together with shapes (414,500,3) (429,499,3)
因为两个大小不一样,报错了!那先看看img_cat
的大小:
img_cat.shape
[out]:
(414, 500, 3)
把狗变为猫那么大:
img_dog = cv2.resize(img_dog, (500, 414))
img_dog.shape
[out]:
(414, 500, 3)
# Result = αx1 + βx2 + b(x1:猫,x2:狗,b:偏移量,α、β:权重)
res = cv2.addWeighted(img_cat, 0.4, img_dog, 0.6, 0)
plt.imshow(res)
<img src="http://img.yibogame.com/uPic/2022-04-18-18-58-49-1650279529590-output1.png" alt="image-20220418205212143" />
图像阈值处理
ret, dst = cv2.threshold(src, thresh, maxval, type)
src
: 输入图,只能输入单通道图像,通常来说为灰度图
dst
: 输出图
thresh
: 阈值
maxval
: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
type
:二值化操作的类型,包含以下5种类型:
cv2.THRESH_TOZERO_INV
cv2.THRESH_BINARY
超过阈值部分取maxval
(最大值),否则取0
cv2.THRESH_BINARY_INV
是 THRESH_BINARY
的反转
cv2.THRESH_TRUNC
大于阈值部分设为阈值,否则不变
cv2.THRESH_TOZERO
大于阈值部分不改变,否则设为0
cv2.THRESH_TOZERO_INV
是THRESH_TOZERO
的反转
ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
<img src="http://img.yibogame.com/uPic/2022-04-18-18-58-44-1650279524214-output3.png" alt="image-20220418205212143" />
图像平滑处理
<img src="http://img.yibogame.com/uPic/2022-04-18-18-58-37-1650279517969-input1.png" alt="input1" style="zoom:50%;" />
img = cv2.imread('lenaNoise.png')
原始带噪点图像:
<img src="http://img.yibogame.com/uPic/2022-04-18-20-49-04-1650286144073-lenaNoise.png" alt="lenaNoise" style="zoom:50%;" />
# 均值滤波(121+75+78+……+235)/9
# 简单的平均卷积操作
blur = cv2.blur(img, (3, 3))
cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
均值滤波输出的结果:
<img src="http://img.yibogame.com/uPic/2022-04-18-20-52-12-1650286332261-image-20220418205212143.png" alt="image-20220418205212143" style="zoom: 25%;" />
# 方框滤波
# 基本和均值一样,可以选择归一化(与上图一样)
box = cv2.boxFilter(img,-1,(3,3), normalize=True)
cv2.imshow('box', box)
cv2.waitKey(0)
cv2.destroyAllWindows()
方框滤波输出的结果(归一化):
<img src="http://img.yibogame.com/uPic/2022-04-18-20-52-12-1650286332261-image-20220418205212143.png" alt="image-20220418205212143" style="zoom: 25%;" />
# 方框滤波
# 基本和均值一样,可以选择归一化,容易越界(超过255。当超过255后就是255)
box = cv2.boxFilter(img,-1,(3,3), normalize=False)
cv2.imshow('box', box)
cv2.waitKey(0)
cv2.destroyAllWindows()
方框滤波输出的结果(不归一化):
<img src="http://img.yibogame.com/uPic/2022-04-18-20-55-19-1650286519100-image-20220418205518999.png" alt="image-20220418205518999" style="zoom: 25%;" />
# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian = cv2.GaussianBlur(img, (5, 5), 1)
cv2.imshow('aussian', aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
高斯滤波的函数图像:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-04-07-1650287047640-image-20220418210407535.png" alt="image-20220418210407535" style="zoom:50%;" />
高斯滤波的卷积核大概类似于这样(越中间影响越大):
<img src="http://img.yibogame.com/uPic/2022-04-18-21-01-58-1650286918084-image-20220418210157986.png" alt="image-20220418210157986" style="zoom:50%;" />
高斯滤波输出的结果:
<img src="http://img.yibogame.com/uPic/2022-04-18-20-59-36-1650286776559-image-20220418205936456.png" alt="image-20220418205936456" style="zoom:25%;" />
# 中值滤波(把121,75,78,……,235按数值大小排序,再取中间的那个值)
# 相当于用中值代替
median = cv2.medianBlur(img, 5) # 中值滤波
cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()
中值滤波输出的结果:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-09-00-1650287340845-image-20220418210900722.png" alt="image-20220418210900722" style="zoom:25%;" />
# 展示所有的
res = np.hstack((blur,aussian,median))
# 垂直展示也行:
# res = np.vstack((blur,aussian,median))
cv2.imshow('median vs average', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
hstack
方式输出结果:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-16-04-1650287764298-image-20220418211604185.png" alt="image-20220418211604185" style="zoom:25%;" />
形态学----腐蚀(erode)
img = cv2.imread('res/dige.png')
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
原始图像:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-25-15-1650288315808-image-20220418212515704.png" alt="image-20220418212515704" style="zoom:35%;" />
#3*3的卷积核
kernel = np.ones((3, 3), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
腐蚀后的图像:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-25-37-1650288337151-image-20220418212537049.png" alt="image-20220418212537049" style="zoom:35%;" />
pie = cv2.imread('res/pie.png')
cv2.imshow('pie', pie)
cv2.waitKey(0)
cv2.destroyAllWindows()
腐蚀卷积核:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-38-46-1650289126077-image-20220418213845958.png" alt="image-20220418213845958" style="zoom:35%;" />
#30*30的卷积核
kernel = np.ones((30, 30), np.uint8)
#腐蚀1、2、3次
erosion_1 = cv2.erode(pie, kernel, iterations=1)
erosion_2 = cv2.erode(pie, kernel, iterations=2)
erosion_3 = cv2.erode(pie, kernel, iterations=3)
res = np.hstack((erosion_1, erosion_2, erosion_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
腐蚀1、2、3次的结果图:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-39-49-1650289189888-image-20220418213949773.png" alt="image-20220418213949773" style="zoom:35%;" />
形态学----膨胀(dilate)
img = cv2.imread('res/dige.png')
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
原始图像:
<img src="http://img.yibogame.com/uPic/2022-04-18-21-25-15-1650288315808-image-20220418212515704.png" alt="image-20220418212515704" style="zoom:35%;" />
# 先腐蚀一次
kernel = np.ones((3, 3), np.uint8)
dige_erosion = cv2.erode(img, kernel, iterations=1)
cv2.imshow('dige_erosion', dige_erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
腐蚀后输出图像(减肥):
<img src="http://img.yibogame.com/uPic/2022-04-18-21-25-37-1650288337151-image-20220418212537049.png" alt="image-20220418212537049" style="zoom:35%;" />
# 再膨胀一次
kernel = np.ones((3, 3), np.uint8)
dige_dilate = cv2.dilate(dige_erosion, kernel, iterations=1)
cv2.imshow('dilate', dige_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
膨胀后输出图像(增肥):
<img src="http://img.yibogame.com/uPic/2022-04-18-21-49-44-1650289784890-image-20220418214944784.png" alt="image-20220418214944784" style="zoom:35%;" />
# 原图就不展示了,就是上面那个圆
pie = cv2.imread('res/pie.png')
kernel = np.ones((30, 30), np.uint8)
dilate_1 = cv2.dilate(pie, kernel, iterations=1)
dilate_2 = cv2.dilate(pie, kernel, iterations=2)
dilate_3 = cv2.dilate(pie, kernel, iterations=3)
res = np.hstack((dilate_1, dilate_2, dilate_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
<img src="http://img.yibogame.com/uPic/2022-04-18-21-52-02-1650289922866-image-20220418215202759.png" alt="image-20220418215202759" style="zoom:50%;" />