最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析Python 讀取圖像文件的性能對比

 更新時間:2019年03月07日 11:43:39   作者:BriFuture''s Blog  
這篇文章主要介紹了淺析Python 讀取圖像文件的性能對比,主要介紹了3種性能對比方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下

使用 Python 讀取一個保存在本地硬盤上的視頻文件,視頻文件的編碼方式是使用的原始的 RGBA 格式寫入的,即無壓縮的原始視頻文件。最開始直接使用 Python 對讀取到的文件數(shù)據(jù)進行處理,然后顯示在 Matplotlib 窗口上,后來發(fā)現(xiàn)視頻播放的速度比同樣的處理邏輯的 C++ 代碼慢了很多,嘗試了不同的方法,最終實現(xiàn)了在 Python 中讀取并顯示視頻文件,幀率能夠達到 120 FPS 以上。

讀取一幀圖片數(shù)據(jù)并顯示在窗口上

最簡單的方法是直接在 Python 中讀取文件,然后逐像素的分配 RGB 值到窗口中,最開始使用的是 matplotlib 的 pyplot 組件。

一些用到的常量:

FILE_NAME = "I:/video.dat"
WIDTH = 2096
HEIGHT = 150
CHANNELS = 4
PACK_SIZE = WIDTH * HEIGHT * CHANNELS

每幀圖片的寬度是 2096 個像素,高度是 150 個像素,CHANNELS 指的是 RGBA 四個通道,因此 PACK_SIZE 的大小就是一副圖片占用空間的字節(jié)數(shù)。

首先需要讀取文件。由于視頻編碼沒有任何壓縮處理,大概 70s 的視頻(每幀約占 1.2M 空間,每秒 60 幀)占用達 4Gb 的空間,所以我們不能直接將整個文件讀取到內(nèi)存中,借助 Python functools 提供的 partial 方法,我們可以每次從文件中讀取一小部分數(shù)據(jù),將 partial 用 iter 包裝起來,變成可迭代的對象,每次讀取一幀圖片后,使用 next 讀取下一幀的數(shù)據(jù),接下來先用這個方法將保存在文件中的一幀數(shù)據(jù)讀取顯示在窗口中。

with open( file, 'rb') as f:
  e1 = cv.getTickCount()
  records = iter( partial( f.read, PACK_SIZE), b'' ) # 生成一個 iterator
  frame = next( records ) # 讀取一幀數(shù)據(jù)
  img = np.zeros( ( HEIGHT, WIDTH, CHANNELS ), dtype = np.uint8)
  for y in range(0, HEIGHT):
    for x in range( 0, WIDTH ):
      pos = (y * WIDTH + x) * CHANNELS
      for i in range( 0, CHANNELS - 1 ):
        img[y][x][i] = frame[ pos + i ]
      img[y][x][3] = 255
  plt.imshow( img )
  plt.tight_layout()
  plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
  plt.xticks([])
  plt.yticks([])
  e2 = cv.getTickCount()
  elapsed = ( e2 - e1 ) / cv.getTickFrequency()
  print("Time Used: ", elapsed )
  plt.show()

需要說明的是,在保存文件時第 4 個通道保存的是透明度,因此值為 0,但在 matplotlib (包括 opencv)的窗口中顯示時第 4 個通道保存的一般是不透明度。我將第 4 個通道直接賦值成 255,以便能夠正常顯示圖片。

這樣就可以在我們的窗口中顯示一張圖片了,不過由于圖片的寬長比不協(xié)調(diào),使用 matplotlib 繪制出來的窗口必須要縮放到很大才可以讓圖片顯示的比較清楚。

為了方便稍后的性能比較,這里統(tǒng)一使用 opencv 提供的 getTickCount 方法測量用時??梢詮目刂婆_中看到顯示一張圖片,從讀取文件到最終顯示大概要用 1.21s 的時間。如果我們只測量三層嵌套循環(huán)的用時,可以發(fā)現(xiàn)有 0.8s 的時間都浪費在循環(huán)上了。


讀取并顯示一幀圖片用時 1.21s


在處理循環(huán)上用時 0.8s

約百萬級別的循環(huán)處理,同樣的代碼放在 C++ 里面性能完全沒有問題,在 Python 中執(zhí)行起來就不一樣了。在 Python 中這樣的處理速度最多就 1.2 fps。我們暫時不考慮其他方法進行優(yōu)化,而是將多幀圖片動態(tài)的顯示在窗口上,達到播放視頻的效果。

連續(xù)讀取圖片并顯示

這時我們繼續(xù)讀取文件并顯示在窗口上,為了能夠動態(tài)的顯示圖片,我們可以使用 matplotlib.animation 動態(tài)顯示圖片,之前的程序需要進行相應的改動:

fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
try:
  img = np.zeros( ( HEIGHT, WIDTH, CHANNELS ), dtype = np.uint8)
  f = open( FILE_NAME, 'rb' )
  records = iter( partial( f.read, PACK_SIZE ), b'' )
  
  def animateFromData(i):
    e1 = cv.getTickCount()
    frame = next( records ) # drop a line data
    for y in range( 0, HEIGHT ):
      for x in range( 0, WIDTH ):
        pos = (y * WIDTH + x) * CHANNELS
        for i in range( 0, CHANNELS - 1 ):
          img[y][x][i] = frame[ pos + i]
        img[y][x][3] = 255
    ax1.clear()
    ax1.imshow( img )
    e2 = cv.getTickCount()
    elapsed = ( e2 - e1 ) / cv.getTickFrequency()
    print( "FPS: %.2f, Used time: %.3f" % (1 / elapsed, elapsed ))

  a = animation.FuncAnimation( fig, animateFromData, interval=30 ) # 這里不要省略掉 a = 這個賦值操作
  plt.tight_layout()
  plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
  plt.xticks([])
  plt.yticks([])
  plt.show()
except StopIteration:
  pass
finally:
  f.close()

和第 1 部分稍有不同的是,我們顯示每幀圖片的代碼是在 animateFromData 函數(shù)中執(zhí)行的,使用 matplotlib.animation.FuncAnimation 函數(shù)循環(huán)讀取每幀數(shù)據(jù)(給這個函數(shù)傳遞的 interval = 30 這個沒有作用,因為處理速度跟不上)。另外值得注意的是不要省略掉 a = animation.FuncAnimation( fig, animateFromData, interval=30 ) 這一行的賦值操作,雖然不太清楚原理,但是當我把 a = 刪掉的時候,程序莫名的無法正常工作了。

控制臺中顯示的處理速度:

由于對 matplotlib 的了解不多,最開始我以為是 matplotlib 顯示圖像過慢導致了幀率上不去,打印出代碼的用時后發(fā)現(xiàn)不是 matplotlib 的問題。因此我也使用了 PyQt5 對圖像進行顯示,結(jié)果依然是 1~2 幀的處理速度。因為只是換用了 Qt 的界面進行顯示,邏輯處理的代碼依然沿用的 matplotlib.animation 提供的方法,所以并沒有本質(zhì)上的區(qū)別。這段用 Qt 顯示圖片的代碼來自于 github matplotlib issue,我對其進行了一些適配。

使用 Numpy 的數(shù)組處理 api

我們知道,顯示圖片這么慢的原因就是在于 Python 處理 2096 * 150 這個兩層循環(huán)占用了大量時間。接下來我們換用一種 numpyreshape 方法將文件中的像素數(shù)據(jù)讀取到內(nèi)存中。注意 reshape 方法接收一個 ndarray 對象。我這種每幀數(shù)據(jù)創(chuàng)造一個 ndarray 數(shù)組的方法可能會存在內(nèi)存泄漏的風險,實際上可以調(diào)用一個 ndarray 數(shù)組對象的 reshape 方法。這里不再深究。

重新定義一個用于動態(tài)顯示圖片的函數(shù) optAnimateFromData,將其作為參數(shù)傳遞個 FuncAnimation

def optAnimateFromData(i):
  e1 = cv.getTickCount()
  frame = next( records ) # one image data
  img = np.reshape( np.array( list( frame ), dtype = np.uint8 ), ( HEIGHT, WIDTH, CHANNELS ) )
  img[ : , : , 3] = 255
  ax1.clear()
  ax1.imshow( img )
  e2 = cv.getTickCount()
  elapsed = ( e2 - e1 ) / cv.getTickFrequency()
  print( "FPS: %.2f, Used time: %.3f" % (1 / elapsed, elapsed ))

a = animation.FuncAnimation( fig, optAnimateFromData, interval=30 )

效果如下,可以看到使用 numpyreshape 方法后,處理用時大幅減少,幀率可以達到 8~9 幀。然而經(jīng)過優(yōu)化后的處理速度仍然是比較慢的:


優(yōu)化過的代碼執(zhí)行結(jié)果

使用 Numpy 提供的 memmap

在用 Python 進行機器學習的過程中,發(fā)現(xiàn)如果完全使用 Python 的話,很多運算量大的程序也是可以跑的起來的,所以我確信可以用 Python 解決我的這個問題。在我不懈努力下找到 Numpy 提供的 memmap api,這個 API 以數(shù)組的方式建立硬盤文件到內(nèi)存的映射,使用這個 API 后程序就簡單一些了:

cv.namedWindow("file")
count = 0
start = time.time()
try:
  number = 1
  while True:
    e1 = cv.getTickCount()
    img = np.memmap(filename=FILE_NAME, dtype=np.uint8, shape=SHAPE, mode="r+", offset=count )
    count += PACK_SIZE
    cv.imshow( "file", img )
    e2 = cv.getTickCount()
    elapsed = ( e2 - e1 ) / cv.getTickFrequency()
    print("FPS: %.2f Used time: %.3f" % (number / elapsed, elapsed ))
    key = cv.waitKey(20)
    if key == 27: # exit on ESC
      break
except StopIteration:
  pass
finally:
  end = time.time()
  print( 'File Data read: {:.2f}Gb'.format( count / 1024 / 1024 / 1024), ' time used: {:.2f}s'.format( end - start ) )
  cv.destroyAllWindows()

