6
3

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 5 years have passed since last update.

【Ruby】マンデルブロ集合をNArrayで描出してみた

Last updated at Posted at 2019-05-21

小ネタですよ。

mandel.png

旧NArrayの公式ページにサンプルがあるので、Numo::NArrayで書き直してみました。ほとんどそのままです。
https://masa16.github.io/narray/demo/mandel.en.html
Rubyだし実行に時間がかかるんじゃないの? いいえ、NArrayを使っているので計算時間は一瞬です。
(むしろ画像のサイズが大きくなるとgdkpixbufで画像化するのがもたつくかも)

gem install numo-narray
gem install gtk3
require 'numo/narray'
require 'gdk_pixbuf2'
include Numo

def mandel(w, h, w2, h2, zoom)

  z = (SComplex.new(1, w).seq / w - w2) * zoom +
      (SComplex.new(h, 1).seq / h - h2) * zoom * Complex(0, 1)

  c = z.dup
  a = UInt8.zeros(w, h)
  idx = Int32.new(w, h).seq

  (1..100).each do |i|
    z = z**2 + c
    idx_t = (z.abs > 2).where
    idx_f = (z.abs <= 2).where
    a[idx[idx_t]] = i
    break if idx_f.empty?

    idx = idx[idx_f]
    z = z[idx_f]
    c = c[idx_f]
  end
  a
end

data = mandel(600, 600, 0.8, 0.5, 2)

# Grayscale to RGB
data2 = UInt8.zeros(600, 600, 3)
data2[true, true, 1] = (SFloat.cast(data) / 100 * 255)

pixbuf = GdkPixbuf::Pixbuf.new(data: data2.to_string, width: 600, height: 600)

pixbuf.save('mandel.png')

mandel.png

冒頭の画像のようにカラフルにしたい? カラフルにしたいときはこんな感じです。

# frozen_string_literal: true

require 'numo/narray'
require 'gdk_pixbuf2'
include Numo

def mandel(w, h, w2, h2, zoom)
  z = (SComplex.new(1, w).seq / w - w2) * zoom +
      (SComplex.new(h, 1).seq / h - h2) * zoom * Complex(0, 1)

  c = z.dup
  a = UInt8.zeros(w, h)
  idx = Int32.new(w, h).seq

  (1..100).each do |i|
    z = z**2 + c
    idx_t = (z.abs > 2).where
    idx_f = (z.abs <= 2).where
    a[idx[idx_t]] = i
    break if idx_f.empty?

    idx = idx[idx_f]
    z = z[idx_f]
    c = c[idx_f]
  end
  a
end

# Cumoの実行速度対策
def uInt8_dstack(ar)
  x = UInt8.zeros(*ar[0].shape, 3)
  x[true, true, 0] = ar[0]
  x[true, true, 1] = ar[1]
  x[true, true, 2] = ar[2]
  x
end

# HSV を RGB に変換
def hsv2rgb(h)
  i = UInt8.cast(h * 6)
  f = (h * 6.0) - i
  p = UInt8.zeros *h.shape
  v = UInt8.new(*h.shape).fill 255
  q = (1.0 - f) * 256
  t = f * 256
  rgb = UInt8.zeros *h.shape, 3
  t = UInt8.cast(t)
  i = uInt8_dstack([i, i, i])
  rgb[i.eq 0] = uInt8_dstack([v, t, p])[i.eq 0]
  rgb[i.eq 1] = uInt8_dstack([q, v, p])[i.eq 1]
  rgb[i.eq 2] = uInt8_dstack([p, v, t])[i.eq 2]
  rgb[i.eq 3] = uInt8_dstack([p, q, v])[i.eq 3]
  rgb[i.eq 4] = uInt8_dstack([t, p, v])[i.eq 4]
  rgb[i.eq 5] = uInt8_dstack([v, p, q])[i.eq 5]
  rgb
end

data = mandel(600, 600, 0.8, 0.5, 2)

# Grayscale to RGB
data2 = hsv2rgb(SFloat.cast(data) / 100)

pixbuf = GdkPixbuf::Pixbuf.new(data: data2.to_string, width: 600, height: 600)

pixbuf.save('mandel.png')

あとは、(実際に試したわけではないですが)Cumoを導入することでGPUで動かすこともできますし、

GdkPixbufで画像データを扱っているので、Gtk3で簡単にデスクトップアプリ化することも可能ですね。

この記事は以上です。

関連資料

6
3
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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?