图像、视频加载与显示
创建显示窗口
代码语言:javascript复制import cv2
if __name__ == "__main__":
# 创建窗口
cv2.namedWindow('new', cv2.WINDOW_NORMAL)
# 调整窗口大小
cv2.resizeWindow('new', 640, 480)
# 显示窗口
cv2.imshow('new', 0)
# 显示时长
key = cv2.waitKey(0)
if key == 'q':
exit()
# 销毁窗口
cv2.destroyWindow()
运行结果
载入图片
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/WechatIMG12.jpeg")
cv2.imshow('img', img)
while True:
key = cv2.waitKey(0)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
保存文件
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/WechatIMG12.jpeg")
cv2.imshow('img', img)
while True:
key = cv2.waitKey(0)
if key & 0xFF == ord('q'):
break
elif key & 0xFF == ord('s'):
cv2.imwrite("/Users/admin/Documents/帅照.png", img)
cv2.destroyAllWindows()
当我们点击键盘"s"键的时候,运行结果
进入/Users/admin/Documents文件夹
代码语言:javascript复制(base) -bash-3.2$ ls | grep 帅照
帅照.png
摄像头视频采集
代码语言:javascript复制import cv2
if __name__ == "__main__":
# 创建窗口
cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)
# 获取视频设备
cap = cv2.VideoCapture(0)
while True:
# 从摄像头读视频桢
ret, frame = cap.read()
# 将视频帧在窗口中显示
cv2.imshow('video', frame)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
运行结果
这里可以看到摄像头已经打开,并开始采集视频。
读取视频文件
我们这里使用一段鹦鹉的视频,使用命令ffplay查看每秒播放帧数
代码语言:javascript复制./ffplay cockatoo.mp4
ffplay version N-104454-gd92fdc7144-tessus https://evermeet.cx/ffmpeg/ Copyright (c) 2003-2021 the FFmpeg developers
built with Apple clang version 11.0.0 (clang-1100.0.33.17)
configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libmysofa --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvmaf --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-version3 --pkg-config-flags=--static --enable-librtmp --enable-ffplay --enable-sdl2 --disable-ffmpeg --disable-ffprobe
libavutil 57. 7.100 / 57. 7.100
libavcodec 59. 12.100 / 59. 12.100
libavformat 59. 8.100 / 59. 8.100
libavdevice 59. 0.101 / 59. 0.101
libavfilter 8. 16.100 / 8. 16.100
libswscale 6. 1.100 / 6. 1.100
libswresample 4. 0.100 / 4. 0.100
libpostproc 56. 0.100 / 56. 0.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'cockatoo.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf56.4.101
Duration: 00:00:14.00, start: 0.000000, bitrate: 416 kb/s
Stream #0:0[0x1](und): Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), yuv444p(progressive), 1280x720, 387 kb/s, 20 fps, 20 tbr, 10240 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Audio: mp3 (mp4a / 0x6134706D), 16000 Hz, mono, fltp, 24 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
13.63 A-V: -0.031 fd= 0 aq= 0KB vq= 0KB sq= 0B f=0/0
我们可以看到有这么一段
代码语言:javascript复制Stream #0:0[0x1](und): Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), yuv444p(progressive), 1280x720, 387 kb/s, 20 fps, 20 tbr, 10240 tbn (default)
这里有一个20 fps,说明该视频是每秒播放20桢
代码语言:javascript复制import cv2
if __name__ == "__main__":
# 创建窗口
cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)
# 获取视频文件
cap = cv2.VideoCapture("/Users/admin/Downloads/cockatoo.mp4")
while True:
# 从文件读视频桢
ret, frame = cap.read()
# 将视频帧在窗口中显示
cv2.imshow('video', frame)
# 此处不能设为1,否则会过快,可以设的比播放视频每秒帧数长一点
key = cv2.waitKey(40)
if key & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
运行结果
摄像头采集数据输出为媒体文件
代码语言:javascript复制import cv2
if __name__ == "__main__":
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
# 25为帧率,(1280, 720)为分辨率,该分辨率必须与设备摄像头分辨率保持一致
vw = cv2.VideoWriter("/Users/admin/Documents/out.mp4", fourcc, 25, (1280, 720))
# 创建窗口
cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)
# 获取摄像头资源
cap = cv2.VideoCapture(0)
# 判断摄像头是否打开
while cap.isOpened():
# 从摄像头读视频桢
ret, frame = cap.read()
if ret:
# 将视频帧在窗口中显示
cv2.imshow('video', frame)
# 写数据到多媒体文件
vw.write(frame)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
else:
break
# 释放资源
cap.release()
vw.release()
cv2.destroyAllWindows()
运行结果
代码语言:javascript复制(base) -bash-3.2$ ls | grep out
out.mp4
控制鼠标
代码语言:javascript复制import cv2
import numpy as np
def mouse_callback(event, x, y, flags, userdata):
print(event, x, y, flags, userdata)
if __name__ == "__main__":
cv2.namedWindow('mouse', cv2.WINDOW_NORMAL)
cv2.resizeWindow('mouse', 640, 360)
# 设置鼠标回调
cv2.setMouseCallback('mouse', mouse_callback, '123')
# 设置背景为黑色
img = np.zeros((360, 640, 3), np.uint8)
while True:
cv2.imshow('mouse', img)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
当鼠标在黑色区域滑动的时候,控制台会将鼠标的坐标给打印出来
代码语言:javascript复制0 272 156 0 123
0 272 155 0 123
0 272 155 0 123
0 271 155 0 123
0 271 155 0 123
TrackBar的使用
TrackBar就是一种滑动条,滑动到不同的位置,获取相应的值做不同的处理。
代码语言:javascript复制import cv2
import numpy as np
def callback():
pass
if __name__ == "__main__":
cv2.namedWindow('trackbar', cv2.WINDOW_NORMAL)
# 创建trackbar,R是trackbar的名字,0是默认当前值,255是最大值
cv2.createTrackbar('R', 'trackbar', 0, 255, callback)
cv2.createTrackbar('G', 'trackbar', 0, 255, callback)
cv2.createTrackbar('B', 'trackbar', 0, 255, callback)
# 纯黑色背景
img = np.zeros((480, 640, 3), np.uint8)
while True:
cv2.imshow('trackbar', img)
r = cv2.getTrackbarPos('R', 'trackbar')
g = cv2.getTrackbarPos('G', 'trackbar')
b = cv2.getTrackbarPos('B', 'trackbar')
img[:] = [b, g, r]
key = cv2.waitKey(10)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
trackbar取不同的值会有不同的背景色
OpenCV的色彩空间
RGB人眼的色彩空间
每一个像素有三种颜色——红色、绿色和蓝色。通过不同光源的组合,形成真彩色,有暗的,有明亮的。
上图中每一个方格都代表一个像素。
OpenCV默认使用的是BGR,BGR跟RGB的区别就是排列顺序的不同。电脑上一般的排列顺序都是RGB。
HSV/HSB/HSL
HSV代表的是色相、饱和度、明亮度。HSB和HSV是一个意思。
- Hue:色相,即色彩,如红色、蓝色
- Saturation:饱和度,颜色的纯度,值越大,纯度越高,最开始的时候是灰的,逐渐增大就纯度越高,如果是红色就是纯红,蓝色就是纯蓝
- Value:明度,代表更暗一些还是更亮一些,当更暗的时候,黑色的程度越高;更亮一些就黑色成分少一些。
该图中旋转一圈的过程中代表了不同的颜色。对于饱和度来说,以中心点为基础,底下是黑色,上面是白色,中间是黑与白之间的灰。越靠近于圆柱边缘的地方,颜色的纯度越高。而对于纵轴,底下是黑色的,越往上越来越亮,这个就是明亮度。
对于OpenCV来说更喜欢使用HSV,使用HSV在背景判断上要好过RGB,因为在一个背景中可能有各种绿色,使用HSV就可以统一将背景判断为绿色,而使用RGB就不太好判断,每一种成分都有。
判断背景是通过色度来进行判断的,上图中0度就是纯红,60度就是黄色,120度为绿色,180度为青色,240度为蓝色,300度为粉红。这里是不考虑从圆心到边缘的渐变的一些因素的。
HSL
- Hue:色相,即色彩,如红色、蓝色
- Saturation:饱和度
- Ligthness:亮度
HSL与HSV看起来差不多,但存在着不同。
这里左图是HSL的,右图是HSV的,对于HSL到最顶成的时候就是纯白,无论色相是什么,饱和度是什么。而HSV就没有这么夸张。我们基本上使用的都是HSV,HSL几乎是不使用的。
YUV
YUV主要用在视频领域。Y代表的是灰色图像,UV代表的是颜色。YUV来自于电视节目,以前的电视只有黑白电视,就只有这个Y,后来有了彩色电视,但是要兼容黑白电视剧,当彩色电视机播放黑白电视剧的时候就只播放这个Y。一般的YUV包含YUV4:2:0、YUV4:2:2、YUV4:4:4。
YUV4:2:0
上图中,4个Y对应2个U或者V。不同的间隔,U或者V都是不一定的。
色彩空间转换
代码语言:javascript复制import cv2
def callback():
pass
if __name__ == "__main__":
cv2.namedWindow('color', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
colorspaces = [cv2.COLOR_BGR2RGBA, cv2.COLOR_BGR2BGRA, cv2.COLOR_BGR2GRAY,
cv2.COLOR_BGR2HSV_FULL, cv2.COLOR_BGR2YUV]
cv2.createTrackbar('curcolor', 'color', 0, len(colorspaces) - 1, callback)
while True:
index = cv2.getTrackbarPos('curcolor', 'color')
# 颜色空间转换
cvt_img = cv2.cvtColor(img, colorspaces[index])
cv2.imshow('color', cvt_img)
key = cv2.waitKey(10)
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
trackbar取值为0的时候
trackbar取值为1的时候
trackbar取值为2的时候
trackbar取值为3的时候
trackbar取值为4的时候
ROI(Region of Image)
roi的意思是对图像的一个区域进行提取
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('roi', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
print(img.shape)
roi = img[0:550, 750:1350]
while True:
# 颜色空间转换
cv2.imshow('roi', roi)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
代码语言:javascript复制(1080, 1920, 3)
我们这里需要注意的是img是一个numpy三维矩阵,它的第一个维度是图像的高,第二个维度是图像的宽,第三个维度是图像的通道数。
Mat
Mat就是矩阵,它的结构如下
对于Header头部来说,存放的是一些属性,包括维度、行数,列数。而Data是存放数据的地方,就是图像中的实际像素。总体如下
字段 | 说明 | 字段 | 说明 |
---|---|---|---|
dims | 维度 | channels | 通道数 RGB是3 |
rows | 行数 | size | 矩阵大小 |
cols | 列数 | type | dep dt chs CV_8UC3 |
depth | 像素的位深 | data | 存放数据 |
Mat拷贝
这里Mat A是第一个创建的Mat,Mat B是拷贝Mat A,这里我们可以看到Mat A和Mat B的Header是两部分,而Data是它们公用的,也就是说Mat A和Mat B的Header的指针指向的是同一块内存空间。所以当我们用Mat B来拷贝Mat A的时候,默认情况下属于浅拷贝。有关深浅拷贝的概念请参考浅析克隆
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img1', cv2.WINDOW_NORMAL)
cv2.namedWindow('img2', cv2.WINDOW_NORMAL)
img1 = cv2.imread("/Users/admin/Documents/111.jpeg")
# 浅拷贝
img2 = img1
# 将图像左上角变成红色小方块
img1[10:100, 10:100] = [0, 0, 255]
while True:
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
上面的两张图是两个不同的窗口,它们的左上角都有一小块红色的方块,说明,这种拷贝方式属于浅拷贝。
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img1', cv2.WINDOW_NORMAL)
cv2.namedWindow('img2', cv2.WINDOW_NORMAL)
img1 = cv2.imread("/Users/admin/Documents/111.jpeg")
# 深拷贝
img2 = img1.copy()
# 将图像左上角变成红色小方块
img1[10:100, 10:100] = [0, 0, 255]
while True:
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
这里我们可以看到img2的左上角是没有红色小方块的,说明这是深拷贝。
Mat的属性
代码语言:javascript复制import cv2
if __name__ == "__main__":
img = cv2.imread("/Users/admin/Documents/111.jpeg")
print(img.shape)
# 图像占用内存空间数,高度*宽度*通道数
print(img.size)
# 图像中每个元素的位深
print(img.dtype)
运行结果
代码语言:javascript复制(1080, 1920, 3)
6220800
uint8
这里我们可以看到每个元素的类型是uint8,说明它是一个无符号8位整型,是从0~255的范围。
通道的分割与合并
这里我们需要明白一个概念,任何的单通道图像都是灰色的,而任何彩色图像都必须是三通道的。
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 分割图像的三个通道
b, g, r = cv2.split(img)
while True:
cv2.imshow('img', b)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
那么我们显示的是蓝色通道,为什么是黑白的呢?其实要显示蓝色通道的图像依然要合并另外两个通道,即红色通道和绿色通道,只不过这两个通道我们需要设置成纯黑。
代码语言:javascript复制import cv2
import numpy as np
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 分割图像的三个通道
b, g, r = cv2.split(img)
filt = np.zeros((1080, 1920), np.uint8)
# 合并三个通道,但只保留蓝色通道信息
imgnew = cv2.merge((b, filt, filt))
while True:
cv2.imshow('img', imgnew)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
如果我们要一张纯蓝色的图片呢?
代码语言:javascript复制import cv2
import numpy as np
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
filt = np.zeros((1080, 1920), np.uint8)
b = np.full((1080, 1920), 255, np.uint8)
# 合并三个通道,但只保留蓝色通道信息
imgnew = cv2.merge((b, filt, filt))
while True:
cv2.imshow('img', imgnew)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
对比两张图片,我们可以看到,在纯蓝图片中,蓝色通道中的所有像素值都是255,而从111.jpeg中蓝色通道的矩阵应该就是各不相同的像素大小最终显示出来的效果。
OpenCV图形绘制
画线
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,5为线宽
cv2.line(img, (750, 550), (1350, 550), (255, 255, 255), 5)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
现在我们来画一条斜线,并增加锯齿感
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
在视频中画线
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)
# 获取视频文件
cap = cv2.VideoCapture("/Users/admin/Downloads/cockatoo.mp4")
while True:
# 从文件读视频桢
ret, frame = cap.read()
if ret:
cv2.line(frame, (0, 600), (1280, 600), (0, 0, 255), 5)
# 将视频帧在窗口中显示
cv2.imshow('video', frame)
# 此处不能设为1,否则会过快,可以设的比播放视频每秒帧数长一点
key = cv2.waitKey(40)
if key & 0xFF == ord('q'):
break
else:
key = cv2.waitKey(40)
if key & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
运行结果
画矩形
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), 8)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
画实心矩形
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
画圆
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,5为线宽,16的锯齿度数
cv2.circle(img, (1050, 275), 275, (0, 0, 255), 5, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
画实心圆
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
画椭圆
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
# cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
# 画一个红色的椭圆,(1050, 275)为中心点坐标,(500, 275)为长宽的一半
# 第一个0为长方体角度起始值,第二个0为长方体角度终止值
# 360是椭圆的画线部分的度数
cv2.ellipse(img, (1050, 275), (500, 275), 0, 0, 360, (0, 0, 255), 5, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
如果我们要绘制椭圆的下半部分
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
# cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
# 画一个红色的椭圆,(1050, 275)为中心点坐标,(500, 275)为长宽的一半
# 第一个0为长方体角度起始值,第二个0为长方体角度终止值
# 180是椭圆的画线部分的度数
cv2.ellipse(img, (1050, 275), (500, 275), 0, 0, 180, (0, 0, 255), 5, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
如果我们要绘制椭圆的上半部分
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
# cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
# 画一个红色的椭圆,(1050, 275)为中心点坐标,(500, 275)为长宽的一半
# 第一个0为长方体角度起始值,第二个0为长方体角度终止值
# 180是椭圆的画线部分的度数
cv2.ellipse(img, (1050, 275), (500, 275), 180, 0, 180, (0, 0, 255), 5, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
如果我们要绘制一些斜的椭圆
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
# cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
# 画一个红色的椭圆,(1050, 275)为中心点坐标,(500, 275)为长宽的一半
# 第一个0为长方体角度起始值,第二个0为长方体角度终止值
# 180是椭圆的画线部分的度数
cv2.ellipse(img, (1050, 275), (500, 275), 60, 0, 360, (0, 0, 255), 5, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
如果我们要绘制一个与第一个椭圆垂直的椭圆
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
# cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
# 画一个红色的椭圆,(1050, 275)为中心点坐标,(500, 275)为长宽的一半
# 第一个0为长方体角度起始值,第二个0为长方体角度终止值
# 180是椭圆的画线部分的度数
cv2.ellipse(img, (1050, 275), (500, 275), 90, 0, 360, (0, 0, 255), 5, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
如果我们要画一个实体扇形
代码语言:javascript复制import cv2
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/111.jpeg")
# 画一条白线(750, 550)为起始点坐标,(1350, 550)为终止点坐标
# (255, 255, 255)为颜色,用三通道表示,8为线宽,
# 1为锯齿度,越小锯齿感越强,越大越平滑
# cv2.line(img, (759, 550), (1350, 900), (255, 255, 255), 8, 1)
# 画一个红框(750, 0)为起始点坐标,(1350, 550)为终止点坐标
# -1表示线宽无限大,即为实心
# cv2.rectangle(img, (750, 0), (1350, 550), (0, 0, 255), -1)
# 画一个红色的圆,(1050, 275)为圆心坐标,275为半径,-1为线宽无限大,即为实心,16的锯齿度数
# cv2.circle(img, (1050, 275), 275, (0, 0, 255), -1, 16)
# 画一个红色的椭圆,(1050, 275)为中心点坐标,(500, 275)为长宽的一半
# 第一个0为长方体角度起始值,第二个0为长方体角度终止值
# 180是椭圆的画线部分的度数
cv2.ellipse(img, (1050, 275), (500, 275), 120, 330, 360, (0, 0, 255), -1, 16)
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
画多边形