一、背景

本人准备用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)创建视频

  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)

  1. cap = cv2.VideoCapture('in.mp4')
  2. while cap.isOpened():
  3. ret, frame = cap.read() # frame return a numpy.ndarray object (WRITEABLE) with RGB of pixels
  4. if not ret: # Return True when read operation is successful
  5. break # Read operation fails and break
  6. cap.release()

3)视频帧写入[3] (PS:为什么Opencv官方教程中没有这个函数...)

  1. vw.write(frame)

4)写入视频(后来发现这个应该类似于file.close(),只是一个释放文件对象的过程,并不是真的在这个时候写入所有的数据。之前看见在release之前文件是空的应该是数据还没有从内存写入磁盘导致的)

  1. vw.release()

5)创建图片 ( matrix & pillow object )

  1. # Matrix
  2. arr = np.zeros((1080, 1920, 3), dtype=np.uint8) # numpy中xy貌似是颠倒的,于是长1920宽1080的图像输出的shape应该是1080x1920,第三维度3表示图片通道为RGB
  3. # Return a numpy.ndarray object (WRITEABLE)
  4. # Pillow
  5. img = Image.new('RGB', (1920, 1080)) # 这里的xy没有颠倒

6)图片读取(opencv & pillow)(使用新建的图片,满足上面的定义,大小33kb)

  1. # OpenCV
  2. arr = cv2.imread('in.jpg') # Notice that OpenCV don't support ALPHA channel
  3. # Pillow
  4. img = Image.open('in.jpg') # Return a PIL.Image.Image object

7)图片数据结构转换

  1. arr1 = list(img.im) # Return a list
  2. arr2 = np.asarray(img) # Return a np.ndarray object (NOT WRITEABLE) (Shallow copy)
  3. arr3 = np.array(img) # Return a np.ndarray object (WRITEABLE) (Deep copy)

8)图片点操作(matrix & pillow object )

  1. # Matrix
  2. arr3[0][0] = (255, 255, 255)
  3. # Pillow
  4. img.putpixel((0, 0), (255, 255, 255)) # Putpixel
  5. draw = ImageDraw.Draw(img) # ImageDraw.Point
  6. draw.point((0, 0), (255, 255, 255))
  7. # 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]。

  1. ### Line
  2. # Matrix
  3. for x in range(100, 500):
  4. arr3[100][x] = (255, 255, 255) # 注意到numpy的颠倒
  5. # Pillow
  6. draw.line((100, 100, 500, 100), (255, 255, 255))
  7. # OpenCV
  8. cv2.line(arr, (100, 100), (500, 100), (255, 255, 255), 1) # 最后的1表示线宽
  9. ### Rectangle
  10. # Matrix
  11. for x in range(100, 500):
  12. for y in range(100, 500):
  13. arr3[y][x] = (255, 255, 255)
  14. # Pillow
  15. draw.rectangle((100, 100, 500, 500), (255, 255, 255))
  16. # OpenCV
  17. cv2.rectangle(arr, (100, 100), (500, 500), (255, 255, 255), -1)
  18. ### Circle
  19. # Pillow
  20. draw.arc((100, 100, 500, 500), 0, 360, (255, 255, 255)) # PIL.ImageDraw.Draw.arc
  21. # arc方法前一个四元元组表示圆弧的左上点右下点,这里表示半径200、中心(300, 300);后面两个整数表示度数(0-360表示整个圆)
  22. draw.ellipse((100, 100, 500, 500), (255, 255, 255)) # PIL.ImageDraw.Draw.ellipse
  23. # ellipse方法同样表示两点
  24. # OpenCV
  25. cv2.circle(arr, (300, 300), 200, (255, 255, 255), -1) # cv2.circle
  26. # 与Pillow不同的是,这里读取的是中心点和半径,更符合正常的习惯;1表示线宽,如果是-1则是实心圆
  27. cv2.ellipse(arr, (300, 300), (200, 200), 0, 0, 360, (255, 255, 255), -1) # cv2.ellipse
  28. # 这里第一个二元组是椭圆中心,第二个二元组分别表示半长轴长和半短轴长(注:中文文档漏掉了“半”字),后面三个参数分别表示椭圆本身逆时针旋转角(相当于坐标轴旋转)、起始角度和终止角度(0-360表示整个圆)
  29. ### Ellipse
  30. # Pillow
  31. draw.ellipse((100, 100, 700, 500), (255, 255, 255)) # 表示椭圆中心(400, 300),半长轴300,半短轴200
  32. # OpenCV
  33. cv2.ellipse(arr, (400, 300), (300, 200), 0, 0, 360, (255, 255, 255), -1)
  34. ### Text
  35. # Pillow
  36. font = ImageFont.truetype('simkai.ttf', 32) # 楷体,字号32
  37. draw.text((100, 100), 'Hello, world!', (255, 255, 255), font) # 这里的坐标是左上角
  38. # OpenCV
  39. font = cv2.FONT_HERSHEY_SIMPLEX
  40. cv2.putText(arr, 'Hello, world!', (100, 200), font, 2, (255, 255, 255), 1, cv2.LINE_AA) # 这里的坐标是左下角,1表示线宽(cv2不支持中文输出,故不测试中文)

其中opencv的字体参数参考:[6]

10)图片其他操作

