だいぶ時間があきましたが、isightで画像をキャプチャーして
ウインドウに表示するサンプルコードできました。

画像サイズは320×240です。サイズを大きくしてもいいですが、
処理が遅くなるので今後の課題です。

おまけで画像を1)グレイスケールにする関数、
2)RGBのRとBを入れ替える関数も用意してみました。
画像処理する方の参考まで。
次回は顔検出あたりにトライでしょうか。


コード以下>>

package test;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.WritableRaster;

import quicktime.QTSession;
import quicktime.qd.PixMap;
import quicktime.qd.QDGraphics;
import quicktime.qd.QDRect;
import quicktime.std.StdQTConstants;
import quicktime.std.sg.SGVideoChannel;
import quicktime.std.sg.SequenceGrabber;
import quicktime.util.RawEncodedImage;
import viewer.ImageViewer;

public class VideoCapture {
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int TIME_PER_FRAME = 67;
private SequenceGrabber grabber;
private SGVideoChannel channel;
private RawEncodedImage rowEncodedImage;
private int width;
private int height;
private int videoWidth;
private int[] pixels;
private BufferedImage image;
private WritableRaster raster;

public void proccess() {
try {
ImageViewer viewer = new ImageViewer(WIDTH, HEIGHT);
while (true) {
long start = System.currentTimeMillis();
// イメージをビュアーにセット
image = (BufferedImage) getNextImage();
// 画像処理
// inverseColor();
// grayScale();
viewer.setImage(image);
long time = System.currentTimeMillis() - start;
// キャプチャー、プレビューを時間TIME_PER_FRAMEで繰り返す
if (time < TIME_PER_FRAME) {
try {
Thread.sleep(TIME_PER_FRAME - time);
} catch (Exception e) {
System.err.println(e);
}
}
System.out.println("Frame Time : "
+ (System.currentTimeMillis() - start));
}
} catch (Exception e) {
// TODO: handle exception
}
}

public static void main(String[] args) {
try {
new VideoCapture(WIDTH, HEIGHT);
} catch (Exception e) {
System.out.println(e);
}
}

/**
* 画像の座標x,y,のrgb値を配列で返します
*
* @param x
* @param y
* @return
*/
public int[] getRGB(int x, int y) {
int val = image.getRGB(x, y);
int r = val >> 16 & 0xff;
int g = val >> 8 & 0xff;
int b = val & 0xff;
int[] rgb = { r, g, b };
return rgb;
}

/**
* 各ピクセルのrとbを反転します
*/
public void inverseColor() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int[] rgb = getRGB(x, y);
int val = rgb[0] | rgb[1] << 8 | rgb[2] << 16;
image.setRGB(x, y, val);
}
}
}

/**
* 画像をグレースケールに変換します
*/
public void grayScale() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int[] rgb = getRGB(x, y);
int val = (int) (rgb[0] * 0.2989 + rgb[1] * 0.5866 + rgb[2] * 0.1144);
int gray = val | val << 8 | val << 16;
image.setRGB(x, y, gray);
}
}
}

public VideoCapture(int width, int height) throws Exception {
this.width = width;
this.height = height;
try {
QTSession.open();
QDRect bounds = new QDRect(width, height);
QDGraphics graphics = new QDGraphics(bounds);
grabber = new SequenceGrabber();
grabber.setGWorld(graphics, null);
channel = new SGVideoChannel(grabber);
channel.setBounds(bounds);
channel.setUsage(StdQTConstants.seqGrabPreview);
grabber.prepare(true, false);// プレビューON、録画OFF
grabber.startPreview();// プレビューをスタート

PixMap pixmap = graphics.getPixMap();
rowEncodedImage = pixmap.getPixelData();

videoWidth = width + (rowEncodedImage.getRowBytes() - width * 4)
/ 4;
pixels = new int[videoWidth * height];
image = new BufferedImage(videoWidth, height,
BufferedImage.TYPE_INT_RGB);
raster = WritableRaster.createPackedRaster(DataBuffer.TYPE_INT,
videoWidth, height, new int[] { 0x00ff0000, 0x0000ff00,
0x000000ff }, null);
raster.setDataElements(0, 0, videoWidth, height, pixels);
image.setData(raster);

// 画像処理
proccess();
} catch (Exception e) {
QTSession.close();
throw e;
}
}

