Title

アナログフィルムカメラ

今やiPhone+色々なカメラアプリで味のある写真が気軽にtwitterなどに投稿できる時代ですが、敢えて変な事をしてみる人がいるのも世の常。

という訳で、なんとなくフィルムで写真を撮影してみるってことをやってみる事にしました。
父が持っていたRollei35というカメラがあったのでそれで撮影してみました。

このカメラ、近年のデジタルカメラに比べると非常に面倒です。
まずフォーカスがマニュアルです。
それは当然なのですが、レンジファインダーでも一眼レフでもなく、人が距離を判断しないといけません。
被写体まで3メートルくらいかな? と目測した上で「3m」と書かれたところに目盛をあわせるというピント調整方式です。
でもそんなのよく分からないので被写体までの距離はレーザー距離計で測距しました。
無駄にセンチ単位で測れます。
いったい何やってんだろうって思いますが気にしないようにします。

こちらがモノクロネガフィルムで撮影したもの(をスキャンしたもの)です。

まぁ、とりあえず写ってはいるようです。

Rollei35は小さくて良い感じなのですが、レンズが暗く、何よりもピントが合ってるのかどうかよくわからないってことで、もう一台、どうせならって事で、機械式カメラ(シャッター時間などが機械式に制御される)を入手してみました。


Nikon F2というカメラです。
当時の高級機種ですが、ヒット作なので大量に市場に流通している(と思う)

このカメラ、一眼レフなのでフォーカスはバッチリ合います(たぶん)。
しかし、露出がやっぱりマニュアルです。
さらに露出計もありません。

「今日は晴れてるし、正午だし、こんなもんの明るさかな? じゃあ絞りとシャッターをこんなものにしよう。」
・・・ってやるわけですが、そんなの僕に判るわけありません。
しかも結果は現像してみるまでわからない。

こりゃなんとかせねばって事で登場するのがiPhoneですよ。
iPhoneのカメラの露出制御値から被写体の明るさを逆算して露出計の代わりにしてみました。
左は検証用の露出計です。最初からそれ使えというツッコミはなしで。

(このアプリはちゃんと完成させて公開予定!)

上記iPhoneアプリによる露出計算とリバーサルフィルムで撮影した結果がこちらです。


(スキャナが不調なため、フィルムをデジカメで撮影)

リバーサルフィルムはラチチュードが狭い(ダイナミックレンジが狭い)ため、露出がぴったり合っていないとイケナイと聞いているので、この結果はちゃんと露出が取れてると考えていいでしょう。いいですよね。

被写体をみつけたら、iPhoneのカメラを向け、露出を計算し、フィルムで撮影、現像を行い、出来上がったフィルムをデジタルカメラで撮影する・・・・。一体自分が何やってんのかよくわからなくなってきましたが、まぁ楽しいです。

新しい子育てアプリをリリースしました「添い寝アラーム」

前々からちょっと書いていましたが、新しいアプリをリリースしました。

そもそも、ComicGlassの開発するために子どもを寝かしつけてから時間を取っていたのですが、子どもと一緒に寝てしまうんですよね。

この「子どもと一緒に寝てしまう」問題は多くの親が「そうそう!」って頷く問題なわけですが、それをなんとかしようというアプリです。アプリ名は「添い寝アラーム」です。

スクリーンショットはこんな感じ。

添い寝アラームスクリーンショット1

まず、最初にやったのは「暗闇でも止められるアラーム」です。
普通のアラームアプリは画面を見て止めますよね?
あれだと、もしまだ子どもが寝ていなかったりするときに画面を点灯させなければならないのが困るのです。
そういうわけで、加速度センサを利用し、iPhoneを軽く叩くとアラームがスヌーズになるアラームアプリを作りました。

しかし、これでやってみるとアラーム時間を何分後くらいに設定すればいいのかが難しい。
絵本を読み聞かせている途中になってしまったり、まだ子どもが起きていてしゃべっている最中や、ゴロゴロ転がっている(子どもはよく動きます)途中にアラームがなってしまったりします。

そこでアラーム時間の自動設定方法の開発に取り組みました。
使えるのはマイクと加速度センサ。

連日データを収集し、毎秒どのくらいのデータを取得し、どのように信号処理したらいいのかを試験しました。
少しでも楽に使えたらいいなーと思いながら毎回すこしづづ改善をした結果、それなりに良い感じになってきたので、本格的にアプリにしてみました。
(最初に時点では完全自分用で公開するつもりはなかったのですが)

