洋食の日記

「だ・である」調ではなく「です・ます」調で書きはじめれば良かったなと後悔してる人のブログです

画像をNumo::NArrayで表現するRubyの画像処理ライブラリを作り始めた

はじめに

PythonではOpenCVとScikit-imageという画像処理ライブラリがある。これらライブラリでは、画像データをNumPyのndarrayで表す。

>>> from skimage import io
>>> img = io.imread('lena.png')
>>> type(img)
<class 'numpy.ndarray'>

同じような感じで、画像データをNumo::NArrayで扱うものが欲しくなったので作り始めた。名前は、Image ProcessingからとってMagroとした(Gem名を考えているときに、ふと「そういえば鮪ペイントって昔あったよな」と思い出したのもあって)。実はまだ、pngjpegを読み書きすることしかできないが...

magro | RubyGems.org | your community gem host

インストール

Magroでは、pngjpegの読み書きにlibpngとlibjpegを使用するため、これらを先にインストールする。メジャーなライブラリなので、なにかしらパッケージがある(環境によってはすでにインストールされている場合もある)。

macOSであればbrewで:

$ brew install libpng libjpeg

Ubuntuなどlinux系であれば適当なパッケージマネージャで:

$ sudo apt-get install libpng-dev libjpeg-dev

Magroは、gemコマンドでインストールできる。

$ gem install magro

使い方

Magroでは、まだ、pngjpeg画像の読み書きしかできない。画像の形式はファイル名の拡張子で判定している。例えば、有名なRGBなPNG画像ファイルをグレイスケールにするならば、以下のようになる。

[1] pry(main)> require 'magro'
=> true
[2] pry(main)> img = Magro::IO.imread('lena.png')
=> Numo::UInt8#shape=[512,512,3]
[[[226, 137, 125],
  [226, 137, 125],
  [223, 137, 133],
...
[3] pry(main)> gray = img.median(axis: 2)
=> Numo::UInt8#shape=[512,512]
[[137, 137, 137, 136, 138, 129, 138, 134, 140, 136, 135, 134, 130, 139, ...],
 [137, 137, 137, 136, 138, 129, 138, 134, 140, 136, 135, 134, 130, 139, ...],
 [137, 137, 137, 136, 138, 129, 138, 134, 140, 136, 135, 134, 130, 139, ...],
...
[4] pry(main)> Magro::IO.imsave('lena_gray.png', gray)
=> true

画像データはNumo::UInt8で表現されるので、Red ChainerのConvolution Netsに投げるとか、Numo::DFloatなベクトルに変換してRumaleのRandom Forestに投げるとかできる。

おわりに

Rubyの画像処理ライブラリとしては、RMagickをはじめImageMagickをbindingしたものや、OpenCVをbindingしたものがある。OpenCVでは、画像をCvMatというOpenCVの行列型で表現する。行列の表現がNumo::NArrayでなくてもOKで、画像を行列で欲しい場合は、RubyであればOpenCVのbindingが良い(ただし対応しているOpenCVのバージョンは2系の様子)。

Magroは、PythonのScikit-Imageや、C言語のVLFeatあたりの雰囲気を目指して、あまり大きくならない程度に開発する予定。次は、画像にフィルタをかけるには、畳み込み演算が必要で、そのためのフーリエ変換をなにかしら組み込むとかかなぁ。

github.com