WebCFace 2.5.2
Web-based Communication Framework & Dashboard-like UI
Loading...
Searching...
No Matches
6-2. Image

Since
1.3 1.2 2.4
See also

画像データを送受信します。 画像のリサイズ、圧縮などの処理をサーバー側で行う機能があります。

送信

  • C++ 画像データを表す型として webcface::ImageFrame があります。 生の画像データがあればImageFrameのコンストラクタに渡すことができます。

    unsigned char data[640 * 480 * 3]; /* = {...}; */
    // dataの中身がImageFrameにコピーされる
    // sizeWH で幅と高さを指定、または sizeHW で高さと幅を指定
    // ver1.11以前: サイズは高さ,幅の順で指定
    // webcface::ImageFrame frame(480, 640, data, webcface::ImageColorMode::rgb);
    (ver1.3から追加) 画像データ
    Definition image_frame.h:101
    Size sizeWH(int width, int height)
    幅 × 高さ でサイズを指定
    Definition image_frame.h:48

    ImageColorModeとしては gray(8bitグレースケール)、rgb(8bit×3)、bgr(8bit×3)、rgba(8bit×4)、bgra(8bit×4) が扱えます。

    Note
    ImageFrameオブジェクト内部では画像データはshared_ptr<vector<unsigned char>>で保持されます。
    ImageFrameのコンストラクタにdataのポインタを渡した場合、 dataの内容(width × height × channels() バイト)がすべてコピーされます。
    ImageFrameをコピーした場合は画像データが共有されます(コピーされません)。

    Client::image からImageオブジェクトを作り、 Image::set() でImageFrame型の画像データを代入し、Client::sync()することで送信されます。 set() の代わりに代入演算子(Image::operator=)でも同様のことができます。

    wcli.image("hoge").set(frame);
    wcli.image("hoge") = frame;
  • JavaScript 画像データを表す型として ImageFrame があります。 生の画像データがあればImageFrameのコンストラクタに渡すことができます。

    import { ImageFrame, imageColorMode } from "webcface";
    const data: ArrayBuffer = /* 640 * 480 * 3 バイトのデータ... */;
    // 画像サイズは 横, 縦 で指定
    const frame: ImageFrame = new ImageFrame(640, 480, data, imageColorMode.rgb);

    imageColorModeとしては gray(8bitグレースケール)、rgb(8bit×3)、bgr(8bit✕3)、rgba(8bit✕4)、bgra(8bit✕4) が扱えます。

    Client.image からImageオブジェクトを作り、 Image.set() でImageFrame型の画像データを代入し、Client.sync()することで送信されます。

    wcli.image("hoge").set(frame);
  • Python 画像データを表す型として webcface.ImageFrame があります。 生の画像データがあればImageFrameのコンストラクタに渡すことができます。

    from webcface import ImageFrame, ImageColorMode, ImageCompressMode
    # data: 640 * 480 * 3 バイトの bytes 型
    # 画像サイズは 横, 縦 で指定
    frame = ImageFrame(640, 480, data, ImageColorMode.RGB, ImageCompressMode.RAW)

    ImageColorModeとして GRAY(8bitグレースケール)、RGB(8bit×3)、BGR(8bit✕3)、RGBA(8bit✕4)、BGRA(8bit✕4) が扱えます。

    Client.image からImageオブジェクトを作り、 Image.set() でImageFrame型の画像データを代入し、Client.sync()することで送信されます。

    wcli.image("hoge").set(frame)

