opencv-python学习之旅
opencv-python 操作
*注:在此笔记中只记录下各种函数的使用,规则
详细讲解见https://opencv.apachecn.org/#/docs/4.0.0/2.1-tutorial_py_image_display
创建,读取,显示,保存图像
创建图像
import numpy as np
img = np.zeros((512,512,3),np.uint8) # 创建一个图像 ,3 是指三个通道,可传入RGB
读取图像
cv2.imread(“本工作目录下的文件名”,-1或0或1) # -1:加载图像,包括alpha通道,0:灰色模式加载图像,1:默认正常模式加载
显示图像
cv.imshow('image', img) # imshow("窗口名字",要显示的图像)
cv.waitKey(0)
cv.destroyAllWindows()
cv.waitKey() 是一个键盘绑定函数,它的参数是以毫秒为单位的时间。该函数为任意键盘事件等待指定毫秒。如果你在这段时间内按下任意键,程序将继续。如果传的是 0,它会一直等待键盘按下。它也可以设置检测特定的击键,例如,按下键 a 等,我们将在下面讨论。
Note
除了绑定键盘事件,该函数还会处理许多其他 GUI 事件,因此你必须用它来实际显示图像。
cv.destroyAllWindows() 简单的销毁我们创建的所有窗口。如果你想销毁任意指定窗口,应该使用函数 cv.destroyWindow() 参数是确切的窗口名。
eg.下面的程序以灰度模式读取图像,显示图像,如果你按下 's‘ 会保存和退出图像,或者按下 ESC 退出不保存。
import numpy as np
import cv2 as cv
img = cv.imread('messi5.jpg',0)
cv.imshow('image',img)
k = cv.waitKey(0)
if k == 27: # ESC 退出
cv.destroyAllWindows()
elif k == ord('s'): # 's' 保存退出
cv.imwrite('messigray.png',img)
cv.destroyAllWindows()
Note
有一种特殊情况,你可以先创建一个窗口然后加载图像到该窗口。在这种情况下,你能指定窗口是否可调整大小。它是由这个函数完成的 cv.namedWindow()。默认情况下,flag 是 cv.WINDOW_AUTOSIZE。但如果你指定了 flag 为 cv.WINDOW_NORMAL,你能调整窗口大小。当图像尺寸太大,在窗口中添加跟踪条是很有用的。
看下面的代码:
cv.namedWindow('image', cv.WINDOW_NORMAL)
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()
保存图像
保存图像,用这个函数 cv.imwrite()。
第一个参数是文件名,第二个参数是你要保存的图像。
cv.imwrite('messigray.png',img)
将该图像用 PNG 格式保存在工作目录。
使用 Matplotlib
Matplotlib 是一个 Python 的绘图库,提供了丰富多样的绘图函数。你将在接下来的文章中看到它们。在这里,你将学习如何使用 Matplotlib 来显示图像。你还能用 Matplotlib 缩放图像,保存图像等。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') # 让图像以灰色形式展示
# 或者选择 plt.imshow(img[:,:,::-1]) #这一步操作,保证和原图像显示的色彩一致
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值 去掉则会显示刻度
plt.show()
色彩模式与cv2不一样(BGR),因此显示出来的颜色不对,需要改一下
plt.imshow(img[:,:,::-1]) #这一步操作,保证和原图像显示的色彩一致
plt.show()
图像的绘制功能
画线
去画一条线,你需要传递线条的开始和结束的坐标。我们将创建一个黑色图像,并在坐上角到右下角画一条蓝色的线
import numpy as np
import cv2 as cv
# 创建一个黑色的图像
img = np.zeros((512,512,3), np.uint8)
# 画一条 5px 宽的蓝色对角线
cv.line(img,(0,0),(511,511),(255,0,0),5)
cv2.line(图像,(起始坐标),(终点坐标),(颜色),宽度)
画圆
画一个圆,你需要它的圆心和半径。我们将在上面绘制的矩形上画一个内圆。
cv.circle(img,(447,63), 63, (0,0,255), -1)
cv.circle(图像,(圆心坐标x,y),半径,(颜色),加载方式)
画椭圆
画一个椭圆,你需要传好几个参数。一个参数是圆心位置 (x,y)。下个参数是轴的长度 (长轴长度,短轴长度)。角度是椭圆在你逆时针方向的旋转角度。startAngle 和 endAngle 表示从长轴顺时针方向测量的椭圆弧的起点和终点。如整圆就传 0 和 360。更多细节请看 cv.ellipse() 的文档。下面是在这个图像中间画的一个半椭圆例子。
cv.ellipse(img,(256,256),(100,50),0,0,180,(0,255,255),-1)
cv.ellipse(图像,(圆心坐标),(长轴,短轴),起时角度,起点,终点,颜色,加载方式
画矩形
cv.rectangle(img,左上角坐标,右下角坐标,颜色,线条厚度)
画多边形
画多边形,首先你需要顶点的做坐标。将这些点组成一个形状为 ROWSx1x2 的数组,ROWS 是顶点数,它应该是 int32 类型。这里我们绘制一个顶点是黄色的小多边形。
pts = np.array([[10,5],[20,30],[70,20],[50,10]], np.int32)
pts = pts.reshape((-1,1,2))
cv.polylines(img,[pts],True,(0,255,255))
Note
- 如果地三个是 False,你将获得所有点的折线,而不是一个闭合形状。
- cv.polylines() 能画很多线条。只需创建你想绘制所有线条的列表,然后将其传给这个函数。所有线条都将单独绘制。绘制一组线条比调用 cv.line() 好很多,快很多。
绘图添加文字
cv.putText(img,输入内容,文本的放置位置,字体,字体大小,颜色,线条宽度,cv.LINE__AA)
访问并修改像素点
通过行列坐标来进行访问及修改
黄色为绿色和红色的混合。所以,该图像的所有像素值都应为R=255,G=255,B=0。
>>> import numpy as np
>>> import CV2
>>> img = CV2.imread("img/yellow.jpg")
>>> h,w,c = img.shape
#图像大小为128*128*3
>>> print(h,w,c)
128 128 3
px = img[100,100] # 获取某个点的像素值
从上面的代码中可以看到,您可以通过行和列坐标访问像素值。注意,对于常见的RGB 图像,OpenCV的imread函数返回的是一个蓝色(Blue)值、绿色(Green)值、红色(Red)值的数组,维度大小为3。而对于灰度图像,仅返回相应的灰度值。
>>> img[100,100]
#OpenCV的读取顺序为B,G,R,由于图像所有像素为黄色,因此,G=255,R=255
array([ 0, 255, 255], dtype=uint8)
# 仅访问蓝色通道的像素
>>> blue = img[100,100,0]
>>> print(blue)
0
你也可以使用同样的方法来修改像素值。
>>> img[100,100] = [255,255,255]
>>> print(img[100,100])
[255 255 255]
访问属性
图像大小
img.shape # 变量.shape
(256,256,3)
img.shape[:2] 取彩色图片的长、宽。
- 使用彩色模式传参时
cols,rows = img.shape[:2]
# 或者
cols,rows,x = img.shape
-
使用灰色模式
cols ,rows = img.shape
如果img.shape[:3] 则取彩色图片的长、宽、通道。
关于img.shape[0]、[1]、[2]
img.shape[0]:图像的垂直尺寸(高度)
img.shape[1]:图像的水平尺寸(宽度)
img.shape[2]:图像的通道数
数据类型
img.dtype
dtype('uint8')
像素点数量
img.size
196608
图像的裁剪、拼接、翻转、缩放等 [(https://blog.csdn.net/zh_jessica/article/details/77946346)]
缩放:
一、图像缩放
图像缩放主要使用resize函数
result = cv2.resize(src, dsize[, result[. fx[, fy[, interpolation]]]]) 记得要用新变量来接收
其中src表示原始图像,dsize表示缩放大小,fx和fy也可以表示缩放大小倍数,他们两个(dsize或fx\fy)设置一个即可实现图像缩放
参数说明:
src - 原图
dst - 目标图像。当参数dsize不为0时,dst的大小为size;否则,它的大小需要根据src的大小,参数fx和fy决定。dst的类型(type)和src图像相同
dsize - 目标图像大小。当dsize为0时,它可以通过以下公式计算得出:
所以,参数dsize和参数(fx, fy)不能够同时为0
fx - 水平轴上的比例因子。当它为0时,计算公式如下:
fy - 垂直轴上的比例因子。当它为0时,计算公式如下:
interpolation - 插值方法。共有5种:
INTER_NEAREST - 最近邻插值法
INTER_LINEAR - 双线性插值法(默认)
INTER_AREA - 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取也叫缩小图像(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
INTER_CUBIC - 基于4x4像素邻域的3次插值法
INTER_LANCZOS4 - 基于8x8像素邻域的Lanczos插值
缩小图像 用INTER_AREA更好,放大图像用 INTER_CUBIC更好;
————————————————
代码如下:
import cv2
#读取图片
image = cv2.imread("E:/pythonProject/xin.jpeg")
#图片缩放
image1 = cv2.resize(image, (200,200))
#图片显示
cv2.imshow("resize", image1)
cv2.imshow("image", image)
#等待窗口
cv2.waitKey(0)
旋转
opencv中对图像的旋转主要是先通过getRotationMatrix2D函数得到图像的旋转矩阵,然后再通过仿射变换函数warpAffine得到旋转后的图像。
函数说明:
cv2.getRotationMatrix2D(center, angle, scale)
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
参数说明:
getRotationMatrix2D: 得到图像的旋转矩阵
center–表示旋转的中心点
angle–表示旋转的角度degrees
scale–图像缩放因子
warpAffine:
src – 输入的图像
M – 2 X 3 的变换矩阵.
dsize – 输出的图像的size大小
dst – 输出的图像
flags – 输出图像的插值方法
borderMode – 图像边界的处理方式
borderValue – 当图像边界处理方式为BORDER_CONSTANT 时的填充值
代码示范:
img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
#90度旋转
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
dst = cv2.warpAffine(img,M,(cols,rows))
平移
- 平移translate
平移通过自定义平移矩阵以及函数warpAffine实现:
代码示范:
img = cv2.imread('messi5.jpg',0)
rows,cols = img.shape
# 平移矩阵M:[[1,0,x],[0,1,y]]
M = np.float32([[1,0,100],[0,1,50]])
dst = cv2.warpAffine(img,M,(cols,rows))
反转
- 翻转flip
翻转通过函数flip实现:
函数说明:
cv2.flip(src, flipCode[, dst]) → dst
1
参数说明:
src – 输入的图像
dst – 输出的图像
flipCode – 翻转模式,flipCode==0垂直翻转(沿X轴翻转),flipCode>0水平翻转(沿Y轴翻转),flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)
代码示范:
# 水平翻转
flip_horiz_img = cv2.flip(pad_img, 1)
# 垂直翻转
flip_verti_img = cv2.flip(pad_img, 0)
# 水平垂直翻转
flip_horandver_img = cv2.flip(pad_img, -1)
拼接
单个图像多次拼接
import cv2
img =cv2.imread(file_path[i])
img=cv2.hconcat([img,img,img])#水平拼接
img=cv2.vconcat([img,img,img])#垂直拼接
多个相似特征图像拼接(开摆!)
import cv2
import numpy as np
def stitch(image):
# 图像拼接
# stitcher = cv2.createStitcher(False) # OpenCV 3.X.X.X使用该方法
stitcher = cv2.Stitcher_create(cv2.Stitcher_PANORAMA) # OpenCV 4.X.X.X使用该方法,cv2.Stitcher_create()也可以
status, pano = stitcher.stitch(image)
# 黑边处理
if status == cv2.Stitcher_OK:
# 全景图轮廓提取
stitched = cv2.copyMakeBorder(pano, 10, 10, 10, 10, cv2.BORDER_CONSTANT, (0, 0, 0))
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
# 轮廓最小正矩形
mask = np.zeros(thresh.shape, dtype="uint8")
(x, y, w, h) = cv2.boundingRect(cnts[0]) # 取出list中的轮廓二值图,类型为numpy.ndarray
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
# 腐蚀处理,直到minRect的像素值都为0
minRect = mask.copy()
sub = mask.copy()
while cv2.countNonZero(sub) > 0:
minRect = cv2.erode(minRect, None)
sub = cv2.subtract(minRect, thresh)
# 提取minRect轮廓并裁剪
cnts = cv2.findContours(minRect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
(x, y, w, h) = cv2.boundingRect(cnts[0])
stitched = stitched[y:y + h, x:x + w]
cv2.imshow('stitched', stitched)
cv2.imwrite('stitched.jpg', stitched)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print('图像匹配的特征点不足')
if __name__ == "__main__":
image1 = cv2.imread('data/space1.jpg')
image2 = cv2.imread('data/space2.jpg')
image3 = cv2.imread('data/space3.jpg')
image = image1, image2, image3
stitch(image)
(18条消息) OpenCV-Python 图像全景拼接stitch及黑边处理_Klein-的博客-CSDN博客_stitcher_create