mieki256's diary



2017/04/08() [n年前の日記]

#1 [dxruby][ruby] Scale2x や Scale3x をRubyで書いてみたり

Ruby + DXRuby を使って、ドット絵専用の整数倍拡大アルゴリズム、Scale2x や Scale3x の処理を書いて試してみたり。

以下のページに書かれてる内容をそのままコピペ。

_Scale2x Algorithm

画像端の部分を読み取る際に、元画像をはみ出しながら読み取ろうとしてしまうので、ちょっと一手間入れる必要が。本来、画像端とソレ以外でループを分けて速度面の最適化をすべきだろうけど、動くかどうかをひとまず試したいだけなので遅くなるのは分かってるけど安易な書き方を。

ソースはこんな感じに。

_scalenx.rb
# pixel scalking , Scale2x, Scale3x

module ScaleNx

  # pixel scaling, Scale2x
  # @param src [Array<Array>] pixel data array
  # @return [Array<Array>] 2x pixel data array
  def scale2x(src)
    width, height = src[0].size, src.size
    nwidth, nheight = width * 2, height * 2
    dst = Array.new(nheight).map { Array.new(nwidth).map { Array.new(4, 0) } }

    height.times do |y|
      width.times do |x|
        e = src[y][x]
        d = (x - 1 >= 0)? src[y][x - 1] : e
        f = (x + 1 < width)? src[y][x + 1] : e

        if y - 1 >= 0
          b = src[y - 1][x]
          a = (x - 1 >= 0)? src[y - 1][x - 1] : b
          c = (x + 1 < width)? src[y - 1][x + 1] : b
        else
          a = d
          b = e
          c = f
        end

        if y + 1 < height
          h = src[y + 1][x]
          g = (x - 1 >= 0)? src[y + 1][x - 1] : h
          i = (x + 1 < width)? src[y + 1][x + 1] : h
        else
          g = d
          h = e
          i = f
        end

        if b != h && d != f
          e0 = (d == b)? d : e
          e1 = (b == f)? f : e
          e2 = (d == h)? d : e
          e3 = (h == f)? f : e
        else
          e0 = e
          e1 = e
          e2 = e
          e3 = e
        end

        dx = x * 2
        dy = y * 2
        dst[dy][dx] = e0
        dst[dy][dx + 1] = e1
        dst[dy + 1][dx] = e2
        dst[dy + 1][dx + 1] = e3
      end
    end
    return dst
  end

  # pixel scaling, Scale3x
  # @param src [Array<Array>] pixel data array
  # @return [Array<Array>] 3x pixel data array
  def scale3x(src)
    width, height = src[0].size, src.size
    nwidth, nheight = width * 3, height * 3
    dst = Array.new(nheight).map { Array.new(nwidth).map { Array.new(4, 0) } }

    height.times do |y|
      width.times do |x|
        e = src[y][x]
        d = (x - 1 >= 0)? src[y][x - 1] : e
        f = (x + 1 < width)? src[y][x + 1] : e

        if y - 1 >= 0
          b = src[y - 1][x]
          a = (x - 1 >= 0)? src[y - 1][x - 1] : b
          c = (x + 1 < width)? src[y - 1][x + 1] : b
        else
          a = d
          b = e
          c = f
        end

        if y + 1 < height
          h = src[y + 1][x]
          g = (x - 1 >= 0)? src[y + 1][x - 1] : h
          i = (x + 1 < width)? src[y + 1][x + 1] : h
        else
          g = d
          h = e
          i = f
        end

        if b != h and d != f
          e0 = (d == b)? d : e
          e1 = ((d == b and e != c) or (b == f and e != a))? b : e
          e2 = (b == f)? f : e
          e3 = ((d == b and e != g) or (d == h and e != a))? d : e
          e4 = e
          e5 = ((b == f and e != i) or (h == f and e != c))? f : e
          e6 = (d == h)? d : e
          e7 = ((d == h and e != i) or (h == f and e != g))? h : e
          e8 = (h == f)? f : e
        else
          e0 = e
          e1 = e
          e2 = e
          e3 = e
          e4 = e
          e5 = e
          e6 = e
          e7 = e
          e8 = e
        end

        dx = x * 3
        dy = y * 3
        dst[dy][dx] = e0
        dst[dy][dx + 1] = e1
        dst[dy][dx + 2] = e2
        dst[dy + 1][dx] = e3
        dst[dy + 1][dx + 1] = e4
        dst[dy + 1][dx + 2] = e5
        dst[dy + 2][dx] = e6
        dst[dy + 2][dx + 1] = e7
        dst[dy + 2][dx + 2] = e8
      end
    end
    return dst
  end