11)写入图片( Pillow & OpenCV)

  1. # Pillow
  2. img.save('out.jpg')
  3. # OpenCV
  4. cv2.imwrite('out.jpg', arr) # Read from cv2.imread
  5. cv2.imwrite('out.jpg', arr2) # np.asarray
  6. cv2.imwrite('out.jpg', arr3) # np.array

2.时间计算工具

这里的时间计算工具用一个类实现给定次数的循环智能循环(自动控制循环次数)的功能,并能给出每次循环的函数返回值、循环次数、平均时间、最短时间、最长时间、总共用时。

对于自动判断循环次数的算法参考了Python的timeit模块源码(autorange函数)[7]:

  1. # -*- coding: utf-8 -*-
  2.  
  3. import time
  4. import cv2
  5. from PIL import Image, ImageDraw, ImageFont
  6. import numpy as np
  7.  
  8. # Class
  9. class FunctionTimer(object):
  10. MAX_WAIT_SEC = 0.5
  11. INF = 2147483647
  12. SMART_LOOP = -1
  13.  
  14. def __init__(self, timer=None, count=None):
  15. self._timer = timer if timer != None else time.perf_counter
  16. self._count = count if count != None else 100
  17.  
  18. def _get_single_time(self, func, *args, **kwargs):
  19. s = self._timer()
  20. ret = func(*args, **kwargs)
  21. f = self._timer()
  22. return ret, f - s
  23.  
  24. def _get_repeat_time(self, number, func, *args, **kwargs):
  25. time_min, time_max, time_sum = self.INF, 0, 0
  26. for i in range(number):
  27. ret, delta = self._get_single_time(func, *args, **kwargs)
  28. time_min = min(time_min, delta)
  29. time_max = max(time_max, delta)
  30. time_sum += delta
  31. return func, ret, number, time_sum / number, time_min, time_max, time_sum
  32.  
  33. def gettime(self, func, *args, **kwargs):
  34. if self._count != self.SMART_LOOP:
  35. return self._get_repeat_time(self._count, func, *args, **kwargs)
  36. else:
  37. # Arrange loop count automatically
  38. # Refer to Lib/timeit.py
  39. i = 1
  40. while True:
  41. for j in 1, 2, 5:
  42. number = i * j
  43. func, ret, number, time_ave, time_min, time_max, time_sum = self._get_repeat_time(number, func, *args, **kwargs)
  44. if time_sum >= self.MAX_WAIT_SEC:
  45. return func, ret, number, time_ave, time_min, time_max, time_sum
  46. i *= 10
  47.  
  48. def better_print(self, params):
  49. func, ret, count, ave, minn, maxn, sumn = params
  50. print('========================================')
  51. print(' Function name:')
  52. print(' ' + func.__repr__())
  53. print('========================================')
  54. print(' Function has the return content below:')
  55. print(' ' + ret.__name__)
  56. print('========================================')
  57. print(' Summary of Function Timer:')
  58. print(' Count of loops: {}'.format(count))
  59. print(' Average time of loops: {} (sec)'.format(ave))
  60. print(' Minimum of every loop time: {} (sec)'.format(minn))
  61. print(' Maximum of every loop time: {} (sec)'.format(maxn))
  62. print(' Total time of loops: {} (sec)'.format(sumn))
  63. print('========================================')
  64.  
  65. # Function
  66. def testfunc(x=10000000):
  67. for i in range(x):
  68. pass
  69. return i
  70.  
  71. # Main Function
  72. timer = FunctionTimer()

测试结果(将整个文件作为模块以op为名字调用):

  1. In [168]: op.timer.better_print(op.timer.gettime(op.testfunc, 10000))
  2. ========================================
  3. Function name:
  4. testfunc
  5. ========================================
  6. Function has the return content below:
  7. 9999
  8. ========================================
  9. Summary of Function Timer:
  10. Count of loops: 100
  11. Average time of loops: 0.00039519199983260476 (sec)
  12. Minimum of every loop time: 0.0002532999988034135 (sec)
  13. Maximum of every loop time: 0.0010392999993200647 (sec)
  14. Total time of loops: 0.03951919998326048 (sec)
  15. ========================================
  16. In [169]: op.timer.better_print(op.timer.gettime(op.testfunc, 100000))
  17. ========================================
  18. Function name:
  19. testfunc
  20. ========================================
  21. Function has the return content below:
  22. 99999
  23. ========================================
  24. Summary of Function Timer:
  25. Count of loops: 100
  26. Average time of loops: 0.0029596240000137187 (sec)
  27. Minimum of every loop time: 0.002567899999121437 (sec)
  28. Maximum of every loop time: 0.006201700000019628 (sec)
  29. Total time of loops: 0.29596240000137186 (sec)
  30. ========================================
  31. In [170]: op.timer.better_print(op.timer.gettime(op.testfunc, 10))
  32. ========================================
  33. Function name:
  34. testfunc
  35. ========================================
  36. Function has the return content below:
  37. 9
  38. ========================================
  39. Summary of Function Timer:
  40. Count of loops: 100
  41. Average time of loops: 9.039999349624849e-07 (sec)
  42. Minimum of every loop time: 7.999988156370819e-07 (sec)
  43. Maximum of every loop time: 2.6999987312592566e-06 (sec)
  44. Total time of loops: 9.03999934962485e-05 (sec)
  45. ========================================

