20
18

More than 5 years have passed since last update.

AWS SDK for C++を使ってS3にある画像をOpenCVで操作する

Last updated at Posted at 2015-10-10

AWS SDK for C++を使ってS3にある画像を取得して、OpenCVで操作してみようと思います。
https://github.com/awslabs/aws-sdk-cpp
OSはCentoOS7.1です。

環境構築

OpenCVとAWS SDK for C++をインストールします。

OpenCVのインストール

まずはOpenCVをインストールします。折角なので3.0.0を入れましょう。
必要なものをあらかじめ入れておきます。

$ sudo yum install -y gcc gcc-c++ cmake # コンパイルに必要
$ sudo yum install -y gtk3 gtk3-devel # GTKがないとウィンドウを表示できないよ

OpenCVを/opt/opencvにインストールします。

$ curl -o opencv-3.0.0.tar.gz https://codeload.github.com/Itseez/opencv/tar.gz/3.0.0
$ tar xvf opencv-3.0.0.tar.gz
$ mkdir opencv-3.0.0/build
$ cd opencv-3.0.0/build/
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/opencv ..
$ make -j4
$ sudo make install
$ echo '/opt/opencv/lib/' | sudo tee -a /etc/ld.so.conf
$ sudo ldconfig

これでOpenCVが入りました。

PKG_CONFIG_PATHの設定

さて、OpenCVを使ったコードをコンパイルするとき、ヘッダファイルが何処にあるのか、ライブラリが何処にあるのかを指定する必要があります。これらをリストアップしてくれるのがpkg-configというコマンドです。
このコマンドが使えるように設定します。

$ echo 'export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/opt/opencv/lib/pkgconfig' >> .bashrc
$ exec -l $SHELL
$ pkg-config --libs --cflags opencv
-I/opt/opencv/include/opencv -I/opt/opencv/include  -L/opt/opencv/lib -lopencv_calib3d -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_hal -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_video -lopencv_videoio -lopencv_videostab

pkg-config --libs --cflags opencvを実行すると動作を確認できます。

AWS SDK for C++のインストール

次はAWS SDK for C++のインストールです。実は少々てこずりました。
まずはgithubからダウンロードしてきます。

$ curl -LkO https://github.com/awslabs/aws-sdk-cpp/archive/master.zip
$ sudo yum install -y unzip # unzipがなかったら入れましょう
$ unzip master.zip

READMEを読むとlibcurllibopensslが必要そうなので、入れます。

$ sudo yum install -y libcurl-devel openssl-devel

さて、cmakeと行きたいところですが・・・

$ mkdir aws-sdk-cpp-master/build
$ cd aws-sdk-cpp-master/build/
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/aws-sdk-cpp ..

こんなことを言われてしまい、私は悲しみに包まれました。

CMake Error at CMakeLists.txt:16 (cmake_minimum_required):
  CMake 3.2.3 or higher is required.  You are running version 2.8.11


-- Configuring incomplete, errors occurred!

cmakeを入れます

cmakeのバージョンが低いといわれてしまったので、入れなおします。
ソースからビルドする方法を書いていましたが、yumで入れられることを知ったので、そちらの方法を取ろうと思います。

cmake 3.4.1をさくっとyumで入れます

リポジトリを追加してcmake 3.4.1を入れます。

$ sudo yum install -y epel-release
$ curl -sL https://copr.fedoraproject.org/coprs/g/kdesig/cmake3_EPEL/repo/epel-7/heliocastro-cmake3_EPEL-epel-7.repo | sudo tee /etc/yum.repos.d/heliocastro-cmake3_EPEL-epel-7.repo
$ sudo yum install -y cmake3

パスを通します。

$ echo 'export PATH=/usr/lib/cmake3/bin/:$PATH' >> ~/.bashrc
$ exec -l $SHELL
$ cmake --version
cmake version 3.4.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).

さくっとインストールできました。

改めてAWS SDK for C++のインストール

aws-sdk-cpp-master/build/に移動して改めてcmakeからやり直します。

$ cd ~/aws-sdk-cpp-master/build/
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/aws-sdk-cpp ..
$ make -j4
$ sudo make install
$ echo '/opt/aws-sdk-cpp/lib/linux/intel64/' | sudo tee -a /etc/ld.so.conf
$ sudo ldconfig

やっと入りました。

S3から画像を取得して表示するプログラム

ほいでは環境構築が済んだのでS3から画像を取得して表示するプログラムを書いて実行してみましょう。
https://github.com/awslabs/aws-sdk-cpp
https://aws.amazon.com/jp/blogs/aws/introducing-the-aws-sdk-for-c/
公式ブログやgithubのREADMEを参考にしました。

