GPUありなしでの、画像キャプチャー・OpenCV速度比較

#概要
最近、PCを新調しました。
以前、OpenCVで遊んでいたとき、画像処理のfpsが10fps程度しか出なくて、微妙だな～と思っていたので、PCを変えてどんな感じになったのか調べようと思います。
ついでにGPUについて、GTX1660superとIntel内蔵グラフィックで比較します。

すでに、たぶん誰かやってると思うのですが、見つからなかったので書いてます。
ほかに同じことをしている記事があったら教えてください。読みたい。

#環境

* Python3 (anaconda3導入-Spyderで実行)
* Windows 10 Home 64bit

#比較対象PCスペック

###旧PC

* core i5-6200U @2.3GHz  2core-4threads
* Intel HD Graphics 520
* 12GBメモリ
* SSD

###新PC-内蔵GPU

* core i9-9900k @3.6GHz 8core-16threads
* Intel HD Graphics 630
* SSD

###新PC-GPU

* core i9-9900k @3.6GHz
* Zotac GTX1660-super
* SSD

#Cine-bench R20 結果

|PC |  ベンチ結果|
|-----|----|
| 旧PC |  613|
| 新PC-内蔵GPU|4741|
| 新PC-GPU|4839|
GPUには全く依存しません。

#FFXV_bench
1920*1080,標準品質

|PC |  ベンチ結果|
|-----|----|
| 旧PC |547:動作困難|
| 新PC-内蔵GPU|708:動作困難|
| 新PC-GPU|8379:快適|
メモリがギリギリなのと、GPUがないと全然だめですね

#画像キャプチャー bench

###画像キャプチャー(mssライブラリ利用)
mss というライブラリの中で画面キャプチャができます。

```python
pip install mss
```
が必要です。
time というライブラリで経過時間$[s]$を取得します。
1000回画面をキャプチャするのにかかった時間を比較します。
どこにボトルネックがあるかはわかりません。画像取得をせずに$while$ループさせると秒レベルでは計測できなかったので、画像キャプチャー部分

```python
sct.grab(monitor)
```
に時間がかかっているので間違いないと思います。

|PC |秒|
|-----|----|
| 旧PC |16.7(60fps)|
| 新PC-内蔵GPU|16.7(60fps)|
| 新PC-GPU|16.7(60fps)|

PCに接続しているディスプレイのリフレッシュレートが59.94Hzに設定されているため、こうなったと予想されます。


```python:capture_test.py
import cv2			#	OpenCVライブラリ
import numpy as np		#	Numpyライブラリ
from mss import mss
import time

sct = mss()

"""
動作確認用：動作確認後はコメントアウト
"""
#windowName = "capture"
#cv2.namedWindow(windowName)

n= 0
while True:
    if n == 0:
        start_time = time.time()
        
    if n>= 1000:  #1000回　繰り返した
        end_time = time.time()
        break
    """
    画像取得
    """        
    monitor = {"top": 300, "left": 170, "width": 600, "height": 200}
    img = np.array(sct.grab(monitor))
    
    """
    動作確認部
    """
    """
    img = img[:,:,0:3]
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    img = np.asarray(img)
    cv2.imshow(windowName,img)
    key = cv2.waitKey(1)
    if key ==ord('q'):                 #       end 処理
        break
    """
    
    n = n+ 1

cv2.destroyAllWindows()
img[0][0][0] = 1         #一回も使わないと、ダメかなと思い追加

print(end_time-start_time)
```

###画像キャプチャー(pyautoguiライブラリ利用)
有名なライブラリ"pyautogui"でやってみます。

|PC |秒|
|-----|----|
| 旧PC |68.1(15fpsに近い)|
| 新PC-内蔵GPU|34.1(30fpsに近い)|
| 新PC-GPU|33.4(30fpsに近い)|

15,30,60fpsとPCの性能に合わせて切りのいい数になるよう調整している可能性があります。
mssと比べて、GPU,CPUともに負荷が少し高くなりました。キャプチャー範囲の影響はほぼなかったです。どのPCでも負荷率は上限から余裕があるので、なぜ性能差が出るのか不思議です。

ただ、旧PCの15fpsは流石に低すぎて使いにくいです。

```python:capture_test_pyautogui.py
import cv2			#	OpenCVライブラリ
import numpy as np		#	Numpyライブラリ
import pyautogui
import time

"""
動作確認用：動作確認後はコメントアウト
"""
"""
windowName = "capture"
cv2.namedWindow(windowName)
"""
monitor = {"top": 300, "left": 170, "width": 600, "height": 600}
n= 0
while True:
    if n == 0:
        start_time = time.time()
        
    if n>= 1000:  #100回　繰り返した
        end_time = time.time()
        break
    """
    画像取得
    """        
    home = pyautogui.screenshot(region=(0,0,600,200))
    img = np.asarray(home)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    
    """
    動作確認部
    """
    """
    img = img[:,:,0:3]
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    img = np.asarray(img)
    cv2.imshow(windowName,img)
    key = cv2.waitKey(1)
    if key ==ord('q'):                 #       end 処理
        break
    """
    
    n = n+ 1

cv2.destroyAllWindows()
img[0][0][0] = 1         #一回も使わないと、ダメかなと思い追加

print(end_time-start_time)
```

#OpenCV bench
試してみたい関数を列挙します。