將 memmap 讀取到的數(shù)據(jù) img 直接顯示在窗口中 cv.imshow( "file", img),每一幀打印出顯示該幀所用的時間,最后顯示總的時間和讀取到的數(shù)據(jù)大小:


執(zhí)行效率最高的結(jié)果

讀取速度非???,每幀用時只需幾毫秒。這樣的處理速度完全可以滿足 60FPS 的需求。

總結(jié)

Python 語言寫程序非常方便,但是原生的 Python 代碼執(zhí)行效率確實不如 C++,當然了,比 JS 還是要快一些。使用 Python 開發(fā)一些性能要求高的程序時,要么使用 Numpy 這樣的庫,要么自己編寫一個 C 語言庫供 Python 調(diào)用。在實驗過程中,我還使用 Flask 讀取文件后以流的形式發(fā)送的瀏覽器,讓瀏覽器中的 JS 文件進行顯示,不過同樣存在著很嚴重的性能問題和內(nèi)存泄漏問題。這個過程留到之后再講。

本文中的相應代碼可以在 github 上查看。

Reference

functools

partial

opencv

matplotlib animation

numpy

numpy reshape

memmap

matplotlib issue on github

C 語言擴展

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Python 開發(fā)工具PyCharm安裝教程圖文詳解(新手必看)

    Python 開發(fā)工具PyCharm安裝教程圖文詳解(新手必看)

    PyCharm是一種Python IDE,帶有一整套可以幫助用戶在使用Python語言開發(fā)時提高其效率的工具,比如調(diào)試、語法高亮、Project管理、代碼跳轉(zhuǎn)、智能提示、自動完成、單元測試、版本控制。今天通過本文給大家分享PyCharm安裝教程,一起看看吧
    2020-02-02
  • Python如何獲取響應體response body

    Python如何獲取響應體response body

    在Python中,我們可以使用多個庫來發(fā)送HTTP請求并獲取響應體(response body),其中requests就是最常用的庫之一,下面我們就來看看如何利用requests發(fā)送HTTP GET請求,并獲取響應體吧
    2024-11-11
  • Python編程實現(xiàn)下載器自動爬取采集B站彈幕示例

    Python編程實現(xiàn)下載器自動爬取采集B站彈幕示例

    這篇文章主要介紹了使用Python編程來實現(xiàn)一個下載器可以自動爬取采集B站彈幕的示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2021-10-10
  • Python+OpenCV進行不規(guī)則多邊形ROI區(qū)域提取

    Python+OpenCV進行不規(guī)則多邊形ROI區(qū)域提取

    ROI即感興趣區(qū)域。機器視覺、圖像處理中,從被處理的圖像以方框、圓、橢圓、不規(guī)則多邊形等方式勾勒出需要處理的區(qū)域,稱為感興趣區(qū)域,ROI。本文將利用Python和OpenCV實現(xiàn)不規(guī)則多邊形ROI區(qū)域提取,需要的可以參考一下
    2022-03-03
  • Pydantic中BaseConfig的具體使用

    Pydantic中BaseConfig的具體使用

    本文主要介紹了Pydantic中BaseConfig的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-06-06
  • python繪制二維直方圖的代碼實現(xiàn)

    python繪制二維直方圖的代碼實現(xiàn)

    本文主要介紹了python繪制二維直方圖的代碼實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • django model 條件過濾 queryset.filter(**condtions)用法詳解

    django model 條件過濾 queryset.filter(**condtions)用法詳解

    這篇文章主要介紹了django model 條件過濾 queryset.filter(**condtions)用法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • python獲取當前文件和目錄路徑的方法詳解

    python獲取當前文件和目錄路徑的方法詳解

    這篇文章主要介紹了Python中獲取當前文件路徑和目錄的方法,包括使用__file__關鍵字、os.path.abspath、os.path.realpath以及sys.path,文中還介紹了在使用這些函數(shù)時需要注意的事項,需要的朋友可以參考下
    2025-01-01
  • Python3之不使用第三方變量,實現(xiàn)交換兩個變量的值

    Python3之不使用第三方變量,實現(xiàn)交換兩個變量的值

    今天小編就為大家分享一篇Python3之不使用第三方變量,實現(xiàn)交換兩個變量的值,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • 如何利用python多線程爬取天氣網(wǎng)站圖片并保存

    如何利用python多線程爬取天氣網(wǎng)站圖片并保存

    最近做個天 氣方面的APP需要用到一些天氣數(shù)據(jù),所以下面這篇文章主要給大家介紹了關于如何利用python多線程爬取天氣網(wǎng)站圖片并保存的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-11-11

最新評論

毕节市| 曲靖市| 罗山县| 南京市| 崇明县| 长丰县| 沽源县| 丹阳市| 舒城县| 沐川县| 元阳县| 皋兰县| 长阳| 句容市| 鄂伦春自治旗| 华容县| 江北区| 鄂州市| 恩施市| 定远县| 平潭县| 随州市| 嘉定区| 调兵山市| 五寨县| 吴堡县| 黄平县| 鲁山县| 建宁县| 五家渠市| 名山县| 靖安县| 安国市| 什邡市| 韶关市| 襄汾县| 广河县| 临桂县| 杨浦区| 万宁市| 大名县|