3.完整代码

  1. # opencv_pil_time.py
  2.  
  3. # -*- coding: utf-8 -*-
  4.  
  5. import time
  6. import cv2
  7. from PIL import Image, ImageDraw, ImageFont
  8. import numpy as np
  9.  
  10. # Class
  11. class FunctionTimer(object):
  12. MAX_WAIT_SEC = 0.5
  13. INF = 2147483647
  14. SMART_LOOP = -1
  15.  
  16. def __init__(self, timer=None, count=None):
  17. self._timer = timer if timer != None else time.perf_counter
  18. self._count = count if count != None else 100
  19.  
  20. def _get_single_time(self, func, *args, **kwargs):
  21. s = self._timer()
  22. ret = func(*args, **kwargs)
  23. f = self._timer()
  24. return ret, f - s
  25.  
  26. def _get_repeat_time(self, number, func, *args, **kwargs):
  27. time_min, time_max, time_sum = self.INF, 0, 0
  28. for i in range(number):
  29. ret, delta = self._get_single_time(func, *args, **kwargs)
  30. time_min = min(time_min, delta)
  31. time_max = max(time_max, delta)
  32. time_sum += delta
  33. return func, ret, number, time_sum / number, time_min, time_max, time_sum
  34.  
  35. def gettime(self, func, *args, **kwargs):
  36. if self._count != self.SMART_LOOP:
  37. return self._get_repeat_time(self._count, func, *args, **kwargs)
  38. else:
  39. # Arrange loop count automatically
  40. # Refer to Lib/timeit.py
  41. i = 1
  42. while True:
  43. for j in 1, 2, 5:
  44. number = i * j
  45. func, ret, number, time_ave, time_min, time_max, time_sum = self._get_repeat_time(number, func, *args, **kwargs)
  46. if time_sum >= self.MAX_WAIT_SEC:
  47. return func, ret, number, time_ave, time_min, time_max, time_sum
  48. i *= 10
  49.  
  50. def better_print(self, params):
  51. func, ret, count, ave, minn, maxn, sumn = params
  52. print('========================================')
  53. print(' Function name:')
  54. print(' ' + func.__name__)
  55. print('========================================')
  56. print(' Function has the return content below:')
  57. print(' ' + ret.__repr__())
  58. print('========================================')
  59. print(' Summary of Function Timer:')
  60. print(' Count of loops: {}'.format(count))
  61. print(' Average time of loops: {} (sec)'.format(ave))
  62. print(' Minimum of every loop time: {} (sec)'.format(minn))
  63. print(' Maximum of every loop time: {} (sec)'.format(maxn))
  64. print(' Total time of loops: {} (sec)'.format(sumn))
  65. print('========================================')
  66.  
  67. # Function
  68. # Debug
  69. def testfunc(x=10000000):
  70. for i in range(x):
  71. pass
  72. return i
  73.  
  74. # Test Function
  75. def task_1():
  76. vw = cv2.VideoWriter('out.mp4', cv2.VideoWriter_fourcc(*'mp4v'), 60, (1920, 1080))
  77.  
  78. def task_2():
  79. cap = cv2.VideoCapture('in.mp4')
  80. while cap.isOpened():
  81. ret, frame = cap.read()
  82. if not ret:
  83. break
  84. cap.release()
  85.  
  86. def task_3(vw, frame): # Use a new blank video file when testing
  87. vw.write(frame)
  88.  
  89. def task_4(vw):
  90. vw.release()
  91.  
  92. def task_5_matrix():
  93. arr = np.zeros((1080, 1920, 3), dtype=np.uint8)
  94.  
  95. def task_5_pillow():
  96. img = Image.new('RGB', (1920, 1080))
  97.  
  98. def task_6_opencv():
  99. arr = cv2.imread('in.jpg')
  100.  
  101. def task_6_pillow():
  102. img = Image.open('in.jpg')
  103.  
  104. def task_7_list(img):
  105. arr1 = list(img.im)
  106.  
  107. def task_7_asarray(img):
  108. arr2 = np.asarray(img)
  109.  
  110. def task_7_array(img):
  111. arr3 = np.array(img)
  112.  
  113. def task_8_matrix(arr3):
  114. arr3[0][0] = (255, 255, 255)
  115.  
  116. def task_8_pillow_putpixel(img):
  117. img.putpixel((0, 0), (255, 255, 255))
  118.  
  119. def task_8_pillow_point(draw):
  120. draw.point((0, 0), (255, 255, 255))
  121.  
  122. def task_9_line_matrix(arr3):
  123. for x in range(100, 500):
  124. arr3[100][x] = (255, 255, 255)
  125.  
  126. def task_9_line_pillow(draw):
  127. draw.line((100, 100, 500, 100), (255, 255, 255))
  128.  
  129. def task_9_line_opencv(arr):
  130. cv2.line(arr, (100, 100), (500, 100), (255, 255, 255), 1)
  131.  
  132. def task_9_rectangle_matrix(arr3):
  133. for x in range(100, 500):
  134. for y in range(100, 500):
  135. arr3[y][x] = (255, 255, 255)
  136.  
  137. def task_9_rectangle_pillow(draw):
  138. draw.rectangle((100, 100, 500, 500), (255, 255, 255))
  139.  
  140. def task_9_rectangle_opencv(arr):
  141. cv2.rectangle(arr, (100, 100), (500, 500), (255, 255, 255), -1)
  142.  
  143. def task_9_circle_pillow_arc(draw):
  144. draw.arc((100, 100, 500, 500), 0, 360, (255, 255, 255))
  145.  
  146. def task_9_circle_pillow_ellipse(draw):
  147. draw.ellipse((100, 100, 500, 500), (255, 255, 255))
  148.  
  149. def task_9_circle_opencv_circle(arr):
  150. cv2.circle(arr, (300, 300), 200, (255, 255, 255), -1)
  151.  
  152. def task_9_circle_opencv_ellipse(arr):
  153. cv2.ellipse(arr, (300, 300), (200, 200), 0, 0, 360, (255, 255, 255), -1)
  154.  
  155. def task_9_ellipse_pillow(draw):
  156. draw.ellipse((100, 100, 700, 500), (255, 255, 255))
  157.  
  158. def task_9_ellipse_opencv(arr):
  159. cv2.ellipse(arr, (400, 300), (300, 200), 0, 0, 360, (255, 255, 255), -1)
  160.  
  161. def task_9_text_pillow(draw, font):
  162. draw.text((100, 100), 'Hello, world!', (255, 255, 255), font)
  163.  
  164. def task_9_text_opencv(arr, font):
  165. cv2.putText(arr, 'Hello, world!', (100, 200), font, 2, (255, 255, 255), 1, cv2.LINE_AA)
  166.  
  167. def task_10():
  168. pass
  169.  
  170. def task_11_pillow(img):
  171. img.save('out.jpg')
  172.  
  173. def task_11_opencv_imread(arr):
  174. cv2.imwrite('out.jpg', arr)
  175.  
  176. def task_11_opencv_asarray(arr2):
  177. cv2.imwrite('out.jpg', arr2)
  178.  
  179. def task_11_opencv_array(arr3):
  180. cv2.imwrite('out.jpg', arr3)
  181.  
  182. # Main Function
  183. if __name__ == '__main__':
  184. timer = FunctionTimer()
  185. # timer.better_print(timer.gettime(func, *args, **kwargs))
  186. timer.better_print(timer.gettime(task_1))
  187. vw = cv2.VideoWriter('out.mp4', cv2.VideoWriter_fourcc(*'mp4v'), 60, (1920, 1080))
  188. # timer.better_print(timer.gettime(task_2)) # task_2 takes up much time and we don't test it!
  189. frame = np.zeros((1080, 1920, 3), dtype=np.uint8)
  190. timer.better_print(timer.gettime(task_3, vw, frame))
  191. timer.better_print(timer.gettime(task_4, vw))
  192. timer.better_print(timer.gettime(task_5_matrix))
  193. timer.better_print(timer.gettime(task_5_pillow))
  194. timer.better_print(timer.gettime(task_6_opencv))
  195. arr = cv2.imread('in.jpg')
  196. timer.better_print(timer.gettime(task_6_pillow))
  197. img = Image.new('RGB', (1920, 1080))
  198. timer.better_print(timer.gettime(task_7_list, img))
  199. timer.better_print(timer.gettime(task_7_asarray, img))
  200. timer.better_print(timer.gettime(task_7_array, img))
  201. arr2 = np.asarray(img)
  202. arr3 = np.array(img)
  203. timer.better_print(timer.gettime(task_8_matrix, arr3))
  204. timer.better_print(timer.gettime(task_8_pillow_putpixel, img))
  205. draw = ImageDraw.Draw(img)
  206. timer.better_print(timer.gettime(task_8_pillow_point, draw))
  207. timer.better_print(timer.gettime(task_9_line_matrix, arr3))
  208. timer.better_print(timer.gettime(task_9_line_pillow, draw))
  209. timer.better_print(timer.gettime(task_9_line_opencv, arr))
  210. timer.better_print(timer.gettime(task_9_rectangle_matrix, arr3))
  211. timer.better_print(timer.gettime(task_9_rectangle_pillow, draw))
  212. timer.better_print(timer.gettime(task_9_rectangle_opencv, arr))
  213. timer.better_print(timer.gettime(task_9_circle_pillow_arc, draw))
  214. timer.better_print(timer.gettime(task_9_circle_pillow_ellipse, draw))
  215. timer.better_print(timer.gettime(task_9_circle_opencv_circle, arr))
  216. timer.better_print(timer.gettime(task_9_circle_opencv_ellipse, arr))
  217. timer.better_print(timer.gettime(task_9_ellipse_pillow, draw))
  218. timer.better_print(timer.gettime(task_9_ellipse_opencv, arr))
  219. font = ImageFont.truetype('simkai.ttf', 32)
  220. timer.better_print(timer.gettime(task_9_text_pillow, draw, font))
  221. font = cv2.FONT_HERSHEY_SIMPLEX
  222. timer.better_print(timer.gettime(task_9_text_opencv, arr, font))
  223. timer.better_print(timer.gettime(task_11_pillow, img))
  224. timer.better_print(timer.gettime(task_11_opencv_imread, arr))
  225. timer.better_print(timer.gettime(task_11_opencv_asarray, arr2))
  226. 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(读取视频文件)占用时间过多,我们不予循环测试,下面的结果栏中将给出单次运行的结果(取第一次)。

  1. In [10]: import time
  2. In [11]: s = time.perf_counter(); op.task_2(); f = time.perf_counter(); f - s
  3. Out[11]: 8.617467135000027
  4. In [12]: s = time.perf_counter(); op.task_2(); f = time.perf_counter(); f - s
  5. Out[12]: 8.663589091999995

