今日 昨日 | ||||||||
|
AA動画の作り方 元ネタ動画 youtube↓ http://jp.youtube.com/watch?v=77c1GR1itEM 前置き 皆様アクセスありがとうございます。 動画の方いかがだったでしょうか? え?すごいのはプログラムじゃなくてPCの性能だって? その通り PCのスペックは CPU: Core2Quad Q6700 メモリ: DDRII 8GB (XP時は4GB) HDD: 1TB VGA: GeForce8800GTX フフフ、素晴らしいスペックでしょう。 もちろん ((((うp主は貧乏ですorz 家のパソコンで実行できないので、 プログラムを書いては大学まで実行しに 通いました^^; はぁ、自分のPCもこれ位ハイスペックだったらな・・(ブツブツ ・・・と、くだらない話はさておき、 AA動画の作り方を紹介します。 アスキーアート動画の作り方 プログラム言語はC言語を使用しますが、 Cにあまり詳しくない人でもコンパイル環境さえあれば 簡単に出来るのでよければ作ってみてください。 ・C言語がコンパイル出来る環境がある ・DXライブラリをインストールしている という環境の元、下をお読みください。 まず、流れとして
という、4つの工程をふみます。 動画の中では、一旦AAデータファイルを生成していましたが、 bmpファイルから一度に表示できるように プログラムを変更したので工程が少なくなりました。 ただプログラムでやってる作業は動画で言ってる様に そこまでは単純じゃありませんが、 コードは完成してるのでコピペでOKです。 1 変換したい動画を用意する。 まず、変換したい動画がないと始まりません。 youtubeやニコニコ動画から持ってくるのでしたら
こちらのソフトを使用すると ダウンロードと同時にAVIに変換してくれます。 使い方の説明は全く要らないほど操作が簡単です。 見ればわかります。 2 動画をAVIに変換する。 既に持っているmpegであったり、mp4であったりする動画は superという動画変換ソフトで変換すると良いです。
かなりの形式に対応するので、何でも変換出来ます。 3 AVIを静止画bmpファイルに変換する。 AVI2JPGというソフトを使うと
いとも簡単に変換出来てしまいます。 この時、「変換前の動画の名前がbmpのファイル名になる」ことに 注意してください。 プログラム中でファイル名を指定する必要があるので、 ファイル名は注意してください。 プログラムコードのデフォルトでは「raki.avi」である事としています。 トンでもない量のファイルが出来るので、容量には気をつけて。 スペックの低いPCだと長い動画ならいつまでたっても終わらないかも・・。 プロジェクトがあるフォルダにimage0というフォルダをつくり、 そこに画像を入れてください。 4 bmpファイルをCで読み込んで表示する。 いよいよC言語を使った実装です。 こちらに私が使ったプログラムコードを提示しますので、 よければお使いください。 プログラムコードはこのページの一番下にあります。 画像再生と同時に流したい曲を「raki.ogg」で プロジェクトのあるフォルダに保存してください。 ファイル形式はwavかmp3かoggが使えます。 ファイル名を変えた時は、読み込み時のファイル文字列も 変更してください。 ここまできちんと準備できていれば、 下のコードをコピペしてコンパイル、実行すれば AAで動画が再生されます。 左がAAの画像。右が極端に拡大した画像です。 キーボードの十字キー「上キー」と「下キー」で 拡大縮小が出来るようになっています。 F12キーを押せばいつでも最初から見直すことが出来ます。 Escボタンで終了します。 |
連続したbmpを読み込み、適切な文字に置き換え、AAを生成し、連続で表示するプログラム #include "DxLib.h" #define MAX 1000 #define GAMEN_YOKO 1024 #define GAMEN_TATE 768 #define IMAGE1 #ifdef IMAGE0 #define BMP_YOKO 1024 #define BMP_TATE 576 #endif #ifdef IMAGE1 #define BMP_YOKO 512 #define BMP_TATE 384 #endif #ifdef IMAGE2 #define BMP_YOKO 400 #define BMP_TATE 300 #endif #ifdef IMAGE3 #define BMP_YOKO 320 #define BMP_TATE 240 #endif #define HEAD 54 #define TOTAL ((BMP_YOKO*BMP_TATE)*3+HEAD) unsigned char data[TOTAL]; typedef struct{ unsigned char col[3]; }img_t; #define TATEHI 3 #define YOKOHI 2 char img_AA[MAX][BMP_TATE/TATEHI+1][BMP_YOKO/YOKOHI+1]; int img_AAcol[MAX][BMP_TATE/TATEHI+1][BMP_YOKO/YOKOHI+1]; img_t img[MAX][BMP_TATE][BMP_YOKO]; int sound; #define BARANCE 6 #define CONTRAST 1.3 //画像のコントラストを調整する。確定した15階調の幅を広げたり、 //白方向、黒方向にずらしたり出来ます。 //コントラストはCONTRAST //輝度はBARANCE変数を変更して下さい。 void change_contrast(double *col){ *col-=BARANCE; *col*=CONTRAST; if(*col<-7)*col=-7; if(*col>7)*col=7; *col+=BARANCE; *col-=2; } //読み取った色情報からAAになる文字に変換する関数です。 //input配列にいれてある文字は左に行くほど濃く、右に行くほど薄い文字です。 //色はTATEHI、YOKOHIの範囲の色を全て足して、平均をとって決定します。 //1ピクセルが1文字に対応するわけではないので、お間違いなく。 void convert_AA(int cnt){ double sum; int i,j,x,y; int AAcolor[3]; double col; char input[15]={'H','D','E','J','L','I','c','(','ワ','*','+',':','-','.',' '}; for(y=0;y<BMP_TATE-TATEHI;y+=TATEHI){ for(x=0;x<BMP_YOKO-YOKOHI;x+=YOKOHI){ sum=0; AAcolor[0]=AAcolor[1]=AAcolor[2]=0; for(i=0;i<TATEHI;i++){ for(j=0;j<YOKOHI;j++){ sum+= img[cnt][y+i][x+j].col[0] +img[cnt][y+i][x+j].col[1]+img[cnt][y+i][x+j].col[2]; AAcolor[0]+=img[cnt][y+i][x+j].col[0]; AAcolor[1]+=img[cnt][y+i][x+j].col[1]; AAcolor[2]+=img[cnt][y+i][x+j].col[2]; } } sum/=TATEHI*YOKOHI; sum/=3.0; col=sum/17.0; for(i=0;i<3;i++) AAcolor[i]/=TATEHI*YOKOHI; img_AAcol[cnt][y/TATEHI][x/YOKOHI]=GetColor(AAcolor[2],AAcolor[1],AAcolor[0]); change_contrast(&col); if(col<0)col=0; if(col>14)col=14; img_AA[cnt][y/TATEHI][x/YOKOHI]=input[(int)col]; } } } //bmpファイルを読む関数です。 //ファイル名が違う場合はダブルコーテーション内をいじってください //配列に0を埋めている作業は、ファイル名が00000001になるようにするためです。 void bmp_read(int cnt){ int i; char name[64]; FILE *fp; sprintf(name,"image0/raki %7d.bmp",cnt+1); for(i=12;name[i]!='\0';i++){ if(name[i]==' ') name[i]='0'; } fp = fopen( name , "rb" ); if( fp == NULL ){ printfDx( "%sが見つかりません。",name); return; } fread( data, 1, TOTAL, fp ); fclose(fp); } //ロード中の画面を表示します。 void load(){ int x,y,c,t=0; static int cnt=1; for(cnt=0;cnt<MAX;cnt++){ DrawBox(0,0,GAMEN_YOKO*cnt/MAX,50,GetColor(255,255,255),TRUE); bmp_read(cnt); t=HEAD; for(y=BMP_TATE-1;y>=0;y--){ for(x=0;x<BMP_YOKO;x++){ for(c=0;c<3;c++){ img[cnt][y][x].col[c]=data[t]; t++; } } } convert_AA(cnt); } } char Key[256],oldKey[256]; //今押したかどうかを判定する関数です。 void check_key(){ int i; for(i=0;i<256;i++){ if(oldKey[i]==0 && Key[i]==1) Key[i]=2; oldKey[i]=Key[i]; } } //表示文字列サイズを変更する関数です。 void change_size(int *size){ if(Key[KEY_INPUT_UP]==2){ *size+=5; SetFontSize(*size); } if(Key[KEY_INPUT_DOWN]==2){ *size-=5; SetFontSize(*size); } } void play_music(){ PlaySoundMem(sound,DX_PLAYTYPE_BACK); } //AAを描画します。 //グラボによって、GOSAを0にした方がきれいになる場合と1の方がキレイな場合があるので //1でキレイに見えなかったら0にしてください。 #define GOSA 1 void draw_AA(int size, int cnt){ int x,y; DrawBox(0,0,GAMEN_YOKO,GAMEN_TATE,GetColor(255,255,255),TRUE); for(y=0;y<BMP_TATE/TATEHI;y++){ for(x=0;x<BMP_YOKO/YOKOHI;x++){ DrawFormatString(x*(size*3/5-GOSA)-(BMP_YOKO/YOKOHI)/2*(size-5)/2, y*(size-GOSA)-(BMP_TATE/TATEHI)/2*(size-5)/2, img_AAcol[cnt][y][x],"%c",img_AA[cnt][y][x]); } } } void stop_music(){ StopSoundMem(sound); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){ int cnt=0,size=5; SetGraphMode( GAMEN_YOKO , GAMEN_TATE , 16 ) ; //上のイフ文のコメントアウトを解除し、下をコメントアウトすると全画面になります。 // if(DxLib_Init() == -1 ) return -1; if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; load(); sound=LoadSoundMem("raki.ogg"); SetDrawScreen( DX_SCREEN_BACK ); SetFontSize(size); while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key )){ check_key(); change_size(&size); if(cnt==0) play_music(); draw_AA(size,cnt); cnt++; if(Key[KEY_INPUT_F12]==1 || cnt>=MAX){ cnt=0; stop_music(); } //WaitTimer(???); //<-時間がずれる場合はここで時間調整してください。 if(Key[KEY_INPUT_ESCAPE]==1)break; ScreenFlip(); } DxLib_End(); return 0; } #define MAX 1000 の値は、静止画のある枚数です。 #define GAMEN_YOKO 1024 #define GAMEN_TATE 768 は生成したい、画面サイズです。 #define IMAGE1 は読み込むbmpファイルのサイズです。 デフォルトでは512になっています。 #define TATEHI 3 #define YOKOHI 2 はたてと横の比率です。 raki.oggは再生する任意のファイルに変更してください。 |