Pythonでカメラを制御する【研究用】


## はじめに


前回の記事
[pySerialを使った顕微鏡用多波長LED光源の高速波長切り替えについて](https://qiita.com/opto-line/items/3be4e0a1f8ac00442807)

前回は顕微鏡用多波長LED光源の制御方法について書きました。今回はPythonによるカメラ制御について書きたいと思います。顕微鏡といえば肉眼で接眼レンズをのぞき込むイメージがありますが、実はカメラで撮影する場合が多いです。バイオ分野の研究者の中には顕微鏡メーカー各社が配布しているソフトウェアや有償ソフトを購入し、使っている方もいらっしゃいます。Pythonは無償ですので手軽に始められます。また、すでに解析プログラムをPythonで書かれている方は既存のプログラムにハードウェアの制御プログラムを組み込むことで測定フローの自動化ができるでしょう。塩基配列やアミノ酸配列を扱うような[Biopython](https://www.google.com/search?q=bio+python&oq=bio+python&aqs=chrome..69i57j0l5.6168j0j7&sourceid=chrome&ie=UTF-8)や機械学習と組み合わせることもでき、自由度がとても広がります。
定番である画像処理モジュールOpenCVを使ってカメラから画像を取得する方法について共有できればと思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509635/e2f3e3fb-393a-607e-ad6b-2d9e20d96035.jpeg" width=35%>


## 開発環境

- Windows10 (x64)
- Python 3.6
- Anaconda 3
- OpenCV 3.4.1

## 使用する機材

- カメラ: ARTCAM-226IMX-BW-USB3-T2(Artray社)
- PC

<img width="673" alt="Screen Shot 2020-06-29 at 23.10.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509635/9e717d98-4749-c48a-8078-571e74b91a57.png">
※図は[USB3.0 対応 CMOS カメラARTCAM-226IMX-USB3-T2 商品説明書](http://www.artray.co.jp/download/pmanual/ARTCAM-226IMX-USB3-T2_V095_20191218.pdf)より抜粋

##OpenCVのインストール
画像処理ライブラリOpenCVを各自インストールしてください。


##画像の取得
以下のプログラムを実行すると画像が取得できます。
まずはコピペして実行してみてください。



```python:capture.py

import cv2

# VideoCapture オブジェクトを取得します
capture = cv2.VideoCapture(1)

while(True):
    ret, frame = capture.read()
    # resize the window
    windowsize = (800, 600)
    frame = cv2.resize(frame, windowsize)
    
    cv2.imshow('title',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

capture.release()
cv2.destroyAllWindows()
```
こんな風にウィンドウ上に画像が表示されます。
![capture.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509635/2ba54205-4c9e-6252-7195-370a0452ae9d.png)

できない場合は、`cv2.VideoCapture(1)`の引数を`0`に変えてみてください。


ここでカメラの切り替えは`cv2.VideoCapture(0)`の引数で切り替えます。0が引数として設定されていますが2台目のカメラを使いたい場合は`cv2.VideoCapture(1)`と指定します。

## 画像の保存
名前と画像配列を指定して保存します。

```python
cv2.imwrite('test.tif', image_array)
```


##接続されているカメラの台数を数える
以下の関数のように、引数を`0, 1, 2, ...`と変えてあげると接続されたカメラの台数を調べられます。

```python:capture.py
import cv2
import datetime


def check_camera_connection():
    """
    Check the connection between any camera and the PC.

    """

    print('[', datetime.datetime.now(), ']', 'searching any camera...')
    true_camera_is = []  # 空の配列を用意

    # カメラ番号を0～9まで変えて、COM_PORTに認識されているカメラを探す
    for camera_number in range(0, 10):
        cap = cv2.VideoCapture(camera_number)
        ret, frame = cap.read()

        if ret is True:
            true_camera_is.append(camera_number)
            print("camera_number", camera_number, "Find!")

        else:
            print("camera_number", camera_number, "None")
    print("接続されているカメラは", len(true_camera_is), "台です。")


if __name__ == "__main__":
    check_camera_connection()
```
実行結果

```
[ 2019-10-04 18:17:51.607549 ] searching any camera...
camera_number 0 Find!
camera_number 1 Find!
camera_number 2 None
camera_number 3 None
camera_number 4 None
camera_number 5 None
camera_number 6 None
camera_number 7 None
camera_number 8 None
camera_number 9 None
接続されているカメラは 2 台です。
```
カメラが2台みつかりました。
0はノートPCのインカメ、1はPCにUSB接続されているカメラです。

## カメラのプロパティの取得
カメラの画素数や露光時間等の各種パラメーターを取得できる関数がOpenCVには用意されています。
`cap.get()`でカメラのプロパティを取得できます。

```python
def get_camera_propaties():
    params = ['MSEC',
            'POS_FRAMES',
            'POS_AVI_RATIO',
            'FRAME_WIDTH',
            'FRAME_HEIGHT',
            'PROP_FPS',
            'PROP_FOURCC',
            'FRAME_COUNT',
            'FORMAT',
            'MODE',
            'BRIGHTNESS',
            'CONTRAST',
            'SATURATION',
            'HUE',
            'GAIN',
            'EXPOSURE',
            'CONVERT_RGB',
            'WHITE_BALANCE',
            'RECTIFICATION']

    cap = cv2.VideoCapture(1)
    for num in range(19):
        print(params[num], ':', cap.get(num))
```
実行結果

```
POS_MSEC : 0.0
POS_FRAMES : 0.0
POS_AVI_RATIO : 0.0
FRAME_WIDTH : 1280.0
FRAME_HEIGHT : 720.0
FPS : 30.0
FOURCC : 0.0
FRAME_COUNT : 0.0
FORMAT : 16.0
MODE : 0.0
BRIGHTNESS : 0.0
CONTRAST : 0.0
SATURATION : 0.0
HUE : 0.0
GAIN : 0.0
EXPOSURE : 0.0
CONVERT_RGB : 0.0
WHITE_BALANCE : 0.0
RECTIFICATION : 0.0
```

カメラのプロパティをPythonから設定するためには、
`cap.set()`関数を使います。
>参考
>Python, OpenCVで動画を読み込み（ファイル・カメラ映像）
>https://note.nkmk.me/python-opencv-videocapture-file-camera/


設定できるかどうかはカメラの種類によって異なるため、詳しくはカメラメーカーに問い合わせていただければと思います。
パラメーターは以下の表を参考にしててください。

| 引数(数字)              |      　 引数(文字)　　 | プロパティー 　|
|:-----------------|:------------------:|:------------------:|
|0. |CV_CAP_PROP_POS_MSEC         　　　 |ビデオファイルの現在位置（ミリ秒）|                     
|1. |CV_CAP_PROP_POS_FRAMES　　　　　　　|  　　　　 次にデコード/キャプチャされるフレームの0から始まるインデックス|
|2.| CV_CAP_PROP_POS_AVI_RATIO 　　　　  | ビデオファイルの相対位置| 
|3.| CV_CAP_PROP_FRAME_WIDTH　　　　　  | 　 ビデオストリーム内のフレームの幅。|
|4.| CV_CAP_PROP_FRAME_HEIGHT　  |   ビデオストリーム内のフレームの高さ|
|5. |CV_CAP_PROP_FPS         |       フレームレート|
|6. |CV_CAP_PROP_FOURCC      |       コーデックの4文字のコード|
|7. |CV_CAP_PROP_FRAME_COUNT   |     ビデオファイルのフレーム数|
|8. |CV_CAP_PROP_FORMAT       |      retrieve（）によって返されるMatオブジェクトのフォーマット|
|9. |CV_CAP_PROP_MODE         |      現在のキャプチャモードを示すバックエンド固有の値|
|10.| CV_CAP_PROP_BRIGHTNESS   |     画像の明るさ（カメラのみ）|
|11.| CV_CAP_PROP_CONTRAST     |      画像のコントラスト（カメラのみ）|
|12.| CV_CAP_PROP_SATURATION   |      画像の彩度（カメラのみ）|
|13.| CV_CAP_PROP_HUE           |     画像の色相（カメラのみ）|
|14. |CV_CAP_PROP_GAIN          |     画像のゲイン（カメラのみ）|
|15. |CV_CAP_PROP_EXPOSURE      |     露出（カメラのみ）| 
|16.| CV_CAP_PROP_CONVERT_RGB   |     画像をRGBに変換するかどうかを示すブールフラグ|
|17. |CV_CAP_PROP_WHITE_BALANCE  |  現在サポートされていません|
|18. |CV_CAP_PROP_RECTIFICATION   |   ステレオカメラ用の整流フラグ（注：現在DC1394 v 2.xバックエンドでのみサポートされています）|

次回の記事
[Thorlabs自動ステージをPythonで動かす【研究用】](https://qiita.com/opto-line/items/68e144b2ee2e5b733f3d)