cmder.exe中运行结果:

  1. E:\test1
  2. $ python3 opencv_pil_time.py
  3. ========================================
  4. Function name:
  5. task_1
  6. ========================================
  7. Function has the return content below:
  8. None
  9. ========================================
  10. Summary of Function Timer:
  11. Count of loops: 100
  12. Average time of loops: 0.0016054189199999984 (sec)
  13. Minimum of every loop time: 0.0013979550000000063 (sec)
  14. Maximum of every loop time: 0.0057973939999999835 (sec)
  15. Total time of loops: 0.16054189199999985 (sec)
  16. ========================================
  17. ========================================
  18. Function name:
  19. task_3
  20. ========================================
  21. Function has the return content below:
  22. None
  23. ========================================
  24. Summary of Function Timer:
  25. Count of loops: 100
  26. Average time of loops: 0.013229802739999979 (sec)
  27. Minimum of every loop time: 0.01082132600000002 (sec)
  28. Maximum of every loop time: 0.018015121000000023 (sec)
  29. Total time of loops: 1.3229802739999978 (sec)
  30. ========================================
  31. ========================================
  32. Function name:
  33. task_4
  34. ========================================
  35. Function has the return content below:
  36. None
  37. ========================================
  38. Summary of Function Timer:
  39. Count of loops: 100
  40. Average time of loops: 2.1959869999998995e-05 (sec)
  41. Minimum of every loop time: 3.109999999750812e-07 (sec)
  42. Maximum of every loop time: 0.0021468490000000617 (sec)
  43. Total time of loops: 0.0021959869999998993 (sec)
  44. ========================================
  45. ========================================
  46. Function name:
  47. task_5_matrix
  48. ========================================
  49. Function has the return content below:
  50. None
  51. ========================================
  52. Summary of Function Timer:
  53. Count of loops: 100
  54. Average time of loops: 1.4977880000011101e-05 (sec)
  55. Minimum of every loop time: 1.0263000000065858e-05 (sec)
  56. Maximum of every loop time: 4.571699999988965e-05 (sec)
  57. Total time of loops: 0.0014977880000011101 (sec)
  58. ========================================
  59. ========================================
  60. Function name:
  61. task_5_pillow
  62. ========================================
  63. Function has the return content below:
  64. None
  65. ========================================
  66. Summary of Function Timer:
  67. Count of loops: 100
  68. Average time of loops: 0.0029445669399999997 (sec)
  69. Minimum of every loop time: 0.0026519169999998926 (sec)
  70. Maximum of every loop time: 0.00473345600000008 (sec)
  71. Total time of loops: 0.29445669399999996 (sec)
  72. ========================================
  73. ========================================
  74. Function name:
  75. task_6_opencv
  76. ========================================
  77. Function has the return content below:
  78. None
  79. ========================================
  80. Summary of Function Timer:
  81. Count of loops: 100
  82. Average time of loops: 0.02255292473999999 (sec)
  83. Minimum of every loop time: 0.021661312000000432 (sec)
  84. Maximum of every loop time: 0.032752587999999694 (sec)
  85. Total time of loops: 2.255292473999999 (sec)
  86. ========================================
  87. ========================================
  88. Function name:
  89. task_6_pillow
  90. ========================================
  91. Function has the return content below:
  92. None
  93. ========================================
  94. Summary of Function Timer:
  95. Count of loops: 100
  96. Average time of loops: 0.00025689415000005765 (sec)
  97. Minimum of every loop time: 0.0001309319999993619 (sec)
  98. Maximum of every loop time: 0.011476918999999697 (sec)
  99. Total time of loops: 0.025689415000005766 (sec)
  100. ========================================
  101. ========================================
  102. Function name:
  103. task_7_list
  104. ========================================
  105. Function has the return content below:
  106. None
  107. ========================================
  108. Summary of Function Timer:
  109. Count of loops: 100
  110. Average time of loops: 0.38457812533999997 (sec)
  111. Minimum of every loop time: 0.3564736689999961 (sec)
  112. Maximum of every loop time: 0.4698194010000005 (sec)
  113. Total time of loops: 38.457812534 (sec)
  114. ========================================
  115. ========================================
  116. Function name:
  117. task_7_asarray
  118. ========================================
  119. Function has the return content below:
  120. None
  121. ========================================
  122. Summary of Function Timer:
  123. Count of loops: 100
  124. Average time of loops: 0.007278045390000258 (sec)
  125. Minimum of every loop time: 0.007068772000003776 (sec)
  126. Maximum of every loop time: 0.007784698999998341 (sec)
  127. Total time of loops: 0.7278045390000258 (sec)
  128. ========================================
  129. ========================================
  130. Function name:
  131. task_7_array
  132. ========================================
  133. Function has the return content below:
  134. None
  135. ========================================
  136. Summary of Function Timer:
  137. Count of loops: 100
  138. Average time of loops: 0.010643305210000377 (sec)
  139. Minimum of every loop time: 0.009964515000000063 (sec)
  140. Maximum of every loop time: 0.011806892999999263 (sec)
  141. Total time of loops: 1.0643305210000378 (sec)
  142. ========================================
  143. ========================================
  144. Function name:
  145. task_8_matrix
  146. ========================================
  147. Function has the return content below:
  148. None
  149. ========================================
  150. Summary of Function Timer:
  151. Count of loops: 100
  152. Average time of loops: 2.8363499999528583e-06 (sec)
  153. Minimum of every loop time: 1.5549999972108708e-06 (sec)
  154. Maximum of every loop time: 4.1673999994884525e-05 (sec)
  155. Total time of loops: 0.00028363499999528585 (sec)
  156. ========================================
  157. ========================================
  158. Function name:
  159. task_8_pillow_putpixel
  160. ========================================
  161. Function has the return content below:
  162. None
  163. ========================================
  164. Summary of Function Timer:
  165. Count of loops: 100
  166. Average time of loops: 2.1925700001901305e-06 (sec)
  167. Minimum of every loop time: 1.2439999963476112e-06 (sec)
  168. Maximum of every loop time: 2.1769999996479328e-05 (sec)
  169. Total time of loops: 0.00021925700001901305 (sec)
  170. ========================================
  171. ========================================
  172. Function name:
  173. task_8_pillow_point
  174. ========================================
  175. Function has the return content below:
  176. None
  177. ========================================
  178. Summary of Function Timer:
  179. Count of loops: 100
  180. Average time of loops: 2.3574000000081697e-06 (sec)
  181. Minimum of every loop time: 1.5549999972108708e-06 (sec)
  182. Maximum of every loop time: 1.8971000002920846e-05 (sec)
  183. Total time of loops: 0.00023574000000081696 (sec)
  184. ========================================
  185. ========================================
  186. Function name:
  187. task_9_line_matrix
  188. ========================================
  189. Function has the return content below:
  190. None
  191. ========================================
  192. Summary of Function Timer:
  193. Count of loops: 100
  194. Average time of loops: 0.0004368183000000414 (sec)
  195. Minimum of every loop time: 0.0004301160000039772 (sec)
  196. Maximum of every loop time: 0.000561359000002426 (sec)
  197. Total time of loops: 0.04368183000000414 (sec)
  198. ========================================
  199. ========================================
  200. Function name:
  201. task_9_line_pillow
  202. ========================================
  203. Function has the return content below:
  204. None
  205. ========================================
  206. Summary of Function Timer:
  207. Count of loops: 100
  208. Average time of loops: 3.4956700000066122e-06 (sec)
  209. Minimum of every loop time: 2.4879999998006497e-06 (sec)
  210. Maximum of every loop time: 2.519200000250521e-05 (sec)
  211. Total time of loops: 0.0003495670000006612 (sec)
  212. ========================================
  213. ========================================
  214. Function name:
  215. task_9_line_opencv
  216. ========================================
  217. Function has the return content below:
  218. None
  219. ========================================
  220. Summary of Function Timer:
  221. Count of loops: 100
  222. Average time of loops: 3.5982899999709163e-06 (sec)
  223. Minimum of every loop time: 2.4879999998006497e-06 (sec)
  224. Maximum of every loop time: 4.727200000331777e-05 (sec)
  225. Total time of loops: 0.0003598289999970916 (sec)
  226. ========================================
  227. ========================================
  228. Function name:
  229. task_9_rectangle_matrix
  230. ========================================
  231. Function has the return content below:
  232. None
  233. ========================================
  234. Summary of Function Timer:
  235. Count of loops: 100
  236. Average time of loops: 0.1735227326999994 (sec)
  237. Minimum of every loop time: 0.17267937900000163 (sec)
  238. Maximum of every loop time: 0.19454626299999944 (sec)
  239. Total time of loops: 17.35227326999994 (sec)
  240. ========================================
  241. ========================================
  242. Function name:
  243. task_9_rectangle_pillow
  244. ========================================
  245. Function has the return content below:
  246. None
  247. ========================================
  248. Summary of Function Timer:
  249. Count of loops: 100
  250. Average time of loops: 3.0409819999803745e-05 (sec)
  251. Minimum of every loop time: 2.9545000003849964e-05 (sec)
  252. Maximum of every loop time: 7.153000000670318e-05 (sec)
  253. Total time of loops: 0.0030409819999803744 (sec)
  254. ========================================
  255. ========================================
  256. Function name:
  257. task_9_rectangle_opencv
  258. ========================================
  259. Function has the return content below:
  260. None
  261. ========================================
  262. Summary of Function Timer:
  263. Count of loops: 100
  264. Average time of loops: 6.522652000001016e-05 (sec)
  265. Minimum of every loop time: 6.25109999958795e-05 (sec)
  266. Maximum of every loop time: 0.0002674619999964989 (sec)
  267. Total time of loops: 0.006522652000001017 (sec)
  268. ========================================
  269. ========================================
  270. Function name:
  271. task_9_circle_pillow_arc
  272. ========================================
  273. Function has the return content below:
  274. None
  275. ========================================
  276. Summary of Function Timer:
  277. Count of loops: 100
  278. Average time of loops: 2.7626349999891885e-05 (sec)
  279. Minimum of every loop time: 2.6745999996080627e-05 (sec)
  280. Maximum of every loop time: 6.531100000017886e-05 (sec)
  281. Total time of loops: 0.0027626349999891886 (sec)
  282. ========================================
  283. ========================================
  284. Function name:
  285. task_9_circle_pillow_ellipse
  286. ========================================
  287. Function has the return content below:
  288. None
  289. ========================================
  290. Summary of Function Timer:
  291. Count of loops: 100
  292. Average time of loops: 0.0002000553400001337 (sec)
  293. Minimum of every loop time: 0.00019841900000017176 (sec)
  294. Maximum of every loop time: 0.0002512900000013474 (sec)
  295. Total time of loops: 0.02000553400001337 (sec)
  296. ========================================
  297. ========================================
  298. Function name:
  299. task_9_circle_opencv_circle
  300. ========================================
  301. Function has the return content below:
  302. None
  303. ========================================
  304. Summary of Function Timer:
  305. Count of loops: 100
  306. Average time of loops: 6.074186999960318e-05 (sec)
  307. Minimum of every loop time: 5.815699999800472e-05 (sec)
  308. Maximum of every loop time: 0.00016856299999545854 (sec)
  309. Total time of loops: 0.006074186999960318 (sec)
  310. ========================================
  311. ========================================
  312. Function name:
  313. task_9_circle_opencv_ellipse
  314. ========================================
  315. Function has the return content below:
  316. None
  317. ========================================
  318. Summary of Function Timer:
  319. Count of loops: 100
  320. Average time of loops: 6.716407000013192e-05 (sec)
  321. Minimum of every loop time: 6.593300000190538e-05 (sec)
  322. Maximum of every loop time: 0.00012471200000163662 (sec)
  323. Total time of loops: 0.0067164070000131915 (sec)
  324. ========================================
  325. ========================================
  326. Function name:
  327. task_9_ellipse_pillow
  328. ========================================
  329. Function has the return content below:
  330. None
  331. ========================================
  332. Summary of Function Timer:
  333. Count of loops: 100
  334. Average time of loops: 0.0002104615099997176 (sec)
  335. Minimum of every loop time: 0.00020619399999333154 (sec)
  336. Maximum of every loop time: 0.00040772399999866593 (sec)
  337. Total time of loops: 0.021046150999971758 (sec)
  338. ========================================
  339. ========================================
  340. Function name:
  341. task_9_ellipse_opencv
  342. ========================================
  343. Function has the return content below:
  344. None
  345. ========================================
  346. Summary of Function Timer:
  347. Count of loops: 100
  348. Average time of loops: 8.027900999998394e-05 (sec)
  349. Minimum of every loop time: 7.837199999727318e-05 (sec)
  350. Maximum of every loop time: 0.00020712799999955678 (sec)
  351. Total time of loops: 0.008027900999998394 (sec)
  352. ========================================
  353. ========================================
  354. Function name:
  355. task_9_text_pillow
  356. ========================================
  357. Function has the return content below:
  358. None
  359. ========================================
  360. Summary of Function Timer:
  361. Count of loops: 100
  362. Average time of loops: 0.0007998544599997359 (sec)
  363. Minimum of every loop time: 0.0007778169999994589 (sec)
  364. Maximum of every loop time: 0.0016240550000006237 (sec)
  365. Total time of loops: 0.07998544599997359 (sec)
  366. ========================================
  367. ========================================
  368. Function name:
  369. task_9_text_opencv
  370. ========================================
  371. Function has the return content below:
  372. None
  373. ========================================
  374. Summary of Function Timer:
  375. Count of loops: 100
  376. Average time of loops: 3.116865999970742e-05 (sec)
  377. Minimum of every loop time: 3.0166999998471056e-05 (sec)
  378. Maximum of every loop time: 9.610000000037644e-05 (sec)
  379. Total time of loops: 0.0031168659999707415 (sec)
  380. ========================================
  381. ========================================
  382. Function name:
  383. task_11_pillow
  384. ========================================
  385. Function has the return content below:
  386. None
  387. ========================================
  388. Summary of Function Timer:
  389. Count of loops: 100
  390. Average time of loops: 0.033835311859999495 (sec)
  391. Minimum of every loop time: 0.03373037900000497 (sec)
  392. Maximum of every loop time: 0.034273077999998236 (sec)
  393. Total time of loops: 3.3835311859999493 (sec)
  394. ========================================
  395. ========================================
  396. Function name:
  397. task_11_opencv_imread
  398. ========================================
  399. Function has the return content below:
  400. None
  401. ========================================
  402. Summary of Function Timer:
  403. Count of loops: 100
  404. Average time of loops: 0.028288081510000042 (sec)
  405. Minimum of every loop time: 0.028133581999995272 (sec)
  406. Maximum of every loop time: 0.02905974700000513 (sec)
  407. Total time of loops: 2.828808151000004 (sec)
  408. ========================================
  409. ========================================
  410. Function name:
  411. task_11_opencv_asarray
  412. ========================================
  413. Function has the return content below:
  414. None
  415. ========================================
  416. Summary of Function Timer:
  417. Count of loops: 100
  418. Average time of loops: 0.02815422919999975 (sec)
  419. Minimum of every loop time: 0.0279864769999989 (sec)
  420. Maximum of every loop time: 0.029095201000004067 (sec)
  421. Total time of loops: 2.8154229199999747 (sec)
  422. ========================================
  423. ========================================
  424. Function name:
  425. task_11_opencv_array
  426. ========================================
  427. Function has the return content below:
  428. None
  429. ========================================
  430. Summary of Function Timer:
  431. Count of loops: 100
  432. Average time of loops: 0.028195894160001414 (sec)
  433. Minimum of every loop time: 0.028047434000001203 (sec)
  434. Maximum of every loop time: 0.02866104100000655 (sec)
  435. Total time of loops: 2.8195894160001416 (sec)
  436. ========================================