添い寝アラームスクリーンショット2

最終的に、iPhoneの接近センサー、バイブレーター、マイク、スピーカー、加速度センサ、と、かなり内蔵デバイスを多く使うアプリになりました。
技術的な話をすれば、普通じゃありえないような頻度でAudioSessionを切り替えていたりと色々勉強になりました。

簡単に書きますと、
まずAudioSessionを切り替え、マイク入力を有効にします。

        AudioSessionInitialize(NULL, NULL, NULL, NULL);
        UInt32 category = kAudioSessionCategory_PlayAndRecord;
        AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
                                sizeof(UInt32),
                                &category);
        AudioSessionSetActive(YES);

それで音声をモニタリング。

加速度センサは60Hzで取得して微分して使っています。

音声と加速度の認識処理の部分は説明できないので省きますが、完璧な検出はやはり無理なので、アラームタイミングを長くしたり短くしたりすることでだいたい目的の動作が得られるようになっています。

アラームタイミングになると、オーディオセッションをマナーモードでも音が出るようにPlaybackに切り替えてバイブレーターを鳴らします。
(録音モードのままだとスピーカーの音量が自動的に抑えられてしまうというのもあります)

もう一つ苦労したのが、スヌーズのやり方です。
iPhoneを軽く叩いた事を検出すればいいだけなので一見簡単そうなのですが、同時にバイブレーターが動作しているというのが問題でした。
iPhoneを置いている場所(の硬さ)によってバイブレーター→謎の伝達関数→加速度センサの値が全然違うんですよね。

そこで、最初の一定時間は「謎の伝達関数」を推定する処理を行い、その後軽く叩いた動作を検出するようにしています。
最初の着想は簡単だったのですが、調整がとにかく大変でした・・・。

子育て中で、「寝てしまう!」問題にお困りの方がいらっしゃいましたら是非お試しくださいませ。

↓こちら
添い寝アラーム - RR Soft

Retina用@2xがついた画像から半分の解像度の画像を自動生成

iOSでは通常の画像(image.png)と、解像度が倍のRetina用画像(image@2x.png)を両方用意しないといけませんが、すごく面倒です。

そこでimage@2x.pngを入れるとimage.pngを自動生成するアプリケーションを作ってみました。
奇数の大きさを持つファイルや@2xが名前についていないファイルは何もしません。
また、既にファイルが存在している場合は上書きします。

remove@2x

縮小は4画素を平均して1画素を作る方法で計算しています(画素平均法)。
輝度の端数は切り捨てです。
png画像のみ対応。需要があればjpegも対応しますが、ひとまずこれで。

ダウンロード

何かありましたらコメントかtwitter(@rhotta)までお願いします。


Xcode4.3にしたらFileMargeが見つからない

↓ココにあります。
/Applications/Xcode.app/Contents/Applications/FileMerge.app

XcodeのメニューのOpen Developer Toolからも起動可能。

MacOSでも@2xのついたファイルのscaleが2.0になってしまう件

MacOSX(Lion)上で、NSImage – initWithContentsOfFileで画像ファイルを読み込んだ時、ファイル名に@2xがついているとNSImage.sizeの大きさが半分になっていることがある怪現象に遭遇しました。
ルールはわかりませんが、@2xがついていても半分にならないときもあり、すごい謎。

iOSで使うUIImageならば、@2xが付いているとRetina用画像ということで解像度倍なのですが、MacOSにはRetinaという概念はないはずなので@2xというファイル名で何かが変わるのは変だと思うのですが・・・。

なお、下記のようなコードでCGImageからサイズを取得すると正しいサイズが取得できます。

+ (NSSize)getImageSize:(NSImage*)image{
    CGImageRef cgImage = [image CGImageForProposedRect:nil context:nil hints:nil];
    NSSize imageSize;
	imageSize.width = CGImageGetWidth(cgImage);
	imageSize.height = CGImageGetHeight(cgImage);
    return imageSize;
}

という事はつまり、UIImageで言うところのscaleが2.0になっている、という事なのでしょうが、NSImageにはscaleプロパティが無いのでわかりません。

