rubyで画像の色を変更してみた

# はじめに
今回は遊びで画像の色を変換させるプログラムを作成したので、
メモ程度に投稿します。
# 本題
### 前提
この記事のゴールとしては、
画像の色を反転させる、または一部色を指定して変更させることです。

1. Docker環境の準備
2. 色を反転
3. 色の変更

作成したファイルは以下になります
```
作成したファイル
-  Dockerfile 
-  docker-compose.yml
-  detail.rb
-  reverse.rb
-  color_change.rb
```

画像は以下の画像で試してみることとします。
（調べた限り著作権的にも問題なさそうなので？）
画像を実行ファイルと同様のディレクトリに配置した場合を仮定して、以下記述します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/5e48c7a7-22f4-3acb-7dff-0f5b8a88a9e8.png)

### 1. Docker環境の準備
まずはDocker環境の準備をしていきます。
gemは`gdk_pixbuf2`,`numo-narray`を使用しました。
(今回はお試しで遊ぶだけなので、Gemfileの作成/マウントはしていません)

`Dockerfile`
```Dockerfile
FROM ruby:latest

LABEL manintainer chawan.ignore

ENV TZ=Asia/Tokyo

RUN apt-get update && apt-get install -y \
	bash \
	vim

WORKDIR /app

RUN gem install gdk_pixbuf2
RUN gem install numo-narray
```

上記で作成したDockerfileでイメージをbuildし、それを元に以下のdocker-compose.ymlを使用します。


`docker-compose.yml`
```docker
version: '3'
services:
  ruby:
    container_name: "ruby-mkimage"
    image: ruby:latest
    volumes:
    - type: bind
      source: ../
      target: /app
    tty: true
    stdin_open: true
```

### 2. 色を反転
まず色の反転を行ってみます。
その前に、対象の画像がRGBか、RGBAかを判別するために、
以下のdetail.rbを実行します。

```ruby
require 'gdk_pixbuf2'

image  = GdkPixbuf::Pixbuf.new(file: "image.png")
width  = image.width
height = image.height
data   = image.pixels

puts width
puts height
puts data.length
```

出力結果としては以下が得られます。

```
root@259467731a59:/app# ruby detail.rb 
192
192
110592
```
このことから、
```
n = 110592/192*192
n = 3
```
なのでRGBとわかります。

nが4であればRGBAとなります。

上記が分かったところで、色の反転を行います。

色の反転をするには以下のファイルを使用します。

`reverse.rb`
```ruby
require 'numo/narray'
require 'gdk_pixbuf2'

# 画像の取得
image = GdkPixbuf::Pixbuf.new(file: "xxx.png")

# ピクセルデータを取得し、Numo::UInt8型の配列に変換
width  = image.width
height = image.height
data = Numo::UInt8.from_string(image.pixel_bytes.to_str)

# 配列データの形状を変更
data = data.reshape(height, width, 3)

# 色を反転させる（255から各色成分を引く）
data[true, true, 0..2] = 255 - data[true, true, 0..2]

# 変更したピクセルデータを元の画像に戻す
image_data = data.to_string

image2 = GdkPixbuf::Pixbuf.new(data: image_data, width: image.width, height: image.height, has_alpha: false)

image2.save("xxx.png")
```

こちらのファイルでは、それぞれのRGBから255を引くことによって色が反転する仕組みになっています。
こちらのファイルを実行してみます。

以下のように、白い部分と黒い部分を反転することができました。

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/3174aacf-6550-2bf3-e855-94acc9fffe85.png)

### 3. 色の変更　
次に反転だけではなく、色を変更してみたいと思います。
色を変更するために以下のcolor_change.rbを実行します。

今回使用している画像が背景がRGB(247,247,247)で恐竜自体がRGB(82,82,82)で
構成されているので指定する値をそちらで設定しています。

以下では背景を黄色、恐竜をオレンジ色に指定してみました。

`color_change.rb`
```ruby
require 'numo/narray'
require 'gdk_pixbuf2'

# 画像の取得
image = GdkPixbuf::Pixbuf.new(file: "ｘｘｘ.png")

# ピクセルデータを取得し、Numo::UInt8型の配列に変換
height = image.height
width  = image.width
data = Numo::UInt8.from_string(image.pixel_bytes.to_str)

# 配列データの形状を変更
data = data.reshape(height, width, 3)

# 色を変更する
height.times do |y|
  width.times do |x|
    if (data[y, x, 0] == 247) & (data[y, x, 1] == 247) & (data[y, x, 2] == 247) then
      data[y, x, 0] = 255
      data[y, x, 1] = 255
      data[y, x, 2] = 0
    elsif (data[y, x, 0] == 82) & (data[y, x, 1] == 82) & (data[y, x, 2] == 82) then
      data[y, x, 0] = 255
      data[y, x, 1] = 140
      data[y, x, 2] = 0
    end
  end
end

# 変更したピクセルデータを元の画像に戻す
image_data = data.to_string

image2 = GdkPixbuf::Pixbuf.new(data: image_data, width: image.width, height: image.height, has_alpha: false)

image2.save("xxxx_image.png")
```

実行すると以下のように色を変更することができました。
![xxxx_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/3ee52983-a471-fa7c-93a2-d14d60e6a571.png)


他にも設定する値を変更すると色々な色に変更できると思います。

![pink2_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/97a6ae66-555e-aca0-c9ff-b3df96ab5866.png)![green_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/62ad5019-a88d-d9b2-2729-6fb34197fdb7.png)![blue_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/6efbe44a-4ed1-1bbe-eba4-227c9333d7fc.png)
![gold_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295486/bf879364-8eb0-734c-50a0-49116b29930b.png)

# 最後に
遊びで作ってみたので、もろもろツッコミどころは多いですが、
暇つぶしにやってみたいと思った際に参考にして頂ければ幸いです。