【Python | opencv+PIL】常见操作(创建、添加帧、绘图、读取等)的效率对比及其优化
一、背景
本人准备用python做图像和视频编辑的操作,却发现opencv和PIL的效率并不是很理想,并且同样的需求有多种不同的写法并有着不同的效率。见全网并无较完整的效率对比文档,遂决定自己丰衣足食。
二、目的
本篇文章将对Python下的opencv接口函数及PIL(Pillow)函数的常用部分进行逐个运行并计时(多次测算取平均时间和最短时间,次数一般在100次以上),并简单使用numba、ctypes、cython等方法优化代码。
三、测试方法及环境
1.硬件
CPU:Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz 3.30 GHz
内存:4.00 GB
硬盘:ATA WDC WD5000AAKX-7 SCSI Disk Device
2.软件:
操作系统:Windows 7 Service Pack 1 Ultimate 64bit zh-cn
Python解释器:3.7.5 64bit (provided by Anaconda)
各模块:皆为最新
(事情有所变化,暂时使用下面机房电脑的配置进行测试)
1.硬件
CPU:Intel(R) Xeon(R) Silver 4116 CPU @ 2.10GHz 2.10 GHz
内存:3.00 GB
硬盘:VMware Virtual disk SCSI Disk Service
2.软件:
操作系统:Windows 7 Service Pack 1 Ultimate 64bit zh-cn (powered by VMware Horizon View Client)
Python解释器:3.7.3 64bit (provided by Anaconda)
各模块:皆为最新
四、具体实现
1.待测试函数
以下定义新建的视频规定为MP4格式、mp4v编码、1920*1080尺寸、60帧速率;定义新建的图片为JPG格式、1920*1080尺寸、RGB通道。
根据实际需要(其实是我自己的需要),先暂定测试以下函数[1][2]:
1)创建视频
vw = cv2.VideoWriter('out.mp4', cv2.VideoWriter_fourcc(*'mp4v'), 60, (1920, 1080)) # Return MP4 video object
2)视频帧读取(视频不好做测试数据,故使用了手头上现成的。in.mp4参数:时长27秒,尺寸1920x1080,数据速率17073kbps,总比特率17331kbps,帧速率29fps,大小55.7MB)
cap = cv2.VideoCapture('in.mp4')
while cap.isOpened():
ret, frame = cap.read() # frame return a numpy.ndarray object (WRITEABLE) with RGB of pixels
if not ret: # Return True when read operation is successful
break # Read operation fails and break
cap.release()
3)视频帧写入[3] (PS:为什么Opencv官方教程中没有这个函数...)
vw.write(frame)
4)写入视频(后来发现这个应该类似于file.close(),只是一个释放文件对象的过程,并不是真的在这个时候写入所有的数据。之前看见在release之前文件是空的应该是数据还没有从内存写入磁盘导致的)
vw.release()
5)创建图片 ( matrix & pillow object )
# Matrix
arr = np.zeros((1080, 1920, 3), dtype=np.uint8) # numpy中xy貌似是颠倒的,于是长1920宽1080的图像输出的shape应该是1080x1920,第三维度3表示图片通道为RGB
# Return a numpy.ndarray object (WRITEABLE)
# Pillow
img = Image.new('RGB', (1920, 1080)) # 这里的xy没有颠倒
6)图片读取(opencv & pillow)(使用新建的图片,满足上面的定义,大小33kb)
# OpenCV
arr = cv2.imread('in.jpg') # Notice that OpenCV don't support ALPHA channel
# Pillow
img = Image.open('in.jpg') # Return a PIL.Image.Image object
7)图片数据结构转换
arr1 = list(img.im) # Return a list
arr2 = np.asarray(img) # Return a np.ndarray object (NOT WRITEABLE) (Shallow copy)
arr3 = np.array(img) # Return a np.ndarray object (WRITEABLE) (Deep copy)
8)图片点操作(matrix & pillow object )
# Matrix
arr3[0][0] = (255, 255, 255)
# Pillow
img.putpixel((0, 0), (255, 255, 255)) # Putpixel
draw = ImageDraw.Draw(img) # ImageDraw.Point
draw.point((0, 0), (255, 255, 255))
# PS: OpenCV don't has a function that draw a pixel directly so we don't show the code here
9)图片其他绘图操作(matrix & pillow object & opencv )
这里我们测试画直线、画矩形、画圆(不包括matrix)、画椭圆操作(不包括matrix)、绘制文字(不包括matrix)。
注:pillow中默认绘制的图形都是实心的[4],而opencv要设置线宽为负值才是实心的[5]。
### Line
# Matrix
for x in range(100, 500):
arr3[100][x] = (255, 255, 255) # 注意到numpy的颠倒
# Pillow
draw.line((100, 100, 500, 100), (255, 255, 255))
# OpenCV
cv2.line(arr, (100, 100), (500, 100), (255, 255, 255), 1) # 最后的1表示线宽
### Rectangle
# Matrix
for x in range(100, 500):
for y in range(100, 500):
arr3[y][x] = (255, 255, 255)
# Pillow
draw.rectangle((100, 100, 500, 500), (255, 255, 255))
# OpenCV
cv2.rectangle(arr, (100, 100), (500, 500), (255, 255, 255), -1)
### Circle
# Pillow
draw.arc((100, 100, 500, 500), 0, 360, (255, 255, 255)) # PIL.ImageDraw.Draw.arc
# arc方法前一个四元元组表示圆弧的左上点右下点,这里表示半径200、中心(300, 300);后面两个整数表示度数(0-360表示整个圆)
draw.ellipse((100, 100, 500, 500), (255, 255, 255)) # PIL.ImageDraw.Draw.ellipse
# ellipse方法同样表示两点
# OpenCV
cv2.circle(arr, (300, 300), 200, (255, 255, 255), -1) # cv2.circle
# 与Pillow不同的是,这里读取的是中心点和半径,更符合正常的习惯;1表示线宽,如果是-1则是实心圆
cv2.ellipse(arr, (300, 300), (200, 200), 0, 0, 360, (255, 255, 255), -1) # cv2.ellipse
# 这里第一个二元组是椭圆中心,第二个二元组分别表示半长轴长和半短轴长(注:中文文档漏掉了“半”字),后面三个参数分别表示椭圆本身逆时针旋转角(相当于坐标轴旋转)、起始角度和终止角度(0-360表示整个圆)
### Ellipse
# Pillow
draw.ellipse((100, 100, 700, 500), (255, 255, 255)) # 表示椭圆中心(400, 300),半长轴300,半短轴200
# OpenCV
cv2.ellipse(arr, (400, 300), (300, 200), 0, 0, 360, (255, 255, 255), -1)
### Text
# Pillow
font = ImageFont.truetype('simkai.ttf', 32) # 楷体,字号32
draw.text((100, 100), 'Hello, world!', (255, 255, 255), font) # 这里的坐标是左上角
# OpenCV
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(arr, 'Hello, world!', (100, 200), font, 2, (255, 255, 255), 1, cv2.LINE_AA) # 这里的坐标是左下角,1表示线宽(cv2不支持中文输出,故不测试中文)
其中opencv的字体参数参考:[6]
10)图片其他操作
11)写入图片( Pillow & OpenCV)
# Pillow
img.save('out.jpg')
# OpenCV
cv2.imwrite('out.jpg', arr) # Read from cv2.imread
cv2.imwrite('out.jpg', arr2) # np.asarray
cv2.imwrite('out.jpg', arr3) # np.array
2.时间计算工具
这里的时间计算工具用一个类实现给定次数的循环和智能循环(自动控制循环次数)的功能,并能给出每次循环的函数返回值、循环次数、平均时间、最短时间、最长时间、总共用时。
对于自动判断循环次数的算法参考了Python的timeit模块源码(autorange函数)[7]:
- # -*- coding: utf-8 -*-
- import time
- import cv2
- from PIL import Image, ImageDraw, ImageFont
- import numpy as np
- # Class
- class FunctionTimer(object):
- MAX_WAIT_SEC = 0.5
- INF = 2147483647
- SMART_LOOP = -1
- def __init__(self, timer=None, count=None):
- self._timer = timer if timer != None else time.perf_counter
- self._count = count if count != None else 100
- def _get_single_time(self, func, *args, **kwargs):
- s = self._timer()
- ret = func(*args, **kwargs)
- f = self._timer()
- return ret, f - s
- def _get_repeat_time(self, number, func, *args, **kwargs):
- time_min, time_max, time_sum = self.INF, 0, 0
- for i in range(number):
- ret, delta = self._get_single_time(func, *args, **kwargs)
- time_min = min(time_min, delta)
- time_max = max(time_max, delta)
- time_sum += delta
- return func, ret, number, time_sum / number, time_min, time_max, time_sum
- def gettime(self, func, *args, **kwargs):
- if self._count != self.SMART_LOOP:
- return self._get_repeat_time(self._count, func, *args, **kwargs)
- else:
- # Arrange loop count automatically
- # Refer to Lib/timeit.py
- i = 1
- while True:
- for j in 1, 2, 5:
- number = i * j
- func, ret, number, time_ave, time_min, time_max, time_sum = self._get_repeat_time(number, func, *args, **kwargs)
- if time_sum >= self.MAX_WAIT_SEC:
- return func, ret, number, time_ave, time_min, time_max, time_sum
- i *= 10
- def better_print(self, params):
- func, ret, count, ave, minn, maxn, sumn = params
- print('========================================')
- print(' Function name:')
- print(' ' + func.__repr__())
- print('========================================')
- print(' Function has the return content below:')
- print(' ' + ret.__name__)
- print('========================================')
- print(' Summary of Function Timer:')
- print(' Count of loops: {}'.format(count))
- print(' Average time of loops: {} (sec)'.format(ave))
- print(' Minimum of every loop time: {} (sec)'.format(minn))
- print(' Maximum of every loop time: {} (sec)'.format(maxn))
- print(' Total time of loops: {} (sec)'.format(sumn))
- print('========================================')
- # Function
- def testfunc(x=10000000):
- for i in range(x):
- pass
- return i
- # Main Function
- timer = FunctionTimer()
测试结果(将整个文件作为模块以op为名字调用):
In [168]: op.timer.better_print(op.timer.gettime(op.testfunc, 10000))
========================================
Function name:
testfunc
========================================
Function has the return content below:
9999
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.00039519199983260476 (sec)
Minimum of every loop time: 0.0002532999988034135 (sec)
Maximum of every loop time: 0.0010392999993200647 (sec)
Total time of loops: 0.03951919998326048 (sec)
========================================
In [169]: op.timer.better_print(op.timer.gettime(op.testfunc, 100000))
========================================
Function name:
testfunc
========================================
Function has the return content below:
99999
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0029596240000137187 (sec)
Minimum of every loop time: 0.002567899999121437 (sec)
Maximum of every loop time: 0.006201700000019628 (sec)
Total time of loops: 0.29596240000137186 (sec)
========================================
In [170]: op.timer.better_print(op.timer.gettime(op.testfunc, 10))
========================================
Function name:
testfunc
========================================
Function has the return content below:
9
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 9.039999349624849e-07 (sec)
Minimum of every loop time: 7.999988156370819e-07 (sec)
Maximum of every loop time: 2.6999987312592566e-06 (sec)
Total time of loops: 9.03999934962485e-05 (sec)
========================================
3.完整代码
- # opencv_pil_time.py
- # -*- coding: utf-8 -*-
- import time
- import cv2
- from PIL import Image, ImageDraw, ImageFont
- import numpy as np
- # Class
- class FunctionTimer(object):
- MAX_WAIT_SEC = 0.5
- INF = 2147483647
- SMART_LOOP = -1
- def __init__(self, timer=None, count=None):
- self._timer = timer if timer != None else time.perf_counter
- self._count = count if count != None else 100
- def _get_single_time(self, func, *args, **kwargs):
- s = self._timer()
- ret = func(*args, **kwargs)
- f = self._timer()
- return ret, f - s
- def _get_repeat_time(self, number, func, *args, **kwargs):
- time_min, time_max, time_sum = self.INF, 0, 0
- for i in range(number):
- ret, delta = self._get_single_time(func, *args, **kwargs)
- time_min = min(time_min, delta)
- time_max = max(time_max, delta)
- time_sum += delta
- return func, ret, number, time_sum / number, time_min, time_max, time_sum
- def gettime(self, func, *args, **kwargs):
- if self._count != self.SMART_LOOP:
- return self._get_repeat_time(self._count, func, *args, **kwargs)
- else:
- # Arrange loop count automatically
- # Refer to Lib/timeit.py
- i = 1
- while True:
- for j in 1, 2, 5:
- number = i * j
- func, ret, number, time_ave, time_min, time_max, time_sum = self._get_repeat_time(number, func, *args, **kwargs)
- if time_sum >= self.MAX_WAIT_SEC:
- return func, ret, number, time_ave, time_min, time_max, time_sum
- i *= 10
- def better_print(self, params):
- func, ret, count, ave, minn, maxn, sumn = params
- print('========================================')
- print(' Function name:')
- print(' ' + func.__name__)
- print('========================================')
- print(' Function has the return content below:')
- print(' ' + ret.__repr__())
- print('========================================')
- print(' Summary of Function Timer:')
- print(' Count of loops: {}'.format(count))
- print(' Average time of loops: {} (sec)'.format(ave))
- print(' Minimum of every loop time: {} (sec)'.format(minn))
- print(' Maximum of every loop time: {} (sec)'.format(maxn))
- print(' Total time of loops: {} (sec)'.format(sumn))
- print('========================================')
- # Function
- # Debug
- def testfunc(x=10000000):
- for i in range(x):
- pass
- return i
- # Test Function
- def task_1():
- vw = cv2.VideoWriter('out.mp4', cv2.VideoWriter_fourcc(*'mp4v'), 60, (1920, 1080))
- def task_2():
- cap = cv2.VideoCapture('in.mp4')
- while cap.isOpened():
- ret, frame = cap.read()
- if not ret:
- break
- cap.release()
- def task_3(vw, frame): # Use a new blank video file when testing
- vw.write(frame)
- def task_4(vw):
- vw.release()
- def task_5_matrix():
- arr = np.zeros((1080, 1920, 3), dtype=np.uint8)
- def task_5_pillow():
- img = Image.new('RGB', (1920, 1080))
- def task_6_opencv():
- arr = cv2.imread('in.jpg')
- def task_6_pillow():
- img = Image.open('in.jpg')
- def task_7_list(img):
- arr1 = list(img.im)
- def task_7_asarray(img):
- arr2 = np.asarray(img)
- def task_7_array(img):
- arr3 = np.array(img)
- def task_8_matrix(arr3):
- arr3[0][0] = (255, 255, 255)
- def task_8_pillow_putpixel(img):
- img.putpixel((0, 0), (255, 255, 255))
- def task_8_pillow_point(draw):
- draw.point((0, 0), (255, 255, 255))
- def task_9_line_matrix(arr3):
- for x in range(100, 500):
- arr3[100][x] = (255, 255, 255)
- def task_9_line_pillow(draw):
- draw.line((100, 100, 500, 100), (255, 255, 255))
- def task_9_line_opencv(arr):
- cv2.line(arr, (100, 100), (500, 100), (255, 255, 255), 1)
- def task_9_rectangle_matrix(arr3):
- for x in range(100, 500):
- for y in range(100, 500):
- arr3[y][x] = (255, 255, 255)
- def task_9_rectangle_pillow(draw):
- draw.rectangle((100, 100, 500, 500), (255, 255, 255))
- def task_9_rectangle_opencv(arr):
- cv2.rectangle(arr, (100, 100), (500, 500), (255, 255, 255), -1)
- def task_9_circle_pillow_arc(draw):
- draw.arc((100, 100, 500, 500), 0, 360, (255, 255, 255))
- def task_9_circle_pillow_ellipse(draw):
- draw.ellipse((100, 100, 500, 500), (255, 255, 255))
- def task_9_circle_opencv_circle(arr):
- cv2.circle(arr, (300, 300), 200, (255, 255, 255), -1)
- def task_9_circle_opencv_ellipse(arr):
- cv2.ellipse(arr, (300, 300), (200, 200), 0, 0, 360, (255, 255, 255), -1)
- def task_9_ellipse_pillow(draw):
- draw.ellipse((100, 100, 700, 500), (255, 255, 255))
- def task_9_ellipse_opencv(arr):
- cv2.ellipse(arr, (400, 300), (300, 200), 0, 0, 360, (255, 255, 255), -1)
- def task_9_text_pillow(draw, font):
- draw.text((100, 100), 'Hello, world!', (255, 255, 255), font)
- def task_9_text_opencv(arr, font):
- cv2.putText(arr, 'Hello, world!', (100, 200), font, 2, (255, 255, 255), 1, cv2.LINE_AA)
- def task_10():
- pass
- def task_11_pillow(img):
- img.save('out.jpg')
- def task_11_opencv_imread(arr):
- cv2.imwrite('out.jpg', arr)
- def task_11_opencv_asarray(arr2):
- cv2.imwrite('out.jpg', arr2)
- def task_11_opencv_array(arr3):
- cv2.imwrite('out.jpg', arr3)
- # Main Function
- if __name__ == '__main__':
- timer = FunctionTimer()
- # timer.better_print(timer.gettime(func, *args, **kwargs))
- timer.better_print(timer.gettime(task_1))
- vw = cv2.VideoWriter('out.mp4', cv2.VideoWriter_fourcc(*'mp4v'), 60, (1920, 1080))
- # timer.better_print(timer.gettime(task_2)) # task_2 takes up much time and we don't test it!
- frame = np.zeros((1080, 1920, 3), dtype=np.uint8)
- timer.better_print(timer.gettime(task_3, vw, frame))
- timer.better_print(timer.gettime(task_4, vw))
- timer.better_print(timer.gettime(task_5_matrix))
- timer.better_print(timer.gettime(task_5_pillow))
- timer.better_print(timer.gettime(task_6_opencv))
- arr = cv2.imread('in.jpg')
- timer.better_print(timer.gettime(task_6_pillow))
- img = Image.new('RGB', (1920, 1080))
- timer.better_print(timer.gettime(task_7_list, img))
- timer.better_print(timer.gettime(task_7_asarray, img))
- timer.better_print(timer.gettime(task_7_array, img))
- arr2 = np.asarray(img)
- arr3 = np.array(img)
- timer.better_print(timer.gettime(task_8_matrix, arr3))
- timer.better_print(timer.gettime(task_8_pillow_putpixel, img))
- draw = ImageDraw.Draw(img)
- timer.better_print(timer.gettime(task_8_pillow_point, draw))
- timer.better_print(timer.gettime(task_9_line_matrix, arr3))
- timer.better_print(timer.gettime(task_9_line_pillow, draw))
- timer.better_print(timer.gettime(task_9_line_opencv, arr))
- timer.better_print(timer.gettime(task_9_rectangle_matrix, arr3))
- timer.better_print(timer.gettime(task_9_rectangle_pillow, draw))
- timer.better_print(timer.gettime(task_9_rectangle_opencv, arr))
- timer.better_print(timer.gettime(task_9_circle_pillow_arc, draw))
- timer.better_print(timer.gettime(task_9_circle_pillow_ellipse, draw))
- timer.better_print(timer.gettime(task_9_circle_opencv_circle, arr))
- timer.better_print(timer.gettime(task_9_circle_opencv_ellipse, arr))
- timer.better_print(timer.gettime(task_9_ellipse_pillow, draw))
- timer.better_print(timer.gettime(task_9_ellipse_opencv, arr))
- font = ImageFont.truetype('simkai.ttf', 32)
- timer.better_print(timer.gettime(task_9_text_pillow, draw, font))
- font = cv2.FONT_HERSHEY_SIMPLEX
- timer.better_print(timer.gettime(task_9_text_opencv, arr, font))
- timer.better_print(timer.gettime(task_11_pillow, img))
- timer.better_print(timer.gettime(task_11_opencv_imread, arr))
- timer.better_print(timer.gettime(task_11_opencv_asarray, arr2))
- timer.better_print(timer.gettime(task_11_opencv_array, arr3))
在此我先停一下,各位可以猜猜哪种方式更胜一筹。
flag
flag
flag
flag
flag
flag
flag
flag
flag
flag
flag
flag
flag
五、结果
1.现象
其中task_2(读取视频文件)占用时间过多,我们不予循环测试,下面的结果栏中将给出单次运行的结果(取第一次)。
In [10]: import time
In [11]: s = time.perf_counter(); op.task_2(); f = time.perf_counter(); f - s
Out[11]: 8.617467135000027
In [12]: s = time.perf_counter(); op.task_2(); f = time.perf_counter(); f - s
Out[12]: 8.663589091999995
cmder.exe中运行结果:
E:\test1
$ python3 opencv_pil_time.py
========================================
Function name:
task_1
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0016054189199999984 (sec)
Minimum of every loop time: 0.0013979550000000063 (sec)
Maximum of every loop time: 0.0057973939999999835 (sec)
Total time of loops: 0.16054189199999985 (sec)
========================================
========================================
Function name:
task_3
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.013229802739999979 (sec)
Minimum of every loop time: 0.01082132600000002 (sec)
Maximum of every loop time: 0.018015121000000023 (sec)
Total time of loops: 1.3229802739999978 (sec)
========================================
========================================
Function name:
task_4
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 2.1959869999998995e-05 (sec)
Minimum of every loop time: 3.109999999750812e-07 (sec)
Maximum of every loop time: 0.0021468490000000617 (sec)
Total time of loops: 0.0021959869999998993 (sec)
========================================
========================================
Function name:
task_5_matrix
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 1.4977880000011101e-05 (sec)
Minimum of every loop time: 1.0263000000065858e-05 (sec)
Maximum of every loop time: 4.571699999988965e-05 (sec)
Total time of loops: 0.0014977880000011101 (sec)
========================================
========================================
Function name:
task_5_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0029445669399999997 (sec)
Minimum of every loop time: 0.0026519169999998926 (sec)
Maximum of every loop time: 0.00473345600000008 (sec)
Total time of loops: 0.29445669399999996 (sec)
========================================
========================================
Function name:
task_6_opencv
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.02255292473999999 (sec)
Minimum of every loop time: 0.021661312000000432 (sec)
Maximum of every loop time: 0.032752587999999694 (sec)
Total time of loops: 2.255292473999999 (sec)
========================================
========================================
Function name:
task_6_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.00025689415000005765 (sec)
Minimum of every loop time: 0.0001309319999993619 (sec)
Maximum of every loop time: 0.011476918999999697 (sec)
Total time of loops: 0.025689415000005766 (sec)
========================================
========================================
Function name:
task_7_list
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.38457812533999997 (sec)
Minimum of every loop time: 0.3564736689999961 (sec)
Maximum of every loop time: 0.4698194010000005 (sec)
Total time of loops: 38.457812534 (sec)
========================================
========================================
Function name:
task_7_asarray
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.007278045390000258 (sec)
Minimum of every loop time: 0.007068772000003776 (sec)
Maximum of every loop time: 0.007784698999998341 (sec)
Total time of loops: 0.7278045390000258 (sec)
========================================
========================================
Function name:
task_7_array
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.010643305210000377 (sec)
Minimum of every loop time: 0.009964515000000063 (sec)
Maximum of every loop time: 0.011806892999999263 (sec)
Total time of loops: 1.0643305210000378 (sec)
========================================
========================================
Function name:
task_8_matrix
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 2.8363499999528583e-06 (sec)
Minimum of every loop time: 1.5549999972108708e-06 (sec)
Maximum of every loop time: 4.1673999994884525e-05 (sec)
Total time of loops: 0.00028363499999528585 (sec)
========================================
========================================
Function name:
task_8_pillow_putpixel
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 2.1925700001901305e-06 (sec)
Minimum of every loop time: 1.2439999963476112e-06 (sec)
Maximum of every loop time: 2.1769999996479328e-05 (sec)
Total time of loops: 0.00021925700001901305 (sec)
========================================
========================================
Function name:
task_8_pillow_point
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 2.3574000000081697e-06 (sec)
Minimum of every loop time: 1.5549999972108708e-06 (sec)
Maximum of every loop time: 1.8971000002920846e-05 (sec)
Total time of loops: 0.00023574000000081696 (sec)
========================================
========================================
Function name:
task_9_line_matrix
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0004368183000000414 (sec)
Minimum of every loop time: 0.0004301160000039772 (sec)
Maximum of every loop time: 0.000561359000002426 (sec)
Total time of loops: 0.04368183000000414 (sec)
========================================
========================================
Function name:
task_9_line_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 3.4956700000066122e-06 (sec)
Minimum of every loop time: 2.4879999998006497e-06 (sec)
Maximum of every loop time: 2.519200000250521e-05 (sec)
Total time of loops: 0.0003495670000006612 (sec)
========================================
========================================
Function name:
task_9_line_opencv
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 3.5982899999709163e-06 (sec)
Minimum of every loop time: 2.4879999998006497e-06 (sec)
Maximum of every loop time: 4.727200000331777e-05 (sec)
Total time of loops: 0.0003598289999970916 (sec)
========================================
========================================
Function name:
task_9_rectangle_matrix
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.1735227326999994 (sec)
Minimum of every loop time: 0.17267937900000163 (sec)
Maximum of every loop time: 0.19454626299999944 (sec)
Total time of loops: 17.35227326999994 (sec)
========================================
========================================
Function name:
task_9_rectangle_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 3.0409819999803745e-05 (sec)
Minimum of every loop time: 2.9545000003849964e-05 (sec)
Maximum of every loop time: 7.153000000670318e-05 (sec)
Total time of loops: 0.0030409819999803744 (sec)
========================================
========================================
Function name:
task_9_rectangle_opencv
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 6.522652000001016e-05 (sec)
Minimum of every loop time: 6.25109999958795e-05 (sec)
Maximum of every loop time: 0.0002674619999964989 (sec)
Total time of loops: 0.006522652000001017 (sec)
========================================
========================================
Function name:
task_9_circle_pillow_arc
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 2.7626349999891885e-05 (sec)
Minimum of every loop time: 2.6745999996080627e-05 (sec)
Maximum of every loop time: 6.531100000017886e-05 (sec)
Total time of loops: 0.0027626349999891886 (sec)
========================================
========================================
Function name:
task_9_circle_pillow_ellipse
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0002000553400001337 (sec)
Minimum of every loop time: 0.00019841900000017176 (sec)
Maximum of every loop time: 0.0002512900000013474 (sec)
Total time of loops: 0.02000553400001337 (sec)
========================================
========================================
Function name:
task_9_circle_opencv_circle
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 6.074186999960318e-05 (sec)
Minimum of every loop time: 5.815699999800472e-05 (sec)
Maximum of every loop time: 0.00016856299999545854 (sec)
Total time of loops: 0.006074186999960318 (sec)
========================================
========================================
Function name:
task_9_circle_opencv_ellipse
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 6.716407000013192e-05 (sec)
Minimum of every loop time: 6.593300000190538e-05 (sec)
Maximum of every loop time: 0.00012471200000163662 (sec)
Total time of loops: 0.0067164070000131915 (sec)
========================================
========================================
Function name:
task_9_ellipse_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0002104615099997176 (sec)
Minimum of every loop time: 0.00020619399999333154 (sec)
Maximum of every loop time: 0.00040772399999866593 (sec)
Total time of loops: 0.021046150999971758 (sec)
========================================
========================================
Function name:
task_9_ellipse_opencv
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 8.027900999998394e-05 (sec)
Minimum of every loop time: 7.837199999727318e-05 (sec)
Maximum of every loop time: 0.00020712799999955678 (sec)
Total time of loops: 0.008027900999998394 (sec)
========================================
========================================
Function name:
task_9_text_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.0007998544599997359 (sec)
Minimum of every loop time: 0.0007778169999994589 (sec)
Maximum of every loop time: 0.0016240550000006237 (sec)
Total time of loops: 0.07998544599997359 (sec)
========================================
========================================
Function name:
task_9_text_opencv
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 3.116865999970742e-05 (sec)
Minimum of every loop time: 3.0166999998471056e-05 (sec)
Maximum of every loop time: 9.610000000037644e-05 (sec)
Total time of loops: 0.0031168659999707415 (sec)
========================================
========================================
Function name:
task_11_pillow
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.033835311859999495 (sec)
Minimum of every loop time: 0.03373037900000497 (sec)
Maximum of every loop time: 0.034273077999998236 (sec)
Total time of loops: 3.3835311859999493 (sec)
========================================
========================================
Function name:
task_11_opencv_imread
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.028288081510000042 (sec)
Minimum of every loop time: 0.028133581999995272 (sec)
Maximum of every loop time: 0.02905974700000513 (sec)
Total time of loops: 2.828808151000004 (sec)
========================================
========================================
Function name:
task_11_opencv_asarray
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.02815422919999975 (sec)
Minimum of every loop time: 0.0279864769999989 (sec)
Maximum of every loop time: 0.029095201000004067 (sec)
Total time of loops: 2.8154229199999747 (sec)
========================================
========================================
Function name:
task_11_opencv_array
========================================
Function has the return content below:
None
========================================
Summary of Function Timer:
Count of loops: 100
Average time of loops: 0.028195894160001414 (sec)
Minimum of every loop time: 0.028047434000001203 (sec)
Maximum of every loop time: 0.02866104100000655 (sec)
Total time of loops: 2.8195894160001416 (sec)
========================================
(很奇怪为什么循环次数都是100次,感觉可能timer算法有问题)
时间单位:秒,精确度:3位有效数字,制作成表格(红字表示所在子操作名中平均时间最短的函数,如若平均时间最短按照时间排列顺序依次比较)(图片读取一栏的红字标错位置了,应该打在pillow的下面):
2.结论
1)前四项由于没有对比就不多说了,不过感觉opencv读取视频的速度确实有些慢(6.5MB/s,90.8frame/s)。当然写入数据也很慢(75.8frame/s),不过尺寸不同,就不互相比较了。
2)创建图片操作numpy数组要比pillow的对象要快一些(也就两个数量级吧~)。
3)数据结构转换中numpy比list快几乎是显然的hhh,其中asarray要比array略快一点,大概是因为array深复制而asarray浅复制;当然asarray的结果是not writable的,估计是因为image对象存储的数组本身就是只读的吧。如果只是为了读取图片方便塞视频里就用asarray。
4)没想到图片点操作里面numpy的索引赋值竟然比putpixel还要慢一点!真是大开眼界。。。果然pillow源码里面说“自带api要快一点”是真的。。。
5)图片读取、图片绘图绝大多数情况下pillow秒杀numpy和opencv,只有在写文字的时候opencv体现出比较大的效率优势,但是opencv的字体有很多限制,还是弃置了。(我手头上有一套字模,还是可以测试一下numpy写字速度的,不过估计还是要慢一些,而且字模做起来也比较臃肿,就不试了~)
6)写图片还是opencv要快一点点,当然asarray和array在多精确几个数字就是asarray快了,如果只有三位那就是array更快一点。
六、优化
(待续)
七、总结反思
这个项目我大概从一个月前就有想法了,最近一周一直在抽时间做,净时间估计都有十几个小时了。最后一天(11月16日)晚上我拖到12点,作业还没做完,困得要死,也就做了个大概--没有优化的部分,也没有表格,还因为事先没查好api返工了好几次。这件事让我深感个人的力量的薄弱 ,以及我自己水平的低下。
不过这次的项目让我掌握了多方面搜索数据(尤其是api)的能力,诸如找官方文档啊,看源码啊之类的,晦涩难懂的源代码和英文文档我也尽可能啃掉了,也算是一大进步了吧。
然后就是项目的内容。本次的测试我尽可能从自己能想到的角度给出足够多的实现方法来对比运行效率,孰优孰劣一下子就清楚了。不过也要看情况,比如说给定的数据全是数组,你要是为了追求图像处理函数的效率而全部转成pil对象,也并不是好的。除了时间效率的差距,我们也可以看出PIL的图像处理能力果然还是上等,opencv只是视频库附带一个简陋的图像处理能力,真正到解决图像问题时候还是应该选择PIL。
当然,这次的实验也有不科学的地方,诸如没有控制好无关变量,甚至可能导致相反的结果。我不是专业搞cs得,而且我还是高二生,实在无力全身心投入其中。实验方法带来的误差以及内容的错漏,尚希见谅!
最后希望各位能在这篇充满艰辛的博客中得到点什么。哪怕是一点处理编程项目时的教训而不是博客内容本身,我也心满意足了。
参考资料:
[1]Pillow (PIL Fork) 7.0.0.dev0 英文文档
[2]OpenCV Python Tutorials 翻译 OpenCV-Python Tutorials
[3]Python&OpenCV - 读写(read&write)视频(video) 详解 及 代码
[4]Python图像处理库PIL的ImageDraw模块介绍
[5]python opencv cv2.rectangle 参数含义
【Python | opencv+PIL】常见操作(创建、添加帧、绘图、读取等)的效率对比及其优化的更多相关文章
- python opencv 按一定间隔截取视频帧
前言关于opencvOpenCV 是 Intel 开源计算机视觉库 (Computer Version) .它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法. ...
- python Opencv图像基础操作
读取并显示图像 如果读取图像首先要导入OpenCV包,方法为: import cv2 读取并显示图像 img = cv2.imread("C:\test1.jpg") OpenCV ...
- python 字典的常见操作
字典 字典的增删改查 字典的创建方式: # 创建字典类型 info = { 'name':'李白', ', 'sex':'男' } msg = { 'user01':'Longzeluola', 'u ...
- python opencv:像素操作
图片的像素 像素:组成图片的单位 RGB:颜色由 RGB三种颜色组成 颜色深度:对于8bit的颜色深度来说,它可以表示的颜色范围是 0 ~ 255,对于RGB图片来说,8位颜色深度可以表示 (2^8) ...
- Python opencv PIL numpy base64互相转化
PIL2numpy and numpy2PIL from PIL import Image import numpy image = Image.open('timg.jpeg')# image is ...
- python字符串的常见操作
find: 根据指定字符串获取对应的下标, 如果找不到对应的数据返回-1, 这里的-1表示没有找到数据 my_str = "hello" # find: 根据指定字符串获取对应的下 ...
- python之列表常见操作
list = [1,2,3,4,5,6,7,8,9,0,0,0,0,0] listSet = list.set(list)#将列表中的数据进行去重处理 此时listSet中的数据为[1,2,3,4,5 ...
- Python中字符串常见操作
(1)find 查找 格式:mystr.find(str, start, end) 例如: mystr.find(str, start=0, end=len(mystr)) 作用:检测str是否包含在 ...
- 【代码学习】PYTHON字符串的常见操作
一.字符串运算符 下表实例变量 a 值为字符串 "Hello",b 变量值为 "Python": 操作符 描述 实例 + 字符串连接 >>>a ...
随机推荐
- 3、Web server 之httpd2.2 配置说明
http协议实现的程序 静态(httpd, nginx, lighttpd) 动态 (IIS, tomcat, jetty, jboss, resin, websphere, weblogic ...
- CF786E ALT
题意 有一棵 \(n\) 个点的树和 \(m\) 个人,第 \(i\) 个人从 \(u_i\) 走到 \(v_i\) 现在要发宠物,要求一个人要么他自己发到宠物,要么他走的路径上的都有宠物. 求最小代 ...
- Python3 输入和输出(二)
接上一节 1.读写文件的模式图 将字符串写入到文件 foo.txt 中: #!/usr/bin/python3 # 打开一个文件f = open("/tmp/foo.txt", & ...
- (转)hadoop 集群常用端口
转载于:https://www.cnblogs.com/liying123/p/7097806.html hadoop集群的各部分一般都会使用到多个端口,有些是daemon之间进行交互之用,有些是用于 ...
- 小程序 之修改radio默认样式
一.效果图 二.代码 /* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */ radio .wx-radio-input.wx-radio-input-checked { bor ...
- [后渗透]Linux下的几种隐藏技术【转载】
原作者:Bypass 原文链接:转自Bypass微信公众号 0x00 前言 攻击者在获取服务器权限后,会通过一些技巧来隐藏自己的踪迹和后门文件,本文介绍Linux下的几种隐藏技术. 0x01 隐藏文件 ...
- JavaScript中获取html元素常用手法和区分
对于许多前端开发项目来说,获取元素进行操作是必不可少的,例如tab标签,全屏切换,自动滚播等效果都需要通过获取节点元素来实现.下面我来总结下JavaScript最常用的4个Document对象中获取元 ...
- Alpha项目冲刺! Day2-产出
各个成员今日完成的任务 林恩:任务分工,博客撰写,设计设置等模块 杨长元:学习安卓本地数据库建立 李震:如何写登录界面登录页面,如何下载模板 胡彤:连接服务端 寇永明:提供页面 王浩:提供页面 李杰: ...
- 解决GitHub上传大于100M文件失败
目录 问题 解决 参考 问题 push的时候遇到以下问题: remote: error: GH001: Large files detected. You may want to try Git La ...
- 微信小程序里自定义组件,canvas组件没有效果
methods: { /** * el:画圆的元素 * r:圆的半径 * w:圆的宽度 * 功能:画背景 */ drawCircleBg: function (el, r, w) { const ct ...