0

JRubyでglitch iconを作る

こういうのをtwitter iconにしたかった


Twitter のアイコンの目を光らせるライフハック – 地獄の猫日記を参考にアニメgifを作った。末尾も3C2Cにした。

でもちょうど今日からtwitterがGIFアニメアイコンのチェックを厳しくしたらしく、最初の1フレームだけの静止アイコンになってしまう。
既にアップされている他の人のアイコンを見ると、3C00002Cとかになってるのもあったけど色々ためしたけどやっぱりアップロードすると静止画像になる。


画像を生成するスクリプト
jrubyでjavax.imageioを使うと簡単。
最後のあたりのコメントアウトしているconvertかffmpegどちらでも、アニメーションgifを作れる。
glitchicon.rb

#!/usr/bin/env jruby
require 'java'
import 'java.lang.System'
import 'javax.imageio.ImageIO'
import 'java.awt.image.BufferedImage'

if ARGV.size < 2
  STDERR.puts 'require : input file and output dir'
  STDERR.puts 'jruby glitchicon.rb /path/to/img.jpg /path/to/out/'
  exit 1
end

img_in = ImageIO.read(java.io.File.new(ARGV.shift))
out_dir = ARGV.shift
out_dir += '/' unless out_dir =~ /\/$/

puts "#{img_in.width}x#{img_in.height}"

for i in 1..10
  img = BufferedImage.new(img_in.width, img_in.height, img_in.type);
  img.graphics.drawImage(img_in, 0, 0, nil)
  shifts = [0,0,0]
  for y in 0...img.height do
    if rand > 0.85
      shifts = shifts.map{|j|
        j = rand(255)-128
      }
    end
    for x in 0...img.width do
      pix = img.get_rgb(x, y)
      r = pix >> 16 & 0xFF
      g = pix >> 8 & 0xFF
      b = pix & 0xFF
      r += shifts[0]
      g += shifts[1]
      b += shifts[2]
      r = 255 if r > 255
      g = 255 if g > 255
      b = 255 if b > 255
      r = 0 if r < 0
      g = 0 if g < 0
      b = 0 if b < 0
      pix = ((r << 16)&0xFF0000 | (g << 8)&0xFF00 | b)
      "#{r},#{g},#{b}"
      img.set_rgb(x,y, pix)
    end
  end
  out_name = "#{out_dir}#{i}.bmp"
  ImageIO.write(img, 'bmp', java.io.File.new(out_name))
  puts out_name
end

puts `convert #{out_dir}*.bmp #{out_dir}out.gif`
#puts `ffmpeg -y -i #{out_dir}%d.bmp -s 100x100 -pix_fmt rgb24 -loop_output 0 -sameq #{out_dir}out.gif`

open("#{out_dir}out.gif"){|gif|
  bytes = gif.read.unpack('H*')
  bytes = [bytes.first.gsub!(/3b$/,'3c2c')]
  open("#{out_dir}glitchicon.gif",'w+'){|out|
    out.write(bytes.pack('H*'))
  }
}

0

gemだけで画像をリサイズできるImageResizeを作った

ImageResizeはImageMagickなどの外部プログラムに依存せずに、単体で画像をリサイズできる。ただしJavaの実行環境が必要。


SFCの「革新的ネットサービスの構築」という授業のTAをやっていて、昨日と今日niftyに行って開発合宿をしていた。
そこでいろいろあって、ImageMagickなしで画像のサムネイルを作る方法が無いのか模索していたら、ImageResizeというgemができた。

■インストール

gem install ImageResize


■使う
require 'rubygems'
require 'ImageResize'

# input, output, width, height
Image.resize('big.jpg', 'small.jpg', 40, 40)
これで40×40ピクセルに縮小される。
縦横のアスペクト比が1:1ではない画像の場合、アスペクト比を保ったまま長辺の方にあわせて縮小する。


