はてなブックマークに追加

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
はてなブックマークに追加

メディアアート

メディアアートって一体、何なのだろう。
既存のアートとメディアアートの違いは?
遊園地にあるアトラクションとメディアアートの違いは?

メディアアートの本質はインタラクティブ性にあると思う。
ユーザが起こしたアクションに対して、リアクションが返ってくる。
この面白さこそ、これまでのアートに無かったものなのだろう。

しかし、現状ではメディアアートはアートと名乗るにはあまりに
貧弱というか、稚拙というか、おこがましいというか。
あれじゃ、遊園地のアトラクションと何ら変わらない。

結局のところ現状のメディアアートって、
技術力がないプログラマの逃げ道にしか見えないのですが?
とりあえず、アートって名乗っといたら、ちょっとは高尚じゃん。
てな感じ。今はまだそのレベル。
スポンサーサイト
はてなブックマークに追加

AppleTV

今回のカンファレンスで
AppleTVに関して、日本をまるっとルーしたジョブズ。

まぁ、分からなくもないけど。
日本のテレビ業界なんて、とっととあちら側に吸収されるべきなんですよ。
数年後にはテレビとネットの区別なんて無くなってるに決まってるし。
え?テレビって何?ネットで見れる動画と何が違うの?
これが、未来のビジョン。

無駄に抵抗せずに楽天に吸収されてたら、
また違ってたんやろけどなぁ。
はてなブックマークに追加

DCT変換と逆DCT変換

openCVを使ってDCT変換と逆DCT変換するサンプルソースです。 cvDCTを使用した場合、画像中心に高周波成分が表示され、周辺に向かうにつれて低周波成分になっていきます。 したがって、下図に示すフィルタはどちらも低周波成分を通し高周波成分をカットするローパスフィルタとして 機能します。左側のフィルタは理想的なLPF、右側のフィルタはガウシアンフィルタになります。

opencv3.jpg

下図に理想LPFとガウシアンフィルタを使用したそれぞれの場合の結果を示します。理想LPFを使用した場合 周波数ドメインの関数に不連続な部分ができてしまうため、変換後の画像にリンギングが生じています。 それに対してガウシアンフィルタを使用した場合には、フィルタ関数が連続関数で記述可能なため、リンギングは生じていません。(ガウシアンの係数によっては生じる場合もある)