噂のRetinaMacOSXへの布石なのか、ただのバグなのか、はたまた僕の理解不足なのかわかりませんが、とにかく謎です。
分かる方いらっしゃいましたら教えて下さい。

環境はMacOS SDK 10.7,MacOS Lionです。

いろいろな日付の計算(曜日・日付・日本の祝日)

カレンダーを作るにあたって必要な以下の点を考察してみます。
特に祝日の計算は日付クラスなんかを使っても出来ないことが多いので頑張りが必要です。
・日付→任意の曜日
・月が何日までか
・日本の祝日、国民の休日にあたるかどうか

まず任意の日付の曜日を得る方法。
これは簡単。有名なツェラーの公式を使います。

if (y*366+m*31+d < 1582*366+10*31+15) return -1;
return (y + y/4 - y/100 + y/400 + (13*m+8)/5 + d) % 7;

次に任意の月の最後の日(=日数)を計算する方法。
2月以外は固定なので、要するに閏年の計算になります。
閏年を4年に1度と勘違いしている場合がありますが、それだけだと誤差が蓄積するので以下のルールになっています。
1.西暦が4で割り切れる年
2.ただし、100で割り切れる場合は例外
3.ただし、400で割り切れる場合は2のルールは適用しない

int last;
switch(m){
	case 1:last = 31;break;
	case 2:
		//うるう年の算出
		if(y % 4 ==0){
			if(y % 100 == 0) {
				if(y % 400 == 0){
					last=29;
				}else{
					last=28;
				}
			}else{
				last=29;
			}
		}else{
			last=28;
		}
		break;
	case 3:last = 31;break;
	case 4:last = 30;break;
	case 5:last = 31;break;
	case 6:last = 30;break;
	case 7:last = 31;break;
	case 8:last = 31;break;
	case 9:last = 30;break;
	case 10:last = 31;break;
	case 11:last = 30;break;
	case 12:last = 31;break;
	default: return 0;
}
return last;

最後に祝日・休日の計算方法について
今後制定される祝日については予測のしようがないので仕方が無いとして、既に制定されている祝日について考えます。

日付が固定されている祝日は楽ですが、ハッピーマンデーや振り替え休日がありますので注意が必要です。
また2007年の法律改正により、振替休日のルールが若干複雑になっています。

また、春分・秋分の日については法令としては前年になるまで確定しませんが、天文学的な春分日・秋分日と違う日になることはまず無いと推測できるので、計算により導いてみます。

以下は春分と秋分日の近似計算です。西暦1851年~2150年の間で利用できます。

//春分(3月)
int GetVernalEquinoxDay()
{

	int y = m_Systime.wYear;
	int  d;
	if(y<1851) return -1;
	else if(y < 1900){
		d = (int)(19.8277 + 0.242194 * (double)(y-1980) - ((y-1983)/4));
	}else if(y < 1980){
		d = (int)(20.8357 + 0.242194 * (double)(y-1980) - ((y-1983)/4));
	}else if(y < 2100){
		d = (int)(20.8431 + 0.242194 * (double)(y-1980) - ((y-1980)/4));
	}else if(y < 2151){
		d = (int)(21.8510 + 0.242194 * (double)(y-1980) - ((y-1980)/4));
	}else return -1;
	return d;
}

//秋分(9月)
int GetAutumnalEquinoxDay()
{

	int y = m_Systime.wYear;
	int  d;
	if(y<1851) return -1;
	else if(y < 1900){
		d = (int)(22.2588 + 0.242194 * (double)(y-1980) - ((y-1983)/4));
	}else if(y < 1980){
		d = (int)(23.2588 + 0.242194 * (double)(y-1980) - ((y-1983)/4));
	}else if(y < 2100){
		d = (int)(23.2488 + 0.242194 * (double)(y-1980) - ((y-1980)/4));
	}else if(y < 2151){
		d = (int)(24.2488 + 0.242194 * (double)(y-1980) - ((y-1980)/4));
	}else return -1;
	return d;
}

最後に祝日です。 現在と2007年の改定前の祝日を拾うようにしてみました。 これに加えて、振替休日を考慮する必要があります。 2007より前は日曜日に重なった場合は月曜日を休日に、 2007年以降は「その日後においてその日に最も近い「国民の祝日」でない日」が休日です。


int c = (d-1) / 7 + 1;
if(m==9)
	autumnalEquinoxDay =GetAutumnalEquinoxDay();