■ソースコード
githubに置いた。
http://github.com/shokai/ImageResize-ruby


■実装
本体はJava。
標準実行環境にJPEGやGIFやBITMAPなど様々な画像フォーマットの読み書き機能を含んでいる環境というと、Javaと.NETとopenFrameworksしか思いつかなかった。
その中でいちばん色々なマシンにインストールされていそうで、配布が容易な物を選んだらJavaになった。


Javaでの画像の扱いは.NET並に簡単。java.awtとjavax.imageioの下に色々充実しているのでそれらを使えばいい。
ImageResize.java

import javax.imageio.*;
import java.io.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.regex.*;

class ImageResize{

    public ImageResize(){
    }

    public static void main(String args[]){
if(args.length < 4){
    System.out.println("ImageResize in.jpg out.jpg 320 320");
    System.exit(1);
}
ImageResize app = new ImageResize();
if(app.resize(args[0], args[1], Integer.parseInt(args[2]), Integer.parseInt(args[3]))){
    System.out.println(args[1]);
}
    }

    public boolean resize(String fname_in, String fname_out, int max_width, int max_height){
System.out.println(fname_in);
BufferedImage img = null;
try {
    img = ImageIO.read(new File(fname_in));
}
catch (Exception e) {
    e.printStackTrace();
    img = null;
}

int width, height;
if(img.getWidth() < img.getHeight()){
    height = max_height;
    width = img.getWidth() * max_height / img.getHeight();
}
else{
    width = max_width;
    height = img.getHeight() * max_width / img.getWidth();
}
System.out.println(img.getWidth() + "x" +img.getHeight() + " => " + width + "x" + height);

BufferedImage img_resized = new BufferedImage(width, height, img.getType());
AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance((double)width / img.getWidth(), 
       (double)height / img.getHeight()), 
      null);
ato.filter(img, img_resized);


String format = Pattern.compile("^.+\\.(.+)$").matcher(fname_out).replaceAll("$1");
boolean result = false;
try {
    result = ImageIO.write(img_resized, format, new File(fname_out));
}
catch (Exception e) {
    e.printStackTrace();
    result = false;
}
return result;
    }
    
}


■参考


今回は使わなかったが、Java Advanced Imaging (JAI) APIというのが標準実行環境には含まれていないけどSunが作っていて、かなり充実しているらしい。
Javaランタイムも速くなってきているらしいしScalaで画像処理とかしてみたい。

3

OpenCVをはじめた

openFrameworksをやっていて詰まったのでとりあえずOpenCVをやってみることにした。

openFrameworksはOpenCV・OpenGL・シリアルポート関連・音声関連のC++ライブラリをまとめたWin/Mac/Ubuntuで動作するクロスプラットフォームラッパーで、processingの影響を受けているらしいのだが、その中のOpenCVとOpenGL自体がまず巨大なライブラリなのでこいつらを扱う作法を知っていないとopenFrameworksが使いこなせない。


今回はOpenCVを単体で扱ってみてどんなもんか探ってみた。


■OpenCVのセットアップ、サンプル実行、コンパイル環境と対応カメラの確認

マシンに3つOSが入っているので実行環境も3つ揃えてみた。
MacとUbuntuはgccで、WinはVS2008でコンパイル。Ubuntuは色々ためしたけどiSightを認識しなかったが古い外付けUSBカメラを認識して使えた。
この内Macだけが駄目。描画が異常に重い。ググったらhighguiとCarbonの組み合わせが悪さしている?ような情報もあったがよくわからなかった。でもちゃんと動いていると報告してる人がたくさんいる。悔しい。

最近は全部パッケージ管理システムから入るんですね


本当はMacかUbuntuで動かしたかったけど、WindowsでVS2008でやる事にした。
俺が電車で移動中プログラムを書く事が多いので、Windowsからは内蔵i-Sightを使えて一番都合が良い。