public void dispose() {
try {
grabber.stop();
grabber.release();
grabber.disposeChannel(channel);
image.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
QTSession.close();
}
}

public void getNextPixels(int[] pixels) throws Exception {
grabber.idle();
rowEncodedImage.copyToArray(0, pixels, 0, pixels.length);
}

public Image getNextImage() throws Exception {
grabber.idle();
rowEncodedImage.copyToArray(0, pixels, 0, pixels.length);
raster.setDataElements(0, 0, videoWidth, height, pixels);
image.setData(raster);
return image;
}
}

ども。初ブログですが、macの技術めもです。

タイトルの件、javaベースで画像処理でもしようかなと
思い立ったのが始まり。

で、自分はmacbook proだけど環境設定はすぐできそう
だし。。。って意外と大変。同じように困ってる人が
いそうだから情報共有できればと。
前置きが長くなりました。m(_ _ )m

さてまず、自分のデフォルトの環境をご説明。

1. OSー>
Mac OS X バージョン10.6.4。

2. Javaー>
Java環境はこのOSに入っているデフォルトはJava SE 6.0です。
こいつが64bit対応のせいでいろいろトラブル原因になるわけですが。

3. 動画用ライブラリー>
動画の読み込みはjava標準のライブラリにはないので
今回はQuickTime for Javaを使います。これはデフォルト
でライブラリに入っているので特にwebから落としてくる必要は
ありません。/System/Library/Java/Extensions/QTJava.zip
を確認してください。Java Media Frameworkというライブラリも
ありますが、はっきりいって不評なので今回はQTJを使用。


では、ここからが本題グー

1. JavaのバージョンをJ2SE5.0に落とします
macだとアプリケーション >ユーテリティ>Java Preferences
でGUIベースで切り替えられますが、なぜかJava SE 6.0の
32bitか64bitしか選べません。のでひと工夫必要なわけです。
手順はターミナルで以下↓

% cd /tmp/
% curl -o java.1.5.0-leopard.tar.gz http://www.cs.washington.edu/homes/isdal/snow_leopard_workaround/java.1.5.0-leopard.tar.gz
% tar -xvzf java.1.5.0-leopard.tar.gz
% sudo mv 1.5.0 /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0-leopard% cd /System/Library/Frameworks/JavaVM.framework/Versions/
% sudo rm 1.5.0
% sudo ln -s 1.5.0-leopard 1.5.0

これでJava PreferencesでJ2SE 5.0が選択できます。
ドラッグしてJ2SE 5.0の32bitを一番上にもってきて
Java SE 6.0のチェックを外しておきましょう。
参考:http://blog.cnu.jp/2009/10/15/snowleopard-java5/

2. 開発環境として便利なのでeclipseの準備します
注意としてeclipseの場合のjavaとは違う独自のコンパイラが
はしっていることです。なので最新のeclipseはheliosですが、
これだと後に述べるサンプルコードが実行できません。理由は
よくわかりませんが、環境設定で選択できるコンパイラ準拠レベル
を5.0に落としても6.0ベースでコンパイルしている模様(-。-;)
なのでGalileoあたりが無難だと思い、これを使用。コンパイラ準拠レベル
はもちろん5.0に落としておきます。これでokです。

3. サンプルコードを実行
サンプルコードはいくつか落ちています。
基本的には.movを再生するとか、isightから画像取得するなど
シンプルですが、テストプログラムとしては十分です。
eclipse上で実行してみてください。

参考:
http://en.wikipedia.org/wiki/QuickTime_for_Java
http://kjunichi.cocolog-nifty.com/misc/2008/02/macbook_airisig_29d4.html
http://gogo.tea-nifty.com/interpot/2004/06/isight__java_.html

ここまでできればAPI Referenceを参照しつつ、画像処理。
がんばるぞ!!グー