外部ライブラリの利用

  • OpenCV (C++) ImageFrame → cv::Mat
    cv::Mat img_mat(img_frame.rows(), img_frame.cols(), CV_8UC3, img_frame.data().data());
    cv::Mat → ImageFrame
    assert(img_mat.depth() == CV_8U);
    // https://stackoverflow.com/questions/26681713/convert-mat-to-array-vector-in-opencv
    if (img_mat.isContinuous()) {
    img_frame = webcface::ImageFrame(webcface::sizeHW(img_mat.rows, img_mat.cols),
    } else {
    img_frame = webcface::ImageFrame(webcface::sizeHW(img_mat.rows, img_mat.cols),
    for (int i = 0; i < mat.rows; ++i) {
    std::memcpy(&img_frame.at(i, 0, 0), mat.ptr<unsigned char>(i),
    mat.cols * mat.channels());
    }
    }
    const unsigned char & at(int row, int col, int ch=0) const
    画像の要素にアクセス
    Definition image_frame.h:257
    Size sizeHW(int height, int width)
    高さ × 幅 でサイズを指定
    Definition image_frame.h:55
  • Numpy (Python) ImageFrame → ndarray
    img_np = img_frame.numpy()
    assert img_np.shape == (height, width, img_frame.channels())
    ndarray → ImageFrame
    # 例: uint8, BGR形式の場合
    assert img_np.dtype == np.uint8
    assert img_np.shape == (height, width, 3)
    img_frame = ImageFrame.from_numpy(img_np, ImageColorMode.BGR)
C++ OpenCVと相互変換できるImageFrame (〜ver1.11まで)

画像データを表す型として webcface::ImageFrame があります。 cv::Mat形式 (CV_8UC1,CV_8UC3,CV_8UC4 フォーマットのみ) の画像データをImageFrameのコンストラクタに渡すことができます。

ImageColorModeとしては gray(8bitグレースケール)、rgb(8bit×3)、bgr(8bit×3)、rgba(8bit×4)、bgra(8bit×4) から元の画像データのフォーマットを指定してください。

Note
ImageFrameオブジェクト内部では画像データはshared_ptr<vector<unsigned char>>で保持されます。
ImageFrameのコンストラクタでcv::Mat内部の画像データがすべてコピーされます。
ImageFrameをコピーした場合は画像データが共有されます(コピーされません)。

ImageFrameをImageにsetして送信します。

wcli.image("hoge").set(frame);

(C++のみ) set() の代わりに代入演算子(Image::operator=)でも同様のことができます。

wcli.image("hoge") = frame;

ImageFrame::mat() でcv::Mat形式に変換できますが、その場合画像データ本体はImageFrameが保持しているためcv::Mat画像を使う間ImageFrameオブジェクトが破棄されないようにしてください。 (例えば wcli.member("foo").image("hoge").get().mat() はできません)
また、Imageを一度変数に入れて使うと、 Image::mat() で直接cv::Matに変換することもできます (この場合データ本体はImageが保持しています)

webcface::Image image = wcli.member("foo").image("hoge");
while(true){
cv::Mat data = image.mat(); // 内部で get() → mat() が呼ばれる
// ...
}
(ver1.3から追加) 画像の送受信データを表すクラス
Definition image.h:20
Note
圧縮された画像が入ったImageFrameをcv::Matに変換すると画像をデコードして返します。

受信

  • C++ Member::image() でImageクラスのオブジェクトが得られ、 Image::request() で画像のリクエストをした後 Image::tryGet() で受信した画像を取得できます。

    例えばfooというクライアントのhogeという名前のデータを取得したい場合は次のようにします。

    wcli.member("foo").image("hoge").request(); // 何も指定しない→元画像をそのまま受信
    while(true){
    std::optional<webcface::ImageFrame> frame = wcli.member("foo").image("hoge").tryGet();
    if(frame){
    //...
    }
    }
    • リクエストした画像を受信するまでの間tryGet()はstd::nulloptを返します。
    • get() を使うとstd::nulloptの代わりに空のImageFrameを返します。
      • (ImageFrame::empty() で空かどうかを判別できます)
    • ImageをImageFrameにキャストすることでも get() と同様に画像が得られます。
    • request() を1度も呼ばずに tryGet() や get() した場合、デフォルトのオプションで(元画像のフォーマットで)リクエストされます。
    • ImageFrameの中のデータには dataPtr() (shared_ptr<vector<unsigned char>>型)、 data() (vector<unsigned char>& 型)、 at(y, x, ch) (unsigned char &型) でアクセスできます。

    request() の引数に画像のサイズと色モードを指定すると、サーバー側で指定したフォーマットに変換されたものが取得できます。
    また送信側が高頻度で画像を更新する場合、フレームレートを指定するとそれより遅い頻度で受信させることもできます。

    // 64x48にリサイズ、さらに要素をRGBの順にし、1秒に5枚まで受信する
    wcli.member("foo").image("hoge").request(sizeWH(64, 48),
    // 幅が64になるようリサイズ(縦横比を維持)
    wcli.member("foo").image("hoge").request(sizeWH(64, std::nullopt),
    // サイズは元画像のままグレースケール
    wcli.member("foo").image("hoge").request(std::nullopt, webcface::ImageColorMode::gray);

    また jpeg, png, webp に圧縮した画像をリクエストすることでも通信量を減らすことができます。 詳細は webcface::Image::request() を参照

    // 64x48にリサイズ、さらにjpeg圧縮、1秒に5枚まで受信する
    wcli.member("foo").image("hoge").request(sizeWH(64, 48),
    5);

    圧縮された画像の場合 dataPtr() または data() を使ってバイナリデータとして取得できますが、 at() での要素アクセスはできません。

  • JavaScript Member.image() でImageクラスのオブジェクトが得られ、 Image.request() で画像のリクエストをした後 Image.tryGet() で受信した画像を取得できます。

    例えばfooというクライアントのhogeという名前のデータを取得したい場合は次のようにします。

    wcli.member("foo").image("hoge").request({}); // 何も指定しない→元画像をそのまま受信
    while(true){
    const frame: ImageFrame | null = wcli.member("foo").image("hoge").tryGet();
    if(frame){
    //...
    }
    }
    • リクエストした画像を受信するまでの間tryGet()はnullを返します。
    • Image.get() を使うとnullの代わりに空のImageFrameを返します。
    • request() を1度も呼ばずに tryGet() や get() した場合、デフォルトのオプションで(元画像のフォーマットで)リクエストされます。
    • 受信した画像は ImageFrame.data から取得できます。

    request() の引数に画像のサイズと色モードを指定すると、サーバー側で指定したフォーマットに変換されたものが取得できます。
    また送信側が高頻度で画像を更新する場合、フレームレートを指定するとそれより遅い頻度で受信させることもできます。
    request() の引数については ImageReq を参照

    // 64x48にリサイズ、さらに要素をRGBの順にし、1秒に5枚まで受信する
    wcli.member("foo").image("hoge").request({
    width: 64,
    height: 48,
    colorMode: imageColorMode.rgb,
    frameRate: 5,
    });
    // 幅が64になるようリサイズ(縦横比を維持)
    wcli.member("foo").image("hoge").request({
    width: 64,
    colorMode: imageColorMode.rgb,
    });
    // サイズは元画像のままグレースケール
    wcli.member("foo").image("hoge").request({
    colorMode: imageColorMode.gray,
    });

    また jpeg, png, webp に圧縮した画像をリクエストすることでも通信量を減らすことができます。

    // 64x48にリサイズ、さらにjpeg圧縮、1秒に5枚まで受信する
    wcli.member("foo").image("hoge").request({
    width: 64,
    height: 48,
    compressMode: imageCompressMode.jpeg,
    quality: 50,
    frameRate: 5,
    });

    圧縮された画像の場合も ImageFrame.data からバイナリデータとして取得できます。
    また、 ImageFrame.toBase64() でbase64にエンコードすることができます。

  • Python Member.image() でImageクラスのオブジェクトが得られ、 Image.request() で画像のリクエストをした後 Image.try_get() で受信した画像を取得できます。

    例えばfooというクライアントのhogeという名前のデータを取得したい場合は次のようにします。

    wcli.member("foo").image("hoge").request() # 何も指定しない→元画像をそのまま受信
    while True:
    frame = wcli.member("foo").image("hoge").try_get()
    if frame is not None:
    # ...
    • リクエストした画像を受信するまでの間try_get()はNoneを返します。
    • Image.get() を使うとNoneの代わりに空のImageFrameを返します。
      • (ImageFrame.empty() で空かどうかを判別できます)
    • request() を1度も呼ばずに try_get() や get() した場合、デフォルトのオプションで(元画像のフォーマットで)リクエストされます。
    • 受信した画像は ImageFrame.data, ImageFrame.numpy() から取得できます。

    request() の引数に画像のサイズと色モードを指定すると、サーバー側で指定したフォーマットに変換されたものが取得できます。
    また送信側が高頻度で画像を更新する場合、フレームレートを指定するとそれより遅い頻度で受信させることもできます。

    # 64x48にリサイズ、さらに要素をRGBの順にし、1秒に5枚まで受信する
    wcli.member("foo").image("hoge").request(
    width=64,
    height=48,
    color_mode=ImageColorMode.RGB,
    frame_rate=5,
    )
    # 幅が64になるようリサイズ(縦横比を維持)
    wcli.member("foo").image("hoge").request(
    width=64,
    color_mode=ImageColorMode.RGB,
    )
    # サイズは元画像のままグレースケール
    wcli.member("foo").image("hoge").request(
    color_mode=ImageColorMode.GRAY,
    )

    また jpeg, png, webp に圧縮した画像をリクエストすることでも通信量を減らすことができます。

    # 64x48にリサイズ、さらにjpeg圧縮、1秒に5枚まで受信する
    wcli.member("foo").image("hoge").request(
    width=64,
    height=48,
    compress_mode=ImageCompressMode.JPEG,
    quality=50,
    frame_rate=5,
    )

    圧縮された画像の場合も ImageFrame.data からバイナリデータとして取得できますが、 ImageFrame.numpy() は使えません。

Entry, Event

いずれも使い方は Value と同様なのでそちらを参照してください