cvWaitKey(msec)の待ち時間を短くしすぎなければ(30ぐらいなら大丈夫)どの環境でも動く事が確認できたので、後述するプログラムはどの環境でも動くと思う。少なくともWindowsとUbuntuでは動いている。



■画像処理の勉強

この本でやった。プログラムの途中重要な定数宣言部分が省略されまくったりしていて困ったけど、理論的な所は詳しく解説してくれているのでこの本と翻訳版ドキュメントサンプル集を見ればなんとかなった。


OpenCV プログラミングブック
奈良先端科学技術大学院大学 OpenCVプログラミングブック制作チーム
毎日コミュニケーションズ
売り上げランキング: 58513
おすすめ度の平均: 3.0
3 とっかかりとしてはよい本
4 OpenCVを日本語でまとまって解説した初めての本
2 肩すかし


OpenCVというとまっさきに「顔認識」を思い浮かべるけど、機械学習を用いた分類器については巻末のリファレンスに少し書かれている程度で、この本では基本的なOpenCVの組み込み関数を使った2値化やノイズ除去や表色系の変換、輪郭、エッジ抽出、テンプレートマッチング、物体追跡、背景差分法などが書かれている。書かれている内容はbuilt with processingディジタル画像処理の基礎と応用なんかに書かれている内容と被っている部分が多いけど、OpenCVの関数を使っているから滅茶苦茶処理が速い。やばい。もっと早くOpenCVに移れば良かった。


Read more

0

AS3 – あらためてラベリング処理

火曜に、imglのうっちーとあらためてラベリング処理ってどうやんのよという話をしていて、あらためてAS3で書き直した。

ただし、ラベルの衝突処理はまだやっていない。

ラベリング処理について→s.h.log: Proce55ing – 2値化画像を4近傍ラベリング処理してパーツ抜き出し

今まで、ラベルそのものを2次元のint配列で管理してたけど、今回はBitmapDataオブジェクトとして保存する様にしてみた。BitmapDataならx,y座標で要素にアクセスできるし、ピクセルはuint型なので都合がいい。

■できたもの

download => fla, as, swf (FlashDevelop3.0.0 Beta5 + FlashCS3)

年末年始作ったカメラから画像処理のサンプルを元に改造した。

webcamから撮影してBitmapDataにして、1ピクセルずつ走査して真っ白(0x00FFFFFF)のピクセルを検出。

さらにラベリング処理をして、「ピクセルのかたまり」毎に番号をつける。

(0x00FFFFFFは蛍光灯を撮影すると良いです)

labelinglabelinglabeling

今回はノイズを飛ばしたりしていないので、右の本棚の小さな白にも反応してしまって28個とか検出される

labeling

ラベルの衝突時の処理もしていないので、左上が空いた弧の様な形の時に割れてしまう

labeling

この辺はまたの機会に。

Read more

0

AS3 – BitmapMirror.asでYouTubeを鏡写しにする

右下の「Load」を押して再生。

Source Code (Flash CS3 / AS3)

土善開発合宿(ゆーすけべー日記: 奥出研’07秋合宿@土善旅館に部外者(OB)の開発合宿も兼ねて参入してきた)で作ってたBitmapMirror.asを公開しておきます。

宴会直前に到着したのであんまり時間がなかったけど、今回やったことは3つ

1.YouTubeのビデオ(flv)をGoogleVideo経由で取得して

2.AS3のBitmapDataとして扱って

3.鏡面反射させる

ビデオはこれを読み込んでいます。ひゃあ゛ああああうまい゛いいいいい

■1.YouTubeのビデオをGoogleVideo経由で取得する

数ヶ月前にGoogleに買収されて以来、

http://www.youtube.com/watch?v=YRY0M5cgDG8

のビデオは

http://cache.googlevideo.com/get_video?video_id=YRY0M5cgDG8

から取れる様になりました。

以前はWebService::YouTube使って

スクレイピングしなければならなかったけど、素直になった。

Read more