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を読むとlibcurl
とlibopenssl
が必要そうなので、入れます。
$ 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を参考にしました。
#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_ID
やAWS_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 config
のconnectTimeoutMs
やrequestTimeoutMs
は、 https://github.com/awslabs/aws-sdk-cpp#using-a-service-client ここをパクりました。region
にAws::Region::AP_NORTHEAST_1
を指定したのは、目的のバケットが東京リージョンにあるからです。
んで、そのあとは公式ブログを真似してAws::S3::S3Client s3Client
とGetObjectRequest 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::stringstream
→std::string
→std::vector<char>
→cv::Mat
という順番で変換すればOKです。自分でもなんだか回りくどいような気がしているのでもっといい方法がないか、と思っています(std::vector<char> v(ss.str.begin(), ss.str.end())
ってやれば良くね?と最初思いましたがダメでした。 http://stackoverflow.com/a/12267277 )。
おしまい
いろいろ理解不足なところもありますが、これでS3にある画像をOpenCVで操作できるようになりました。