Ruby Processing

Here is my blog in which I will describe my experiments with ruby-processing, find out more about ruby-processing at:- https://github.com/jashkenas/ruby-processing compatible with processing-2.2.1 and https://github.com/monkstone/cf3ruby for my version of the cfdg DSL (context-free-art)

Sunday, 22 February 2015

More video library stuff with JRubyArt

The latest JRubyArt has a configurable library loader here is it being used to load the processing-3.0 video library:-
The library can be in a local 'library', folder in the default "~/.jruby_art/libraries", or in "~/.jruby_art/libraries/config.yml" defined alternative folder.
require 'jruby_art'

# Test your Webcam with this sketch
class TestCapture < Processing::App
  load_library :video
  include_package 'processing.video'
  attr_reader :cam

  def setup
    size(960, 544)
    cameras = Capture.list
    fail 'There are no cameras available for capture.' if (cameras.length == 0)
    p 'Matching cameras available:'
    size_pattern = Regexp.new(format('%dx%d', width, height))
    select = cameras.grep size_pattern # filter available cameras
    select.uniq.map { |cam| p cam.strip }
    fail 'There are no matching cameras.' if (select.length == 0)
    start_capture(select[0])
  end

  def start_capture(cam_string)
    # The camera can be initialized directly using an
    # element from the array returned by list:
    @cam = Capture.new(self, cam_string)
    p format('Using camera %s', cam_string)
    cam.start
  end

  def draw
    return unless cam.available
    cam.read
    image(cam, 0, 0)
    # The following does the same, and is faster when just drawing the image
    # without any additional resizing, transformations, or tint.
    # set(0, 0, cam)
  end
end

TestCapture.new(title: 'Test Capture')

Thursday, 19 February 2015

ASCII Capture sketch with JRubyArt

To get this sketch to work I placed the processing library jars in an adjacent library folder, also needed font in adjacent data folder. See jruby_art on github. It occurs to me that a library naming convention and library_loader utility like ruby-processing would be nice to have, perhaps with default location '~/.jruby_art/libraries' with a local library alternative (WIP).
#
# ASCII Video
# by Ben Fry, translated to jruby_art by Martin Prout.
#
#
# Text chars have been used to represent images since the earliest computers.
# This sketch is a simple homage that re-interprets live video as ASCII text.
# See the key_pressed function for more options, like changing the font size.
#
require 'jruby_art'

Dir[File.join('library', '*.jar')].each do |jar|
  require_relative jar
end