prog.cpp
#include <sstream>
#include <opencv2/opencv.hpp>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/GetObjectRequest.h>

const Aws::String AWS_ACCESS_KEY_ID = "XXXXXXXXXXXXXXXXXXXX";
const Aws::String AWS_SECRET_ACCESS_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

int main(int argc, char** argv) {

    Aws::Client::ClientConfiguration config;
    config.scheme = Aws::Http::Scheme::HTTPS;
    config.connectTimeoutMs = 30000;
    config.requestTimeoutMs = 30000;
    config.region = Aws::Region::AP_NORTHEAST_1;

    Aws::S3::S3Client s3Client(Aws::Auth::AWSCredentials(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), config);
    Aws::S3::Model::GetObjectRequest getObjectRequest;
    getObjectRequest.SetBucket("mybucket");
    getObjectRequest.SetKey("path/to/img.jpg");

    auto getObjectOutcome = s3Client.GetObject(getObjectRequest);
    if (!getObjectOutcome.IsSuccess()) {
        std::cerr << "File download failed from s3 with error " << getObjectOutcome.GetError().GetMessage() << std::endl;
        exit(1);
    }

    std::stringstream ss;
    ss << getObjectOutcome.GetResult().GetBody().rdbuf();
    std::string str = ss.str();
    std::vector<char> vec(str.begin(), str.end());
    cv::Mat img = cv::imdecode(cv::Mat(vec), CV_LOAD_IMAGE_COLOR);
    cv::imshow("window", img);
    cv::waitKey(0);

    return 0;
}

AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY、バケットや画像は各自で用意してくださいね。

コンパイルして実行し、目的の画像が表示されれば成功です。

$ g++ -DAWS_CUSTOM_MEMORY_MANAGEMENT -std=c++11 prog.cpp -I/opt/aws-sdk-cpp/include -L/opt/aws-sdk-cpp/lib/linux/intel64/ -laws-cpp-sdk-core -laws-cpp-sdk-s3 `pkg-config --libs --cflags opencv`
$ ./a.out

プログラムとコンパイルオプションについて

よく分かっていないところもありますが、自分なりの理解を書いてみます。

コンパイルオプションについて

C++11を使っているので、-std=c++11が必要なことと、ヘッダとライブラリの場所を指定するために-I/opt/aws-sdk-cpp/include -L/opt/aws-sdk-cpp/lib/linux/intel64/が必要なことは別に問題ないですね。
AWS SDK for C++では独自のメモリ管理システムを使っている(?)んですかね。-DAWS_CUSTOM_MEMORY_MANAGEMENTこちらのオプションが必要です(READMEを読むとcmake-DCUSTOM_MEMORY_MANAGEMENT=1を指定しろ、みたいに書いてあるんですが、指定すると何か変わるのかよくわかりませんでした)。

プログラムについて

まず、必要なヘッダをインクルードするのと、アクセスキーとシークレットキーを定義してます。
Aws::Client::ClientConfiguration configconnectTimeoutMsrequestTimeoutMsは、 https://github.com/awslabs/aws-sdk-cpp#using-a-service-client ここをパクりました。regionAws::Region::AP_NORTHEAST_1を指定したのは、目的のバケットが東京リージョンにあるからです。

んで、そのあとは公式ブログを真似してAws::S3::S3Client s3ClientGetObjectRequest getObjectRequest;を作って画像を取得します。

画像が取得ができたらgetObjectOutcome.GetResult().GetBody().rdbuf(); これでunderlying bufferにアクセスできます。ただ、OpenCVでこの画像を扱うためにはcv::Matに変換する必要があるんですよね。以下の方法でやります。

    std::stringstream ss;
    ss << getObjectOutcome.GetResult().GetBody().rdbuf();
    std::string str = ss.str();
    std::vector<char> v(str.begin(), str.end());
    cv::Mat img = cv::imdecode(cv::Mat(v), CV_LOAD_IMAGE_COLOR);

std::stringstreamstd::stringstd::vector<char>cv::Matという順番で変換すればOKです。自分でもなんだか回りくどいような気がしているのでもっといい方法がないか、と思っています(std::vector<char> v(ss.str.begin(), ss.str.end()) ってやれば良くね?と最初思いましたがダメでした。 http://stackoverflow.com/a/12267277 )。

おしまい

いろいろ理解不足なところもありますが、これでS3にある画像をOpenCVで操作できるようになりました。

20
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
18