pythonで画像をDBに登録し、DBから取得する


目的

業務にて画像をSQLite3のDBへ登録し保存する機能を実装する必要があり、調査を兼ね実装を行いました。

HTTPサーバーを兼ねたRaspberry PiにUSB接続のWebカメラを接続し、このカメラを外部から制御(画像の撮影)を行い、サーバー内のDBへ保存します。
外部機器(PC、スマートフォン)からサーバーへリクエストをかけたら、任意の画像を取得するなどの機能を実装する必要がありました。

今回は、有線接続したWebカメラから画像を取得し、DBへ保存、保存完了後にDBから画像を取得し、ローカルディレクトリに任意のファイルネームで保存するまでを実装しました。

開発環境

IDE

PyCharm Community Edition

ライブラリ

SQLite3
OpenCv
PyQt5

環境構築

pythonはHomebrewでインストールします。
SQLite3はpythonに標準で入っているので、インストールは不要です。

OpneCvはPyCharmからインストールしました。
Preference->Project Interpreterを開き、+ボタンを押します。
Availabel Packagesが開くので、opencv-pythonを検索し、Install Packageにてインストールしました。

PyQt5はHomebrewでインストールします。

brew install pyqt5

実装

save_db.py
import cv2
import sqlite3
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

class App (QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'Sample image to save to DB'
        self.left = 10
        self.top = 10
        self.width = 320
        self.height = 240
        self.initUI()

    def initUI(self):

        # ウィンドウのtitleを設定
        self.setWindowTitle(self.title)

        # ウィンドウサイズを設定
        self.setGeometry(self.left, self.top, self.width, self.height)

        # ボタンのtitleを設定
        buttton = QPushButton('Save Captcha to DB', self)
        # ボタンの意味を設定
        buttton.setToolTip('This is a button to save the camera Captcha image to DB')
        # ボタンの描画位置を設定
        buttton.move(80, 70)
        # ボタン押下処理を設定
        buttton.clicked.connect(self.on_click)

        self.show()

    def camera_capture(self):
        cap = cv2.VideoCapture(0)
        count = 0

        while count < 10:
            count+=1
            ret, frame = cap.read()
            # デバッグ用:画像表示
            #cv2.imshow('camera capture', frame)
            cv2.waitKey(1)

            if count == 10:
                # データベース作成・コネクション作成
                db = sqlite3.connect("my.db")
                # カーソルをコネクションから作成
                cur = db.cursor()
                # テーブル作成
                try:
                    cur.execute('''create table images (id string, img blob)''')
                except sqlite3.OperationalError:
                    print
                    "table images already exists!"

                # コネクションを保存(コミット)
                db.commit()

                # 画像エンコーディング
                _, enc = cv2.imencode(".png", frame)

                # データを追加
                sql = "insert into images values (?, ?)"
                cur.execute(sql, ("camera", memoryview(enc)))

                # コネクションを保存(コミット)
                db.commit()

                # データの読み出し
                # byteデータの取得
                row = cur.execute('SELECT * FROM images').fetchone()
                pic = row[1]

                # 画像保存
                f = open('load2DBforCameraImage.png', 'wb')
                f.write(pic)
                f.close()
                cur.close()
                # OpneCvでも画像保存
                cv2.imwrite("save.png", frame)

        cap.release()
        exit()


    @pyqtSlot()
    def on_click(self):
        print('button on click!')
        self.camera_capture()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

結果


中央のボタンを押下すると、画像をVideoCaptchaの画像をDBへ保存し、その後DBから取得しリネームしローカルディレクトに保存します。
ついでに、OpenCvのimwrite()メソッドでも保存を行っています。

現状では、VideoCaptcha()が起動し画像が取得できるまでに、すこし時間がかかるためカウンターを回し、10回カウントしたところで保存処理を行っています。
(C++書いていたときは、特にこんなコトはなかったんですけどね...)

上記のとおり、DBから取得しリネームした画像ファイルと、imwrite()メソッドで保存した2つのファイルが出来上がっていることがわかります。

おわりに

CやC++でゴリゴリコードを書いてきて、ここ最近MySQLやPHPなんかをやったりしていました。
今回取り組んだpythonによるSQLite画像の保存処理も、比較的簡単に記述できることがわかりました。
また、PyQt5によるGUIの作成も簡単に行えることがわかりました。
(ImGUIより簡単に書けますね!)

まだ、最終目的の機能は実装出来ていませんので、pythonによるGPIOの制御、javascriptとの連携処理などを実装していきたいと思います。

もっとスマートに記述できる箇所が多々あると思いますので、ツッコミ等頂けましたらと思います。
よろしくお願いします。