【Python | opencv+PIL】常見操做(建立、添加幀、繪圖、讀取等)的效率對比及其優化

1、背景

本人準備用python作圖像和視頻編輯的操做,卻發現opencv和PIL的效率並非很理想,而且一樣的需求有多種不一樣的寫法並有着不一樣的效率。見全網並沒有較完整的效率對比文檔,遂決定本身豐衣足食。html

 

2、目的

本篇文章將對Python下的opencv接口函數及PIL(Pillow)函數的經常使用部分進行逐個運行並計時(屢次測算取平均時間和最短期,次數通常在100次以上),並簡單使用numba、ctypes、cython等方法優化代碼。python

 

3、測試方法及環境

1.硬件

CPU:Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz 3.30 GHzgit

內存:4.00 GBgithub

硬盤: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)api

各模塊:皆爲最新數組

(事情有所變化,暫時使用下面機房電腦的配置進行測試)數據結構

1.硬件

CPU:Intel(R) Xeon(R) Silver 4116 CPU @ 2.10GHz 2.10 GHzapp

內存: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)

各模塊:皆爲最新

 

4、具體實現

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]:

 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爲名字調用):

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.完整代碼

 

 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

 

 

5、結果

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更快一點。

 

6、優化

(待續)

 

7、總結反思

這個項目我大概從一個月前就有想法了,最近一週一直在抽時間作,淨時間估計都有十幾個小時了。最後一天(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

相關文章
相關標籤/搜索