if(m==3)
	vernalEquinoxDay = GetVernalEquinoxDay();
if(m==1 && d==1){
	return DAY_NEWYEARSDAY;
}else if((y >= 1949 && y < 2000) &&  m==1 && d==15){
	//1949-1999 1月、15日
	return DAY_SEIJINNOHI;
}else if((y >= 2000) &&  m==1 && w==1 && c == 2){
	//2000~、1月、月曜日、第2
	return DAY_SEIJINNOHI;
}else if(y>= 1967 && m==2 && d==11){
	//1967~、2月、11日
	return DAY_KENKOKUKINENBI;
}else if(y>= 1949 && y<1989 && m==4 && d==29){
	//1949~1988、4月、29日
	return DAY_TENNOUTANJOBI;
}else if(y>=1989 && m==4 && d==29){
	if(y>=2007) return DAY_SHOWANOHI;
	//1989~、4月、29日
	return DAY_MIDORINOHI;
}else if(y>=1949 && m==5 && d==3){
	//1949~、5月、3日
	return DAY_KENPOUKINENBI;
}else if(y>=1986 && m==5 && d==4){
	if(y>=2007) return DAY_MIDORINOHI;
	//1986~、5月、4日
	return DAY_KOKUMINNOKYUJITU5;
}else if(y>=1949 && m==5 && d==5){
	//1949~、5月、5日
	return DAY_KODOMONOHI;
}else if(y>=1996  && y<2003  && m==7 && d==20){
	//1949~2002、7月、20日
	return DAY_UMINOHI;
}else if(y>=2003 && m==7 && w==1 &&c==3){
	//2003~、7月、月曜、第3
	return DAY_UMINOHI;
}else if(y>=1966  && y<2003  && m==9 && d==15){
	//1966~2002、9月、15日
	return DAY_KEIROUNOHI;
}else if(y>=2003 && m==9 && w==1 &&c==3){
	//2003~、9月、月曜、第3
	return DAY_KEIROUNOHI;
}else if(y>=1966  && y<2003  && m==10 && d==10){
	//1966~2002、10月、10日
	return DAY_TAIKUNOHI;
}else if(y>=2003 && m==10 && w==1 &&c==2){
	//2003~、10月、月曜、第2
	return DAY_TAIKUNOHI;
}else if(y>=1948 && m==11 && d==3){
	//1948~、11月、3日
	return DAY_BUNKANOHI;
}else if(y>=1948 && m==11 && d==23){
	//1948~、11月、23日
	return DAY_KINROUKANSYANOHI;
}else if(y>=1989 && m==12 && d==23){
	//1989~、11月、23日
	return DAY_TENNOUTANJOBI2;
}else if(y>=2003 && m==9 && GetNumOfWeek(d-1)==3 && w-1 == 1
	&& (d+1)==m_AutumnalEquinoxDay){
	//2003~、9月、前日が第3月曜日、翌日が秋分の日
	return DAY_KOKUMINNOKYUJITU9;
}else if(m==3 && d==m_VernalEquinoxDay){
	//春分
	return DAY_SYUNBUNNOHI;
}else if(m==9 && d==autumnalEquinoxDay){
	//秋分
	return DAY_SYUUBUNNOHI;
}

ComicGlass 4.60Beta1

次バージョンでの対応予定

・表紙を手動生成したときにiPad Retina解像度にならない問題を修正
・ファイル一覧で「削除」ボタンを表示中、かってにボタンが非表示になってしまうことがある不具合を修正
・Webブラウザビューを若干変更(アップルの審査対策・・・Webブラウザ内蔵してフルアクセスができると+17にしないといけないため。通ったり突然通らなかったりでよくわからない)
・バックアップの復元中に落ちてしまうことがある問題を修正
 発生条件:バックアップするフィアルの総パス超が一定以下(9文字)以下だと発生

accelerometer:didAccelerate:がDeprecatedになっている

加速度センサを使うアプリを新たに作っています。
ふとドキュメントを見たら、accelerometer:didAccelerate:が、(Deprecated in iOS 5.0.)になっていました。

