2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

g++によるopenCVのコンパイル

Last updated at Posted at 2020-08-17

最近CNNを学習しつつ,C++で一からコーディング中です.
画像認識をさせたくてopenCVで画素データ取得しようと思ったのですが,コンパイル段階でかなり苦戦しました...
コードも画像読み込みと画素取得だけなのに,コンパイルが通らなくて大変でした.

色々調べてpkg-configを使ったコンパイル方法などもあったのですが,うまく行かず.(後で原因わかりましたが)
おそらくopenCVをIDEではなくエディタ環境で使ってる人の多くが躓きそうだなぁと...

そこで,openCVの基本中の基本,画像読込み画素データ取得 のコードをコンパイルできるようにする事が目的です.
openCVを使いこなすことが目的ではなく,画素データ取得できればいいんだよ!という方向けです.

実行環境

OS : Arch Linux
OpenCV : 4.4.0
g++(GCC) : 10.1.0

実装

同一ディレクトリ内にあるsample.jpgというデータのRGB情報を取得,表示するだけのコードです.

hoge.cpp
#include <iostream>
#include <opencv2/opencv.hpp>

int main() {
  cv::Mat img, img_rgb;

  img = cv::imread("sample.jpg");
  // error handling
  if(img.data == NULL) {
    std::cerr << "Error: not found such file." << std::endl;
    exit(1);
  }
  // convert BGR to RGB
  cv::cvtColor(img, img_rgb, cv::COLOR_BGR2RGB);

  // print pixel data
  std::cout << img_rgb << std::endl;
}

cv::imread()で読み込んだ画素データはBGRの順番になっています.そこでcv::cvtColor()でBGRをRGBに並び替えてます.そのままでも良い方はcv::cvtColor()は不要です.

コンパイル

上記コード用のMakefileです.

Makefile
# Makefile

FILE = hoge.cpp
HDIR = -I /usr/include/opencv4
OPT  = -lopencv_core -lopencv_imgproc -lopencv_imgcodecs

a.out: $(FILE)
    $(CXX) -Wall $(FILE) $(HDIR) $(OPT)

ソースファイル名がsample.cppなら,上記3行目をFILE = sample.cppと書き換えるか,実行時にmake FILE=sample.cppとしてください.

これで実行ファイルが作成されると思います.
もしコードにそのほかのopenCVの関数を使った場合は,適宜オプションを追加してください.

これでコンパイル時に悩まされないと思います.
pkg-configを使うとMakefileを使わずにできますが,個人的にMakefileが好きという事もありMakefileで記述しました.

おまけ

連番になっている画像の画素データをファイルに書き出したかったので,そのコードも載せておきます.
ファイル名をsample_0.jpg,...,sample_(n).jpgの連番形式,画像サイズを28x28とします.

get_rgb.cpp
#include <iostream>
#include <fstream>    // for ofstream
#include <opencv2/opencv.hpp>

#define PIXEL 28   // image size
#define CHNEL 3    // number of channel [RGB = 3]

int main() {
  cv::Mat img, img_rgb;
  std::ofstream ofs("pixel_data.txt");
  int idx = 0;    // for file index

  while((img = cv::imread("sample_"+std::to_string(idx)+".jpg", 1)).data) {
    // convert BGR to RGB
    cv::cvtColor(img, img_rgb, cv::COLOR_BGR2RGB);

    // output pixel data to file
    for(int i = 0; i < CHNEL; i++) {
      for(int m = 0; m < PIXEL; m++) {
        for(int n = 0; n < PIXEL; n++) {
          ofs << static_cast<int>(img_rgb.at<cv::Vec3b>(cv::Point(n, m))[i]);
          if(n != PIXEL-1) ofs << " ";
        }
        ofs << "\n";
      }
    }
    idx++;
  }
  std::cout << "outputting pixel data to file completed." << std::endl;
}

簡単に説明します.
出力形式は空白区切り,データの並びは各ファイルごとにRGBの順に出力されます.
実際に画素データを取得,出力してるのは,21行目の

ofs << static_cast<int>(img_rgb.at<cv::Vec3b>(cv::Point(n, m))[i]);

です.
Matクラスのat関数を用いて,Channel[i]の(n, m)番値の画素データを取得,intにキャスとした値をファイルに出力,という事をしています.
cv::Point(n, m)が番地を指定しているのですが,(m, n)にするとMatクラスで取得した行列の転置行列になってしまうので,(n, m)にしています.

もし簡単なファイル出力方法などあれば,教えていただけると幸いです.

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?