opencv4.jpg
ピクセルにアクセスするためのマクロ定義はこちら。ピクセルアクセスのためのマクロ
int main(int argc, char ** argv)
{
	IplImage *invImage;
	CvMat *dct,*idct;
	
	IplImage *image = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	IplImage *mask = cvLoadImage("mask1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	invImage = cvCreateImage( cvGetSize(image), IPL_DEPTH_8U, 1);

	dct = cvCreateMat(image->height, image->width, CV_64FC1);
	idct = cvCreateMat(image->height, image->width, CV_64FC1);
	
	// DCT
	int x, y;
	for(y=0; yheight; y++){
		for(x=0; xwidth; x++){
			cvmSet(dct,
				   y,
				   x,
				   (double)(unsigned char)(image->imageData[image->widthStep
															* y + x]));
		}
	}
	
	cvDCT( dct, dct, CV_DXT_FORWARD);
	
	// マスク値をDCT結果に乗算
	for(int x = 0; x < dct->width; ++x){
		for(int y = 0; y < dct->height; ++y){
			double scale = PIXVAL(mask, x, y) / 255.0;
			double value = cvmGet(dct, y, x) * scale;
			cvmSet(dct, y, x, value);
		}
	}
	
	// 逆変換
	cvDCT( dct, idct, CV_DXT_INVERSE);
	for(y=0; yheight; y++){
		for(x=0; xwidth; x++){
			invImage->imageData[invImage->widthStep * y + x] = cvmGet(idct,y,x);
		}
	}

	cvWaitKey(0);
	return 0;
}
はてなブックマークに追加

高速ぼかしフィルタ

通常のぼかしフィルタは、フィルタをかける画像が大きくなればなるほど、またフィルタのオペレータが大きくなればなるほど 処理時間は指数関数的に増大してしまいます。特にゲームではリアルタイム性が求められるため、 高速なぼかしフィルタのアルゴリズムが必要となります。ここではopenCVを用いて高速ぼかしフィルタのアルゴリズムを説明します。

単純にぼかしフィルタを使用すると、下図のようにフィルタが1px右へ移動したときに赤色のゾーンを再計算する必要があります。 高速化するために、この部分の計算結果を保存しておき、次の計算の時に使用しようというのが基本的なアイデアです。

opencv1.jpg

まずは縦列の値C0, C1, C2を先に計算し、それをフィルタ移動先でも再利用します。縦列の値Ciは 各ピクセルの足し算p(i,j-1)+p(i,j)+p(i,j+1)で求めることが出来ます。 フィルタをかけた後の値Sは(C0+C1+C2)/9で求めることが出来ます。

opencv2.jpg

フィルタが移動後の値はS-C0+C3で求めることが出来ます。この方法で従来は9回必要だった計算が 6回で済むため、高速化が図れます。今回は3x3のフィルタを用いましたが、フィルタが大きくなればなるほど この効果は大きくなってきます。残念ながら、この高速化の手法はガウシアンフィルタなどには適応出来ません。 コード例では5x5のフィルタの例を示しています。

4536px x 3024pxの画像に対して通常のぼかしフィルタをかけた場合4.56秒でした。それに対して 高速ぼかしフィルタでは2.12秒と2倍以上の高速化が図れました。 (実行環境:MacBook, Intel Core2Duo 2GHz, 2Gbyte Memory. )

ピクセルにアクセスするためのマクロ定義はこちら。ピクセルアクセスのためのマクロ

CvScalar C0, C1, C2, C3, C4, S;

inline CvScalar apply5x5FastBlurFilterWithImage(IplImage *img, int x, int y)
{
	CvScalar color;
	
	S.val[0] -= C0.val[0];
	S.val[1] -= C0.val[1];
	S.val[2] -= C0.val[2];	
	
	C0 = C1;
	C1 = C2;
	C2 = C3;
	C3 = C4;
	
	C4.val[0] = PIXVALR(img, x+2, y-2) + PIXVALR(img, x+2, y-1) + PIXVALR(img, x+2, y) + PIXVALR(img, x+2, y+1) + PIXVALR(img, x+2, y+2);   	
	C4.val[1] = PIXVALG(img, x+2, y-2) + PIXVALG(img, x+2, y-1) + PIXVALG(img, x+2, y) + PIXVALG(img, x+2, y+1) + PIXVALG(img, x+2, y+2);  
	C4.val[2] = PIXVALB(img, x+2, y-2) + PIXVALB(img, x+2, y-1) + PIXVALB(img, x+2, y) + PIXVALB(img, x+2, y+1) + PIXVALB(img, x+2, y+2);  
	
	S.val[0] += C4.val[0];
	S.val[1] += C4.val[1];
	S.val[2] += C4.val[2];	
	
	color.val[0] = S.val[0] / 25;
	color.val[1] = S.val[1] / 25;
	color.val[2] = S.val[2] / 25;
	
	return color;
}

inline CvScalar blurFront5x5(IplImage *img, int x, int y)
{
	CvScalar color;
	
	C0.val[0] = PIXVALR(img, x-2, y-2) + PIXVALR(img, x-2, y-1) + PIXVALR(img, x-2, y) + PIXVALR(img, x-2, y+1) + PIXVALR(img, x-2, y+2);   
	C1.val[0] = PIXVALR(img, x-1, y-2) + PIXVALR(img, x-1, y-1) + PIXVALR(img, x-1, y) + PIXVALR(img, x-1, y+1) + PIXVALR(img, x-1, y+2);   
	C2.val[0] = PIXVALR(img, x  , y-2) + PIXVALR(img, x  , y-1) + PIXVALR(img, x  , y) + PIXVALR(img, x  , y+1) + PIXVALR(img, x  , y+2);   
	C3.val[0] = PIXVALR(img, x+1, y-2) + PIXVALR(img, x+1, y-1) + PIXVALR(img, x+1, y) + PIXVALR(img, x+1, y+1) + PIXVALR(img, x+1, y+2);   
	C4.val[0] = PIXVALR(img, x+2, y-2) + PIXVALR(img, x+2, y-1) + PIXVALR(img, x+2, y) + PIXVALR(img, x+2, y+1) + PIXVALR(img, x+2, y+2);   	
	
	C0.val[1] = PIXVALG(img, x-2, y-2) + PIXVALG(img, x-2, y-1) + PIXVALG(img, x-2, y) + PIXVALG(img, x-2, y+1) + PIXVALG(img, x-2, y+2);   
	C1.val[1] = PIXVALG(img, x-1, y-2) + PIXVALG(img, x-1, y-1) + PIXVALG(img, x-1, y) + PIXVALG(img, x-1, y+1) + PIXVALG(img, x-1, y+2);   
	C2.val[1] = PIXVALG(img, x  , y-2) + PIXVALG(img, x  , y-1) + PIXVALG(img, x  , y) + PIXVALG(img, x  , y+1) + PIXVALG(img, x  , y+2);   
	C3.val[1] = PIXVALG(img, x+1, y-2) + PIXVALG(img, x+1, y-1) + PIXVALG(img, x+1, y) + PIXVALG(img, x+1, y+1) + PIXVALG(img, x+1, y+2);   
	C4.val[1] = PIXVALG(img, x+2, y-2) + PIXVALG(img, x+2, y-1) + PIXVALG(img, x+2, y) + PIXVALG(img, x+2, y+1) + PIXVALG(img, x+2, y+2);  
	
	C0.val[2] = PIXVALB(img, x-2, y-2) + PIXVALB(img, x-2, y-1) + PIXVALB(img, x-2, y) + PIXVALB(img, x-2, y+1) + PIXVALB(img, x-2, y+2);   
	C1.val[2] = PIXVALB(img, x-1, y-2) + PIXVALB(img, x-1, y-1) + PIXVALB(img, x-1, y) + PIXVALB(img, x-1, y+1) + PIXVALB(img, x-1, y+2);   
	C2.val[2] = PIXVALB(img, x  , y-2) + PIXVALB(img, x  , y-1) + PIXVALB(img, x  , y) + PIXVALB(img, x  , y+1) + PIXVALB(img, x  , y+2);   
	C3.val[2] = PIXVALB(img, x+1, y-2) + PIXVALB(img, x+1, y-1) + PIXVALB(img, x+1, y) + PIXVALB(img, x+1, y+1) + PIXVALB(img, x+1, y+2);   
	C4.val[2] = PIXVALB(img, x+2, y-2) + PIXVALB(img, x+2, y-1) + PIXVALB(img, x+2, y) + PIXVALB(img, x+2, y+1) + PIXVALB(img, x+2, y+2);  
	
	S.val[0] = (C0.val[0]+C1.val[0]+C2.val[0]+C3.val[0]+C4.val[0]);
	S.val[1] = (C0.val[1]+C1.val[1]+C2.val[1]+C3.val[1]+C4.val[1]);
	S.val[2] = (C0.val[2]+C1.val[2]+C2.val[2]+C3.val[2]+C4.val[2]);
	return color;
}

int main(int argc, char** argv)
{
	CvScalar color;
    IplImage* tmp = cvLoadImage("test.jpg");	
	IplImage* result = cvCreateImage(cvGetSize(tmp), IPL_DEPTH_8U, 3);
	cvNamedWindow("w1",  CV_WINDOW_AUTOSIZE);	

	for(int y = 2; y < tmp->height-2; ++y){
		blurFront5x5(tmp, 2, y);
		for(int x = 2; x < tmp->width-2; ++x){
			color = apply5x5FastBlurFilterWithImage(tmp, x, y);
			PIXVALR(result, x, y) = color.val[0];
			PIXVALG(result, x, y) = color.val[1];
			PIXVALB(result, x, y) = color.val[2];			
		}
	}

    cvShowImage("w1", result);
	cvWaitKey(0);
    return 0;
}
はてなブックマークに追加

ピクセルアクセスのためのマクロ

ピクセルにアクセスする場合に便利なマクロ群。
グレースケール画像の場合にはPIXVAL(画像名, x座標, y座標)でアクセス出来る。また、カラー画像(RGB)の場合にはPIXVALR, PIXVALG, PIXVALBを使用することで、各色のピクセルにアクセスすることが出来る。
#define PIXVAL(iplimagep, x, y) (*(uchar *)((iplimagep)->imageData + (y) * (iplimagep)->widthStep + (x)))
#define PIXVALB(iplimagep, x, y) (*(uchar *)((iplimagep)->imageData + (y) * (iplimagep)->widthStep + (x)*3))
#define PIXVALG(iplimagep, x, y) (*(uchar *)((iplimagep)->imageData + (y) * (iplimagep)->widthStep + (x)*3+1))
#define PIXVALR(iplimagep, x, y) (*(uchar *)((iplimagep)->imageData + (y) * (iplimagep)->widthStep + (x)*3+2))
はてなブックマークに追加

セピア変換

cvsepia.jpg

openCVを使ってカラー画像をセピア色に変換するサンプルソースです。
変換アルゴリズムとても単純で、まず入力画像をグレースケールに変換したのち、
変換画像の赤成分をアップ、青成分をダウンするだけです。

得られる写真の色合いはグレースケールにした時の彩度と
色調補正するときの赤青の増減値でほぼ決まります。

ピクセルにアクセスするためのマクロ定義はこちら。ピクセルアクセスのためのマクロ


int main(int argc, char** argv)
{
IplImage *img = cvLoadImage("fw.jpg");
IplImage *gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);

const int darkness = 50;

// グレースケール化
cvCvtColor(img, gray, CV_BGR2GRAY);
for(int x = 0; x < gray->width; ++x){
for(int y = 0; y < gray->height; ++y){
int g = PIXVAL(gray, x, y) - darkness;
PIXVAL(gray, x, y) = (g > 0)?g:0;
}
}
cvCvtColor(gray, img, CV_GRAY2RGB);

// セピア色をつける
for(int x = 0; x < img->width; ++x){
for(int y = 0; y < img->height; ++y){
int r = PIXVALR(img, x, y)+30;
int b = PIXVALB(img, x, y)-30;
PIXVALR(img, x, y) = (r < 256)? r : 255;
PIXVALB(img, x, y) = (b > 0) ? b : 0;
}
}

// 表示
cvNamedWindow("window1", CV_WINDOW_AUTOSIZE);
cvShowImage("window1", img);

cvWaitKey(0);

cvReleaseImage(&img);
cvReleaseImage(&gray);
return 0;
}