代替は手段はどうするんだろうって悩んだのでメモ。

    motionManager_ = [[CMMotionManager alloc] init];
    motionManager_.accelerometerUpdateInterval = 1.0/60.0;

    NSOperationQueue *currentQueue = [NSOperationQueue currentQueue];
    accelerationValueFirst_ = YES;

    [motionManager_ startAccelerometerUpdatesToQueue:currentQueue
            withHandler:^(CMAccelerometerData *accelerometerData, NSError *error)
    {
        CMAcceleration acceleration = accelerometerData.acceleration;

        UIAccelerationValue x = acceleration.x;
        UIAccelerationValue y = acceleration.y;
        UIAccelerationValue z = acceleration.z;
        //お好きな処理
	}

ブロックを使う方法が推奨されているようです。
・・・と思いきやbeginAnimations:context:はDeprecatedになっていませんね。

CMMotionManagerはiOS4.0から利用できるようです。

どこでもドア

夢の道具に文句つけても仕方ないのだけれど、「どこでもドアがあったらなぁ」と想像して楽しむときに、どうしても「こういう場合どうなるんだ?」と疑問になってしまう。

一番最初に気づく問題は「気圧差」。
ドアを開けた先の世界とは気圧差があり、ドアを開けた瞬間突風で吹き飛ばされるのでは? というもの。
ドアには見えないバリアみたいなのがあって、気圧差は保ったまま人間だけが通過できる、と解決案を示せないことはないが、それはそれで、あらゆる物理量の微分値が無限大になるような境界面が存在するのか、それとも緩やかに変化させる緩衝帯があるのか、いろいろと新たな疑問点がわいてくる。未来の科学でうまいこと調整しているのだろうか。

もう少し想像してみると、「位置エネルギー」が心配になってくる。
質量・エネルギー量保存の法則はおそらく宇宙の大原則で覆らない。
高い位置と低い位置をどこでもドアで繋いだら永久機関が出来てしまう。
この問題はエネルギーの増減をどこでもドア側で吸収するような仕組みがあると考えるのが妥当だろう。
どんなエネルギー源で動作しているのか不明だが、低い位置から高い位置にどこでもドアを通じて物質が移動したとき、どこでもドアは何かしらのエネルギー(電気とか)を多く消費する。
位置エネルギーが問題になるならば、重力や電界や磁界のエネルギー差も当然あるわけだが、これも同様にどこでもドアが調整する。

このような事からドアがエネルギーを消費することがわかる。
どこでもドアを通過している途中にエネルギー切れ(電池切れ)等が発生した場合、どのような安全対策が施されているのかについても興味が尽きない。

もう一つ心配なのが、地上で使う限り、どこでもドア自体が常に移動していることである。
相対性理論によると、絶対的静止系は存在しない。よってどこでもドアが移動しているかどうかは特に関係ないのだが、ドアを開けた先と現在地に相対速度差がある場合は話が別である。さらに、地上に置かれた物は、重力と遠心力、地表からの反力が釣り合った状態で円運動をしている。つねに複雑な相対速度差がどこでもドアのこちら側とあちら側には存在する。
相対速度差があるということは時間の流れに差があるということだ。
例えば、ドアのあちら側とこちら側で原子の振動数が見かけ上、変わる。
人間などが通過するとき、その体を構成する原子が、原子や分子としての構造を保ったままどうやって通過しているのか気になるところである。
ここもSF的発想が必要だ。例えば質量を無効にする装置が搭載されているとか、別次元の平面宇宙のようなものを通過するだとか。

いろいろ考えてみたが、おそらく他にもある。
どこでもドアを実現するには、工学的問題の前に机上で解決しなければならないパラドックスが多数存在する。

家庭内ネットワーク

引越ししました。

よって、LAN配線もまったく構成が変わったわけですが、今まで使えていた機器が不調に陥ったりしました。
どうも特定の機器との間で相性が悪い模様。

具体的には持っていた無線LANアクセスポイントと、GIGABYTEのM/Bに乗っている(例のカニのマークのついた)オンラインイーサポートを繋ぐとリンクアップはするものの、パケットロストが多発します。
pingは通ったり通らなかったり・・。
Windowsのファイル共有でファイルをコピーすると、小さいファイルならOK,大きなファイルだとエラー、のような困った状況。

そろそろ買い替え時かもしれません。
SSIDの_nomap付けなきゃ。

カレンダー

2012年5月
« 4月    
 123456
78910111213
14151617181920
21222324252627
28293031  

▲Pagetop