* $cv2.matchTemplate$
* $cv2.circle$
* カメラキャプチャ（使用カメラは30fps）
* $cv2.imshow$
* $cv2.minMaxLoc$

基本的に、画像認識をしたいのでこんな感じです。

###cv2.imshow
"同じ"画像を繰り返し表示するので、”違う画像”ではちょっと違う結果になるかもしれません。
画像の大きさに大きく影響を受けていました。
CPU負荷が高い気がします

------
画像サイズ100*100

|PC |秒|
|-----|----|
| 旧PC ||
| 新PC-内蔵GPU|0.015~0.017|
| 新PC-GPU|0.017|

------
画像サイズ300*300

|PC |秒|
|-----|----|
| 旧PC ||
| 新PC-内蔵GPU|0.08|
| 新PC-GPU|0.083~0.084|

------
画像サイズ800*800

|PC |秒|
|-----|----|
| 旧PC ||
| 新PC-内蔵GPU|1.20~1.23|
| 新PC-GPU|1.11~1.13|

------
画像サイズ2000*2000

|PC |秒|
|-----|----|
| 旧PC ||
| 新PC-内蔵GPU|8.5~8.9|
| 新PC-GPU|8.0~8.2|

####結果

* GPUの影響はほぼなく、CPU依存
* 画面サイズの影響を強く受ける

####ベンチコード

```python:opencv_imshow.py
import cv2			#	OpenCVライブラリ
import numpy as np		#	Numpyライブラリ
import time

windowName = "capture"
cv2.namedWindow(windowName)

img = np.zeros((2000,2000,3))

n= 0
while True:
    if n == 0:
        start_time = time.time()
        
    if n>= 1000:  #100回　繰り返した
        end_time = time.time()
        break
    
    cv2.imshow(windowName,img)
    """
    #動作テスト
    key = cv2.waitKey(1)
    if key ==ord('q'):                 #       end 処理
        break
    """
    n = n+ 1

cv2.destroyAllWindows()
img[0][0][0] = 1         #一回も使わないと、ダメかなと思い追加

print(end_time-start_time)
```

###cv2.circle

|PC |秒|
|-----|----|
| 旧PC |0.0239~0.0269|
| 新PC-内蔵GPU|0.012|
| 新PC-GPU|0.013|

全然負荷はかからないようです。

```python:opencv_circle.py
import cv2			#	OpenCVライブラリ
import numpy as np		#	Numpyライブラリ
import time

windowName = "capture"
cv2.namedWindow(windowName)

img = np.zeros((500,500,3))

n= 0
while True:
    if n == 0:
        start_time = time.time()
        
    if n>= 1000:  #100回　繰り返した
        end_time = time.time()
        break
    
    cv2.circle(img, (int(n*0.5),50), 10, (0, 0, 255), 4)
    
    """
    動作確認部
    """
    """
    cv2.imshow(windowName,img)
    key = cv2.waitKey(1)
    if key ==ord('q'):                 #       end 処理
        break
    """
    
    
    n = n+ 1

cv2.destroyAllWindows()
img[0][0][0] = 1         #一回も使わないと、ダメかなと思い追加

print(end_time-start_time)
```

###cv2.matchTemplate
この処理は一番処理が重いイメージがあります。
また、画像サイズの影響を強く受けました。

|PC |100回実行するのにかかった秒|
|-----|----|
| 旧PC ||
| 新PC-内蔵GPU||
| 新PC-GPU|4.413|

```python

import cv2			#	OpenCVライブラリ
import numpy as np		#	Numpyライブラリ
import time

windowName = "capture"
cv2.namedWindow(windowName)

x = 100
y = 100
depth = 3
img = np.zeros((1000,1000,depth),dtype = np.uint8)
object1 = np.random.randint(0,255,(x,y,depth),dtype = np.uint8)

n= 0
while True:
    if n == 0:
        start_time = time.time()
        
    if n>= 100:  #100回　繰り返した
        end_time = time.time()
        break
    
    img_ccoeff = cv2.matchTemplate(img, object1, cv2.TM_CCOEFF_NORMED)

    n = n+ 1

cv2.destroyAllWindows()

print(end_time-start_time)
```

###カメラキャプチャ（使用カメラは30fps）


###cv2.minMaxLoc

|PC |1000回実行するのにかかった秒|
|-----|----|
| 旧PC ||
| 新PC-内蔵GPU||
| 新PC-GPU|0.255|

まったく時間がかかっていないことがわかります。

```python:minmaxLoc_bench.py
import cv2			#	OpenCVライブラリ
import numpy as np		#	Numpyライブラリ
import time

windowName = "capture"
cv2.namedWindow(windowName)

x = 100
y = 100
depth = 3
img = np.zeros((1000,1000,depth),dtype = np.uint8)
object1 = np.random.randint(0,255,(x,y,depth),dtype = np.uint8)
img_ccoeff = cv2.matchTemplate(img, object1, cv2.TM_CCOEFF_NORMED)

n= 0
while True:
    if n == 0:
        start_time = time.time()
        
    if n>= 1000:  #100回　繰り返した
        end_time = time.time()
        break
    
    cMin, cMax1, pMin, pMax1 = cv2.minMaxLoc(img_ccoeff)
    n = n+ 1

cv2.destroyAllWindows()

print(end_time-start_time)
```

すみません．dbdが楽しすぎてそれどころではなくなったので，とりあえず今はこれで公開して，余裕のある時に更新します．