はてなブックマークに追加

カメラビューの上にビューを配置する

ImagePickerControllerのもつcameraOverlayViewに表示したいビューを登録することで、カメラビューの上にオーバーレイ表示することが出来ます。IB側で設定したビューをviewDidLoadの中で指定すると、ビュー領域が確保されていないためエラーとなるので注意。 画像をオーバレイしたい場合は、cameraOverlayViewに直接UIImageViewを指定すればOKです

また、文字などをオーバレイしたい場合は、UIViewの上にUILabelを配置し、UIViewごとOverLayプロパティに 登録するのが簡単かとおもいます。下の例はカメラが起動されるタイミングでoverlayViewを設定しているプログラムです。

はてなブックマークに追加

UIScrollViewの使い方

UIScrollViewを使って選択した画像をピンチイン・ピンチアウトする方法。 まずはじめに画像の拡大率・縮小率の限界値を設定します。デフォルトの値がどちらも1.0なので そのままの状態では拡大することができません。scrollViewのデリゲートも適切に設定しておく必要があります。

[scrollView setMinimumZoomScale:1.0];
[scrollView setMaximumZoomScale:5.0];
scrollView.delegate = self; 	
次に、UIImageViewをaddSubviewでUIScrollViewに追加します。まずはじめにimageViewに画像を設定し、その サイズをScrollViewに設定します。その後にimageViewをScrollViewに追加することで画像を拡大・縮小することが出来るようになります。

imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
scrollView.contentSize = CGSizeMake(imageView.frame.size.width, imageView.frame.size.height);  
[scrollView addSubview:imageView];	
最後にデリゲートメソッドを設定します。必ず実装する必要があるメソッドがviewForZoomingInScrollView:です。 このメソッドでは画像を設定したimageViewを返さなければなりません。

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)_scrollView {
	return imageView;
}

その他のデリゲートとして設定しておくと便利なのが下記の3つのメソッドです。scrollViewDidEndDragging:willDecelerate: はドラッグが終了した時に呼ばれるメソッドです(あくまでもドラッグが終了した時点なので、その後画面が慣性で移動した分は 考慮されない・・)scrollViewDidEndDecelerating:は実際に画面が静止したときに呼ばれるメソッドです。最後の scrollViewDidEndZooming:withView:atScale:は画面のズームが終了したときに呼ばれるメソッドです。

- (void)scrollViewDidEndDragging:(UIScrollView *)_scrollView 
				  willDecelerate:(BOOL)decelerate
{
offset.x = _scrollView.contentOffset.x/screenScale;
offset.y = _scrollView.contentOffset.y/screenScale;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)_scrollView
{
offset.x = _scrollView.contentOffset.x/screenScale;
offset.y = _scrollView.contentOffset.y/screenScale;
}