(很奇怪为什么循环次数都是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 参数含义

[6]python中cv2.putText参数详解

[7]Python 3.7 timeit

【Python | opencv+PIL】常见操作(创建、添加帧、绘图、读取等)的效率对比及其优化的更多相关文章

  1. python opencv 按一定间隔截取视频帧

    前言关于opencvOpenCV 是 Intel 开源计算机视觉库 (Computer Version) .它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法. ...

  2. python Opencv图像基础操作

    读取并显示图像 如果读取图像首先要导入OpenCV包,方法为: import cv2 读取并显示图像 img = cv2.imread("C:\test1.jpg") OpenCV ...

  3. python 字典的常见操作

    字典 字典的增删改查 字典的创建方式: # 创建字典类型 info = { 'name':'李白', ', 'sex':'男' } msg = { 'user01':'Longzeluola', 'u ...

  4. python opencv:像素操作

    图片的像素 像素:组成图片的单位 RGB:颜色由 RGB三种颜色组成 颜色深度:对于8bit的颜色深度来说,它可以表示的颜色范围是 0 ~ 255,对于RGB图片来说,8位颜色深度可以表示 (2^8) ...

  5. Python opencv PIL numpy base64互相转化

    PIL2numpy and numpy2PIL from PIL import Image import numpy image = Image.open('timg.jpeg')# image is ...

  6. python字符串的常见操作

    find: 根据指定字符串获取对应的下标, 如果找不到对应的数据返回-1, 这里的-1表示没有找到数据 my_str = "hello" # find: 根据指定字符串获取对应的下 ...

  7. 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 ...

  8. Python中字符串常见操作

    (1)find 查找 格式:mystr.find(str, start, end) 例如: mystr.find(str, start=0, end=len(mystr)) 作用:检测str是否包含在 ...

  9. 【代码学习】PYTHON字符串的常见操作

    一.字符串运算符 下表实例变量 a 值为字符串 "Hello",b 变量值为 "Python": 操作符 描述 实例 + 字符串连接 >>>a ...

随机推荐

  1. 3、Web server 之httpd2.2 配置说明

    http协议实现的程序 静态(httpd, nginx, lighttpd) 动态 (IIS, tomcat,  jetty,  jboss,  resin,  websphere, weblogic ...

  2. CF786E ALT

    题意 有一棵 \(n\) 个点的树和 \(m\) 个人,第 \(i\) 个人从 \(u_i\) 走到 \(v_i\) 现在要发宠物,要求一个人要么他自己发到宠物,要么他走的路径上的都有宠物. 求最小代 ...

  3. Python3 输入和输出(二)

    接上一节 1.读写文件的模式图 将字符串写入到文件 foo.txt 中: #!/usr/bin/python3 # 打开一个文件f = open("/tmp/foo.txt", & ...

  4. (转)hadoop 集群常用端口

    转载于:https://www.cnblogs.com/liying123/p/7097806.html hadoop集群的各部分一般都会使用到多个端口,有些是daemon之间进行交互之用,有些是用于 ...

  5. 小程序 之修改radio默认样式

    一.效果图 二.代码 /* 选中后的 背景样式 (红色背景 无边框 可根据UI需求自己修改) */ radio .wx-radio-input.wx-radio-input-checked { bor ...

  6. [后渗透]Linux下的几种隐藏技术【转载】

    原作者:Bypass 原文链接:转自Bypass微信公众号 0x00 前言 攻击者在获取服务器权限后,会通过一些技巧来隐藏自己的踪迹和后门文件,本文介绍Linux下的几种隐藏技术. 0x01 隐藏文件 ...

  7. JavaScript中获取html元素常用手法和区分

    对于许多前端开发项目来说,获取元素进行操作是必不可少的,例如tab标签,全屏切换,自动滚播等效果都需要通过获取节点元素来实现.下面我来总结下JavaScript最常用的4个Document对象中获取元 ...

  8. Alpha项目冲刺! Day2-产出

    各个成员今日完成的任务 林恩:任务分工,博客撰写,设计设置等模块 杨长元:学习安卓本地数据库建立 李震:如何写登录界面登录页面,如何下载模板 胡彤:连接服务端 寇永明:提供页面 王浩:提供页面 李杰: ...

  9. 解决GitHub上传大于100M文件失败

    目录 问题 解决 参考 问题 push的时候遇到以下问题: remote: error: GH001: Large files detected. You may want to try Git La ...

  10. 微信小程序里自定义组件,canvas组件没有效果

    methods: { /** * el:画圆的元素 * r:圆的半径 * w:圆的宽度 * 功能:画背景 */ drawCircleBg: function (el, r, w) { const ct ...