OpenCV图像处理基础操作
Posted 1900_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV图像处理基础操作相关的知识,希望对你有一定的参考价值。
所用版本 OpenCV3.4.1.15
IDE:pycharm
读取图像
随便拿个图像即可实验,当然你也可以用这个在计算机视觉领域大名鼎鼎的图像 http://www.lenna.org/full/l_hires.jpg
(记得裁剪,要个头就行~~)
import cv2
import matplotlib as plt
import numpy as np
# 读取图像
img = cv2.imread("test.jpg")
# 展示图像 前面是窗口名 后面是要显示的图像
cv2.imshow("img",img)
# 等待时间 毫秒级 0表示任意键终止
cv2.waitKey(0)
# 图像大小 会输出[h w c] 高 宽 通道数
print(img.shape)
# 读取图像的时候 指定参数可以读取灰度图
img2 = cv2.imread("test.jpg",cv2.IMREAD_GRAYSCALE)
# 此时再输出shape就只有h w了 没有通道数
print(img2.shape)
# 展示灰度图
cv2.imshow("img2",img2)
cv2.waitKey(0)
# 图像保存 指定一个名字 指定要保存的图像
cv2.imwrite("huidu.jpg",img2)
有的时候图像大小比较大,所以显示出来一个屏幕看不全,就比较麻烦。
我们可以先设置窗口大小,再在指定窗口显示图像
# set window size
cv2.namedWindow("dst",0);
cv2.resizeWindow("dst",1280,760);
cv2.imwrite("dst.png",dst);
图像裁剪和颜色通道切分
img = cv2.imread("test.jpg")
# 截取部分图像
s = img[0:200,0:200] # 前面是h 后面是w
cv2.imshow("img",s)
cv2.waitKey(0)
# 颜色通道切分 b g r分别是三个通道的值
b,g,r=cv2.split(img)
# opencv里面图像的通道顺序是B G R
# 也就意味着 B G R顺序分别是 0 1 2
# [:,:,0] 切片 前面俩冒号 代表取图像宽高的所有 后面0 代表B通道
cur_img=img.copy()
cur_img[:,:,0]=0 # B通道置为0
cur_img[:,:,1]=0 # G通道置为0
cv2.imshow("R",cur_img) # 也就是说只保留了R通道
cv2.waitKey(0)
读取视频
import cv2
import matplotlib as plt
import numpy as np
# 读取视频 也可以读取摄像头
vc = cv2.VideoCapture("test.mp4")
# 检查是否打开正确
if vc.isOpened():
# .read 读取第一帧 会返回两个值 open是布尔值表示是否读成功 第二个参数就是当前帧
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",frame)
if cv2.waitKey(100) & 0xFF ==27: # 每处理完一帧 等待100毫秒 27代表esc键 按esc退出
break
vc.release()
cv2.destroyAllWindows() #销毁所有窗口
图像边界填充
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread("test.jpg")
# 边界填充
# 定义要填充的大小 上下左右
top_size,bottom_size,left_size,right_size = (50,50,50,50)
# copyMakeBorder 边界填充函数 参数分别是:要填充的图像,上,下,左,右,边界类型
# BORDER_REPLICATE 复制法 就是复制最边缘的像素 作为填充
replicate = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REPLICATE)
# BORDER_REFLECT 反射法 把像素在两边进行复制 如 edcba | abcde | edcba
reflect = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REFLECT)
# BORDER_REFLECT_101 反射法 以最边缘的像素为轴 对称 edcb | abcde | dcba
reflect_101 = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_REFLECT_101)
# BORDER_WRAP 外包装法 右边正着往外延申,左边倒着延申 edcba | abcde | abcde
wrap = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_WRAP)
# 常量法 指定一个数值作为填充
constant = cv2.copyMakeBorder(img,top_size,bottom_size,left_size,right_size,borderType=cv2.BORDER_CONSTANT,value=0)
# 使用matplotlib把图像显示出来
plt.subplot(2,3,1),plt.imshow(img,"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(reflect_101,"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()
显示结果如下:
你会发现,这个图是蓝色的。为什么呢?
使用cv2.imread()
读取图像时,默认彩色图像的三通道顺序为B、G、R,这与我们所熟知的RGB中的R通道和B通道正好互换位置了。
而使用plt.imshow()
函数却默认显示图像的通道顺序为R、G、B,所以导致出现色差发蓝
很好解决,用我们前边所说的,图像通道分离。
# 通道分离
b,g,r=cv2.split(img)
# 换下位置 合并 再用matplotlib显示
img_new=cv2.merge([r,g,b])
# 前面这三个参数,代表 2行3列布局,当前图位于第一个
plt.subplot(2,3,1),plt.imshow(img_new,"gray"),plt.title('ORIGINAL')
# 2行3列布局,当前图位于第二个 可以不加逗号
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(reflect_101,"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()
可以看到,图像颜色正常了(我就不每个都处理了,明白用法即可)
数值计算
import cv2
import matplotlib as plt
import numpy as np
img_cat=cv2.imread('cat.png')
# 这里对图像做数值加法 其实就是对每个像素+10 这和numpy的矩阵加法是一样的
# 如果加法完了超过了255 那就把结果对256取模 %
cv2.imshow('ans',img_cat+10)
cv2.waitKey(0)
# opencv里面的图像相加与刚才numpy那种加法不一样
img=cv2.imread('test.jpg')
# 这个加法会把两个图像的对应像素相加 若超过255 则直接置为255
# 注意这样相加必须要求两个图象大小一致
print(cv2.add(img,img_cat))
图像融合以及重新设置大小
两个图必须一样大小才能融合
import cv2
import matplotlib.pyplot as plt
import numpy as np
img_cat=cv2.imread('cat.png')
img_dog=cv2.imread('dog.png')
print(img_dog.shape)
print(img_cat.shape)
# resize 重新设置大小
img_cat = cv2.resize(img_cat,(435,400))
print(img_cat.shape)
# 图像相加的公式是 R=a*x1+b*x2+c x1 x2代表两个图像 a b是两个参数 c是偏置项
# 这里a=0.4 b=0.6 c=0
res = cv2.addWeighted(img_cat,0.4,img_dog,0.6,0)
plt.imshow(res)
plt.show()
# 大小设置为0 0 fx和fy分别代表x方向拉长几倍 y方向拉长几倍
# res = cv2.resize(img_cat,(0,0),fx=1,fy=2)
# plt.imshow(res)
# plt.show()
结果(变蓝色是因为通道的问题)
阈值
ret,dst = cv2.threshold(src,thresh,maxval,type)
src 输入图 只能输入单通道图,一般为灰度图
dst 输出图
thresh 阈值
maxval 当像素值超过了阈值(小于阈值,根据type来决定),就赋值为maxval
type 二值化的操作 包含以下五种类型
cv2.THRESH_BINARY 超过阈值的部分赋值为maxval 否则取0
cv2.THRESH_BINARY_INV THRESH_BINARY的反转(本来比如是大于127的赋值为255,反转就是小于127的赋值为255)
cv2.THRESH_TRUNC 大于阈值部分设置为阈值 否则不变
cv2.THRESH_TOZERO 大于阈值部分不改变 否则设置为0
cv2.THRESH_BINARY_INV THRESH_TOZERO的反转
代码:
# 读进来灰度图
img=cv2.imread("cat.png",cv2.IMREAD_GRAYSCALE)
# 阈值为127 像素超过127就取255 否则取0
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
titles=['Original','THRESH_BINARY','THRESH_BINARY_INV','THRESH_TRUNC','THRESH_TOZERO','THRESH_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()
解释下这个plt.imshow(images[i],'gray')
plt.imshow(images,cmap)
images是要绘制的图像或数组,cmap是颜色图谱,默认绘制RGB颜色空间,也可以设定gray代表黑-白
显示效果
以上是关于OpenCV图像处理基础操作的主要内容,如果未能解决你的问题,请参考以下文章