end

if $0 == __FILE__
  # ----------------------------------------
  require 'dxruby'
  include ScaleNx

  # convert DXRuby Image to array
  def conv_image2array(img)
    w, h = img.width, img.height
    data = []
    h.times do |y|
      dt = []
      w.times do |x|
        a, r, g, b = img[x, y]
        dt.push([r, g, b, a])
      end
      data.push(dt)
    end
    return data
  end

  # convert array to DXRuby Image
  def conv_array2image(src)
    w, h = src[0].size, src.size
    img = Image.new(w, h, [0, 0, 0, 0])
    h.times do |y|
      src[y].each_with_index do |v, x|
        r, g, b, a = v
        img[x, y] = [a, r, g, b]
      end
    end
    return img
  end

  srcimg = Image.load("hq3x_original.png")
  src = conv_image2array(srcimg)

  dst = scale2x(src)
  dstimg2x = conv_array2image(dst)

  dst = scale3x(src)
  dstimg3x = conv_array2image(dst)

  Window.resize(540, 360)
  Window.minFilter = TEXF_POINT
  Window.magFilter = TEXF_POINT
  Window.scale = 2

  Window.loop do
    break if Input.keyPush?(K_ESCAPE)
    x, y = 0, 0
    Window.draw(0, 0, srcimg)
    x += srcimg.width + 8
    Window.draw(x, y, dstimg2x)
    y += dstimg2x.height + 8
    Window.draw(x, y, dstimg3x)
  end
end

テスト用画像は、 _Hq3x - Oss4art で紹介されてる画像を使わせてもらったり。消えるとアレなので転載させてください…。

_hq3x_original.png

ruby scalenx.rb で実行すると、こんな結果に。

scalenx_ss.png

一応実装できた、ような気がする。

コレ、ライセンスはどうなるのかな…。 _scale2x-4.0.tar.gz をDLして中身を見てみたら、COPYING に GPL と書いてあったので、コレも GPL になるのだろうか。たぶん。自分が書いて公開・配布するアレコレは、できれば CC0 / Public Domain にしたいけど、コレを使ってしまうとソレができないなと…。これもいわゆるGPL汚染、だろうか…。

書いた後で気が付いたけど、 _Scale2x のページで、「Scale2x の結果と EPX の結果は全く同じになるんやで」と説明が。EPX を書いてみるべきだったか…。8点ではなくて4点を見るだけで済むみたいだし…。

hqxも試してみたいけど。 :

hq2x、hq3x、hq4x も試してみたいけど、ソースをググってみたらなかなか複雑な感じで…。

一応、関連ページをメモ。

_Pixel art scaling algorithms - Wikipedia
_hqx - Wikipedia
_hq2x - HiEnd3D (Internet Archive)
_hq3x - HiEnd3D (Internet Archive)
_hq4x - HiEnd3D (Internet Archive)
_Usage - Arcnor/hqx-java Wiki
_Arcnor/hqx-java

ちなみに、hqx も GPL らしい。

処理をまとめたツールがあるらしい。 :

_2dimagefilter - Google Code Archive
_2dimagefilter by Hawkynt
_2dimagefilter - ImageResizer.wiki - Google Code Archive

GUI もしくは CUI で各アルゴリズムを試せる模様。ImageResizer-r133.exe をDLして実行してみたけど、Scale3x や hq3x が動くことを確認できた。

以上です。

過去ログ表示

Prev - 2017/04 - Next
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project