class AsciiVideoCapture < Processing::App
  attr_reader :bright, :char, :cheat_screen, :font, :font_size, :letters, :video
  # All ASCII characters, sorted according to their visual density
  LETTER_STRING = %q{ .`-_':,;^=+/\"|)\\<>)iv%xclrs{*}I?!][1taeo7zjLunT#JCwfy325Fp6mqSghVd4EgXPGZbYkOA&8U$@KHDBWNMR0Q}
  LETTER_ORDER = LETTER_STRING.scan(/./)

  def setup
    size(640, 480)
    init_video
    @font_size = 1.5
    @font = load_font(data_path('UniversLTStd-Light-48.vlw'))
    # for the 256 levels of brightness, distribute the letters across
    # the an array of 256 elements to use for the lookup
    @letters = (0...256).map do |i|
      LETTER_ORDER[map1d(i, (0...256), (0...LETTER_ORDER.length))]
    end
    # current brightness for each point
    @bright = Array.new(video.width * video.height, 128)
  end

  def init_video
    # This the default video input, see the test_capture
    # example if it creates an error
    @video = Java::ProcessingVideo::Capture.new(self, 160, 120)
    # Start capturing the images from the camera
    video.start
    @cheat_screen = false
  end

  def capture_event(c)
    c.read
    background 0
  end

  def draw
    return unless (video.available == true)
    capture_event(video)
    push_matrix
    hgap = width / video.width
    vgap = height / video.height
    scale([hgap, vgap].max * font_size)
    text_font(font, font_size)
    index = 0
    video.load_pixels
    (0...video.height).each do
      # Move down for next line
      translate(0,  1.0 / font_size)
      push_matrix
      (0...video.width).each do
        pixel_color = video.pixels[index]
        # Faster method of calculating r, g, b than red(), green(), blue()
        r = pixel_color >> 16 & 0xff
        g = pixel_color >> 8 & 0xff
        b = pixel_color & 0xff
        # Another option would be to properly calculate brightness as luminance:
        # luminance = 0.3*red + 0.59*green + 0.11*blue
        # Or you could instead red + green + blue, and make the the values[] array
        # 256*3 elements long instead of just 256.
        pixel_bright = [r, g, b].max
        # The 0.1 value is used to damp the changes so that letters flicker less
        diff = pixel_bright - bright[index]
        bright[index] += diff * 0.1
        fill(pixel_color)
        text(letters[bright[index]], 0, 0)
        # Move to the next pixel
        index += 1
        # Move over for next character
        translate(1.0 / font_size, 0)
      end
      pop_matrix
    end
    pop_matrix
    # image(video, 0, height - video.height)
    # set() is faster than image() when drawing untransformed images
    set(0, height - video.height, video) if cheat_screen
  end

  MESSAGE = <<-EOS
  Controls are:
  g to save_frame, f & F to set font size
  c to toggle cheat screen display
  EOS

  #
  # Handle key presses:
  # 'c' toggles the cheat screen that shows the original image in the corner
  # 'g' grabs an image and saves the frame to a tiff image
  # 'f' and 'F' increase and decrease the font size
  #
  def key_pressed
    case key
    when 'g' then save_frame
    when 'c' then @cheat_screen = !cheat_screen
    when 'f' then @font_size *= 1.1
    when 'F' then @font_size *= 0.9
    else
      warn MESSAGE
    end
  end
end

AsciiVideoCapture.new(title: 'Video Capture Sketch')

Sunday, 8 February 2015

MDArray gem is available to JRubyArt (handy for image processing)

Sketch makes use of MDArray convenience index function. Requires to be run as "k9 run sobel.rb" to get image stuff to work, but interestingly mdarray gem also just loads...(cf ruby-processing)
require 'jruby_art'
require 'mdarray'

class Strobel < Processing::App
  attr_reader :img, :edge

  def setup
    size 300, 225
    @img = load_image('engine.png')
    @edge = create_image(300, 225, ALPHA)
    edge.load_pixels
    img.load_pixels
    generate(img)
  end

  def draw
    image edge, 0, 0
    filter(GRAY)
  end

  def generate(from_image)
    sbx = MDArray.int([3, 3], [-1, 0, 1, -2, 0, 2, -1, 0, 1])
    sby = MDArray.int([3, 3], [1, 2, 1, 0, 0, 0, -1, -2, -1])
    edg = MDArray.int([225, 300])  # this seems Irish, but is correct
    pxls = from_image.pixels
    (1...from_image.width - 2).each do |x|
      (1...from_image.height - 2).each do |y|
        pixel_x = (sbx[0, 0] * pxls[x - 1 + width * (y - 1)]) + (sbx[0, 1] * pxls[x + width * (y - 1)]) + (sbx[0, 2] * pxls[x + 1+ width * (y - 1)]) +
          (sbx[1, 0] * pxls[x - 1+ width * y])   + (sbx[1, 1] * pxls[x + width * y])   + (sbx[1, 2] * pxls[x + 1+ width * y]) +
          (sbx[2, 0] * pxls[x - 1+ width * y + 1]) + (sbx[2, 1] * pxls[x + width * y + 1]) + (sbx[2, 2] * pxls[x + 1 + width * (y + 1)])
        pixel_y = (sby[0, 0] * pxls[x - 1+ width * (y - 1)]) + (sby[0, 1] * pxls[x + width * (y - 1)]) + (sby[0, 2] * pxls[x + 1+ width * (y - 1)]) +
          (sby[1, 0] * pxls[x - 1+ width * y])   + (sby[1, 1] * pxls[x + width * y])   + (sby[1, 2] * pxls[x + 1+ width * y]) +
          (sby[2, 0] * pxls[x - 1+ width * (y + 1)]) + (sby[2, 1] * pxls[x + width * (y + 1)]) + (sby[2, 2] * pxls[x + 1+ width * (y + 1)])
        val = Math.hypot(pixel_x, pixel_y).ceil
        edg[y, x] = val
      end
    end
    edge.pixels = edg.to_a # load pixels from MDArray
  end

  def mouse_pressed
    save('engine_edge.png')
  end
end

Strobel.new(title: 'Sobel Edge Detect')
before
edge detected

Saturday, 31 January 2015

Installing netbeans ruby-plugin and jruby_art gem

Please note for installation of gems, and some other operations netbeans can be a bit slow:- Download and unzip the plugin yields ~/arch/build/updates/*.* note location, which you will need to navigate to when installing "downloaded" plugins (from netbeans menu). Select all the *.nbm modules and the jruby.jar. And install see below:-























Then install the downloaded gem as install local (local install required to load --pre gem) and you are good to go a real ide to develop jruby_art who needs a processing mode?


























See crude Templates here
To install templates navigate to .netbeans/config/Templates (create a Templates folder if it does not exist) create a sub folder 'Ruby' put the outer .nbattrs file here, create a folder jruby_art and place the other .nbattrs file there along with both ruby sketch files. Templates should now show up in a Ruby sub-folder.

Friday, 30 January 2015

JRubyArt vs ruby-processing

Here are some the key differences jruby_art is still in development and lacks watch and export features of ruby-processing, but it is also a much simpler implentation.

External Dependencies

  • ruby-processing requires an installed version of vanilla-processing
  • jruby_art includes processings core jars in gem

Runnable from netbeans

  • ruby-processing sketches would need a Rakefile or some other script to run 
  • jruby_art sketches mainly just run (except for bare-sketches), opens possibility of incredibly simple/minimal installation from netbeans (no need for MRI ruby or an installed jruby, might suit windows users)

Core processing libraries (sound, video etc)

  • ruby-processing has builtin support 
  • jruby_art now has built in support (but path to libraries is configurable), can also be modular via gem see pbox2d as exemplar

Contributed processing libraries

  • ruby-processing has builtin support for libraries installed by processing ide 
  • jruby_art does not assume that vanilla processing is installed. Wrapping libraries in separate gem would be ideal see pbox2d and toxicgem

Vec2D, Vec3D, Arcball and DEGLUT

  • ruby-processing requires load_library 
  • jruby_art automatically loaded into jruby runtime

Processing::Proxy module

  • in ruby-processing Proxy can be used to mimic processings inner classes, probably v. bad juju convenience isn't everything 
  • in jruby_art a different Proxy is used to access some processing methods eg "pre", "post", "draw" via reflection

Thursday, 29 January 2015

Netbeans, the perfect ide for jruby_art

The perfect ide for jruby_art is netbeans, because all sketches just run (since the netbeans ruby plugin is using a built in jruby-complete) with the jruby command see below (actually bare sketches need k9 command). It is probably easier at this point to download jruby_art-0.2.0.pre.gem and do a local install. Thus it is quite possible to develop jruby_art without a jruby/ruby install, just using the jruby provided by the jruby netbeans plugin (this might actually make sense on windows). However you won't get the examples so make sure you get them here.

Monday, 26 January 2015

Cranky keyboard (unless you are a northern European) sound library example

# This example shows how to make a simple sampler and sequencer with the Sound
# library. In this sketch 5 different short samples are loaded and played back
# at different pitches, in this when 5 different octaves. The sequencer
# triggers and event every 200-1000 mSecs randomly. Each time a sound is
# played a colored rect with a random color is displayed.
load_library :sound

include_package 'processing.sound'

# Define the number of samples
NUM_SOUNDS = 5
attr_reader :device, :file, :value

def setup
  size(640, 360)
  background(255)
  # Create a Sound renderer and an array of empty soundfiles
  @device = AudioDevice.new(self, 48_000, 32)
  @file = []
  @value = Array.new(3, 0)
  # Load 5 soundfiles from a folder in a for loop. By naming the files 1., 2.,
  # 3., n.aif it is easy to iterate through the folder and load all files in
  # one line of code.
  NUM_SOUNDS.times do |i|
    file << SoundFile.new(self, format('%d.aif', (i + 1)))
  end
end

def draw
  background(*value) # splat array values
end

def key_pressed
  defined = true
  case key
  when 'a'
    file[0].play(0.5, 1.0)
  when 's'
    file[1].play(0.5, 1.0)
  when 'd'
    file[2].play(0.5, 1.0)
  when 'f'
    file[3].play(0.5, 1.0)
  when 'g'
    file[4].play(0.5, 1.0)
  when 'h'
    file[0].play(1.0, 1.0)
  when 'j'
    file[1].play(1.0, 1.0)
  when 'k'
    file[2].play(1.0, 1.0)
  when 'l'
    file[3].play(1.0, 1.0)
  when 'ö'
    file[4].play(1.0, 1.0)
  when 'ä'
    file[0].play(2.0, 1.0)
  when 'q'
    file[1].play(2.0, 1.0)
  when 'w'
    file[2].play(2.0, 1.0)
  when 'e'
    file[3].play(2.0, 1.0)
  when 'r'
    file[4].play(2.0, 1.0)
  when 't'
    file[0].play(3.0, 1.0)
  when 'z'
    file[1].play(3.0, 1.0)
  when 'u'
    file[2].play(3.0, 1.0)
  when 'i'
    file[3].play(3.0, 1.0)
  when 'o'
    file[4].play(3.0, 1.0)
  when 'p'
    file[0].play(4.0, 1.0)
  when 'ü'
    file[1].play(4.0, 1.0)
  else
    defined = false # only set background color value, if key is defined
  end
  @value = [rand(0..255), rand(0..255), rand(0..255)] if defined
end

Followers

About Me

My Photo
I am currently the lead developer of ruby-processing.