PythonからSQLite3に保存した画像をC++ OpenCVでdecode

タイトルの日本語わかりにくくない?

ここでは画像はpng形式のものを使うことにします。適宜置き換えてください まずはPythonからsqlite3に画像を保存する。

import sqlite3

img_path = "hoge.png"

# open image and write byte to blob
with open(img_path, 'wb') as f:
    blob = f.read()

conn = sqlite3.connect("huga.db")
cur = conn.cursor()

cur.execute("create table if not exists test(id int primary, data blob)")
cur.execute(f"insert into test({blob})")
conn.commit()
cur.close()
conn.close()

次に画像をC++からopencvでdecode

#include "sqlite3.h"
#include <iostream>

int main()
{
    sqlite3* db;
    sqlite3_stmt* stmt;
    int ret = sqlite3_open("huga.db", &this->db);

    if (ret) {
        // failed
        sqlite3_close(db);
        return ;
    }

    ret = sqlite3_prepare_v2(this->db, "select * from test", -1, &this->stmt, nullptr);
    if (ret)
    {
        // failed
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return ;
    }
    unsigned char* blob = nullptr;
    int len = 0;

    while (SQLITE_ROW == (ret = sqlite3_step(this->stmt)))
    {
        len = sqlite3_column_bytes(this->stmt, 1);
        blob = (unsigned char*)sqlite3_column_blob(this->stmt, 1);

        std::vector<unsigned char> data(blob, blob + len);
    
        cv::Mat Image = cv::imdecode(data, 0);
        if (Image.empty()) continue;

        cv::imshow("a", Image);
        cv::waitKey(0);
    }
    sqlite3_finalize(stmt);
    sqlite3_close(db);
}

おまけ

PythonからSQLite3にbyte配列を渡すときに注意したいのが

import numpy as np
import cv2

img = cv2.imread("hoge.png")
# または
# img = np.full((10, 10), 0, 'uint8')みたいなとき 
blob = np.ndarray.tobytes(img)

これをそのままSQLite3に入れて取り出そうとすると配列の形式が違うためにクラッシュするので、

_, enc = cv2.imencode(".png", img)
blob = enc.tobytes()

こう書き換えてやるといい