- (void)scrollViewDidEndZooming:(UIScrollView *)_scrollView 
					   withView:(UIView *)view atScale:(float)scale {
[scrollView setZoomScale:scale+0.01 animated:NO];
[scrollView setZoomScale:scale animated:NO];
screenScale = scale;	
offset.x = _scrollView.contentOffset.x/screenScale;
offset.y = _scrollView.contentOffset.y/screenScale;
}
はてなブックマークに追加

iPhoneでopenGLの背景を透明にする

opengles1.jpg

ここではiPhoneでopenGLの背景を透明にする方法を説明します。 まずはじめに、openGLレイヤ(EAGLView)の下に、背景を表示するimageViewを配置します。 Interface-BuilderのライブラリからxibウインドウへimageViewをドラックし、それをwindowの直上に配置します。 この作業後の設定画面は以下のようになっています。背景画像は適宜設定して下さい。

opengles2.jpg

つぎに ES1Renderer.mの中のglClearColorを以下のように変更して下さい。
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
ここではOpenGLの画面クリア色を透明に設定します。つぎはGLレイヤの設定です。EAGLView.mの中のinitWithCoderメソッドの中に下の2行を記述して下さい。
self.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];		
eaglLayer.opaque = NO;		

これでopenGLの背景を透明化することが出来ました。実際に確認してみてください。

開発アプリ

iDOF 色影 ラテアート ぱすてる

プロフィール

Author:hokuson
京都在住。iPhoneアプリ「色影」や「iDOF」の開発者。アプリのレビューとかもしてみる。博士後期課程@R大学。ついに就職活動なるものをしなければいけないらしい。誰か雇ってください。笑。

カレンダー
09 | 2010/09 | 10
- - - 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 - -
カテゴリ
最新コメント
RSSリンクの表示
リンク
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。