自己満足日記。
飽きっぽいので期待しないでください。
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
※プラグイン作成の解説記事ではないです。
独学でCとかC++とかやってみてたんだし
何かそれっぽいものを作ってみようということで、
Aviutlで拡大縮小をするプラグインを作ってみることにした。
用いるアルゴリズムは平均画素法(面積平均法・積分法とも)。
大まかな解説は以下のURLを参照の事。
まるも製作所 Diary 12月20日(水) 縮小アルゴリズム(3)- 平均画素法
陶見の窓 画像リサイズ「面積平均法」
開発に使うのはVisual C++ 2008 Express Edition。別に2010でも良い。
あとはAviutlのお部屋からAviUtl Plugin SDKを落とす。
ビルド時についてはまるも製作所 Diary 1月6日(木) VC.NET での拡張 AVI 出力ビルド方法を参照。
マニュアル代わりに永遠に工事中 AviUtlプラグインの作り方。
マイルール
○モチベーション維持のため他で見られない点をどこかに混ぜる
・間引きはしない:普通はほとんど差が出ないのでやります
○適当に間隔開けてから読んでも分かるようにする
・マジックナンバーは可能な限り避ける:あとから見ると何の数字だかワカラン
・とりあえず動くように書く:これ重要
・最適化(笑)は後回しにする:カッコつけちゃいけませんぜ
・変数名・関数名等は長くて良い:略しすぎると後で読んだときイミフ
○細かいところはコンパイラに投げる
・constは可能な限り使う:何かあるとコンパイラが教えてくれる
・変数は初期化する:うっかり未初期化のまま使うと嫌なので
・警告レベルは最大にする:コンパイラは友達だよ
・C++で書く:Better C 的な
どうしても処理が遅い時の解決法
・除算を避ける:クソ遅いと評判
・同じ計算を何度もしない:同じ出力なら定数を宣言しておきましょう
・分散処理する:OpenMPとかOpenCLとか使ってみたいじゃなーい
今回用いる平均画素法は10pxからの6pxにリサイズしたいのなら、一度3倍して最小公倍数である30pxに拡大し、その後5px毎に区切りそこの総和を3で割っていく感じです。
そして最初にまともに動いたのがこんな感じのもの。
当時のコードは残ってないので記憶で書いてますが無駄なところは再現出来てるかと。
独学でCとかC++とかやってみてたんだし
何かそれっぽいものを作ってみようということで、
Aviutlで拡大縮小をするプラグインを作ってみることにした。
用いるアルゴリズムは平均画素法(面積平均法・積分法とも)。
大まかな解説は以下のURLを参照の事。
まるも製作所 Diary 12月20日(水) 縮小アルゴリズム(3)- 平均画素法
陶見の窓 画像リサイズ「面積平均法」
開発に使うのはVisual C++ 2008 Express Edition。別に2010でも良い。
あとはAviutlのお部屋からAviUtl Plugin SDKを落とす。
ビルド時についてはまるも製作所 Diary 1月6日(木) VC.NET での拡張 AVI 出力ビルド方法を参照。
マニュアル代わりに永遠に工事中 AviUtlプラグインの作り方。
マイルール
○モチベーション維持のため他で見られない点をどこかに混ぜる
・間引きはしない:普通はほとんど差が出ないのでやります
○適当に間隔開けてから読んでも分かるようにする
・マジックナンバーは可能な限り避ける:あとから見ると何の数字だかワカラン
・とりあえず動くように書く:これ重要
・最適化(笑)は後回しにする:カッコつけちゃいけませんぜ
・変数名・関数名等は長くて良い:略しすぎると後で読んだときイミフ
○細かいところはコンパイラに投げる
・constは可能な限り使う:何かあるとコンパイラが教えてくれる
・変数は初期化する:うっかり未初期化のまま使うと嫌なので
・警告レベルは最大にする:コンパイラは友達だよ
・C++で書く:Better C 的な
どうしても処理が遅い時の解決法
・除算を避ける:クソ遅いと評判
・同じ計算を何度もしない:同じ出力なら定数を宣言しておきましょう
・分散処理する:OpenMPとかOpenCLとか使ってみたいじゃなーい
今回用いる平均画素法は10pxからの6pxにリサイズしたいのなら、一度3倍して最小公倍数である30pxに拡大し、その後5px毎に区切りそこの総和を3で割っていく感じです。
そして最初にまともに動いたのがこんな感じのもの。
当時のコードは残ってないので記憶で書いてますが無駄なところは再現出来てるかと。
BOOL func_proc( FILTER *fp,FILTER_PROC_INFO *fpip )
{
//
// fp->track[n] : トラックバーの数値
// fp->check[n] : チェックボックスの数値
// fpip->w : 実際の画像の横幅
// fpip->h : 実際の画像の縦幅
// fpip->max_w : 画像領域の横幅
// fpip->max_h : 画像領域の縦幅
// fpip->ycp_edit : 画像領域へのポインタ
// fpip->ycp_temp : テンポラリ領域へのポインタ
// fpip->ycp_edit[n].y : 画素(輝度 )データ ( 0 ~ 4096 )
// fpip->ycp_edit[n].cb : 画素(色差(青))データ ( -2048 ~ 2048 )
// fpip->ycp_edit[n].cr : 画素(色差(赤))データ ( -2048 ~ 2048 )
//
// 画素データは範囲外に出ていることがあります。
// また範囲内に収めなくてもかまいません。
//
// 画像サイズを変えたいときは fpip->w や fpip->h を変えます。
//
// テンポラリ領域に処理した画像を格納したいときは
// fpip->ycp_edit と fpip->ycp_temp を入れ替えます。
//
const int dst_w = fp->track[0];//目的とする任意の解像度(w:横方向、h:縦方向)
const int dst_h = fp->track[1];
const int max_w = fpip->max_w;
const int src_w = fpip->w;//元の解像度
const int src_h = fpip->h;
const int gcd_w = get_gcd(dst_w, src_w);//gcd:最大公約数、つまりdstとsrcの最大公約数
const int gcd_h = get_gcd(dst_h, src_h);//dst*src/gcd=最小公倍数(lcm)
const int lps_w = dst_w / gcd_w;//目的解像度*lps=lcm
const int lps_h = dst_h / gcd_h;
const int lpd_w = src_w / gcd_w;//元の解像度*lps=lcm
const int lpd_h = src_h / gcd_h;
for(int index_y = 0; index_y < dst_h; index_y++){
for(int index_x = 0; index_x < dst_w; index_x++){
int yc_y = 0, yc_cb = 0, yc_cr = 0;//テンポラリ
for(int offset_y = 0; offset_y < lpd_h; offset_y++){//ここが腐ってる
for(int offset_x = 0; offset_x < lpd_w; offset_x++){
//さぁここは何をやってるでしょうΛ||Λ
yc_y += fpip->ycp_edit[(index_x * lpd_w + offset_x) / lps_w + ((index_y * lpd_h + offset_y) / lps_h) * max_w].y;
yc_cb += fpip->ycp_edit[(index_x * lpd_w + offset_x) / lps_w + ((index_y * lpd_h + offset_y) / lps_h) * max_w].cb;
yc_cr += fpip->ycp_edit[(index_x * lpd_w + offset_x) / lps_w + ((index_y * lpd_h + offset_y) / lps_h) * max_w].cr;
}
}
//総和で割るとこ
fpip->ycp_temp[index_x + index_y * max_w].y = static_cast(yc_y / (lpd_w * lpd_h));
fpip->ycp_temp[index_x + index_y * max_w].cb = static_cast(yc_cb / (lpd_w * lpd_h));
fpip->ycp_temp[index_x + index_y * max_w].cr = static_cast(yc_cr / (lpd_w * lpd_h));
}
}
//swap
PIXEL_YC * const temp_ycp = fpip->ycp_edit;
fpip->ycp_edit = fpip->ycp_temp;
fpip->ycp_temp = temp_ycp;
//枠合わせ
fpip->w = dst_w;
fpip->h = dst_h;
return TRUE;
}
全部は書いてないし、やらないとは思いますが
間違ってもこのコードでビルドしようとしないでくださいね☆
要するに1からnまで足すのを地でやってるコードなので、
最小公倍数=元の解像度×目的解像度となる場合に計算量が爆発します。
具体的に言うと一コマ処理するのに10秒超えるのはザラ。下手すれば10分も超える。
そんでこれをかなり処理を縮めたわけだが長くなるのでまた次に。
{
//
// fp->track[n] : トラックバーの数値
// fp->check[n] : チェックボックスの数値
// fpip->w : 実際の画像の横幅
// fpip->h : 実際の画像の縦幅
// fpip->max_w : 画像領域の横幅
// fpip->max_h : 画像領域の縦幅
// fpip->ycp_edit : 画像領域へのポインタ
// fpip->ycp_temp : テンポラリ領域へのポインタ
// fpip->ycp_edit[n].y : 画素(輝度 )データ ( 0 ~ 4096 )
// fpip->ycp_edit[n].cb : 画素(色差(青))データ ( -2048 ~ 2048 )
// fpip->ycp_edit[n].cr : 画素(色差(赤))データ ( -2048 ~ 2048 )
//
// 画素データは範囲外に出ていることがあります。
// また範囲内に収めなくてもかまいません。
//
// 画像サイズを変えたいときは fpip->w や fpip->h を変えます。
//
// テンポラリ領域に処理した画像を格納したいときは
// fpip->ycp_edit と fpip->ycp_temp を入れ替えます。
//
const int dst_w = fp->track[0];//目的とする任意の解像度(w:横方向、h:縦方向)
const int dst_h = fp->track[1];
const int max_w = fpip->max_w;
const int src_w = fpip->w;//元の解像度
const int src_h = fpip->h;
const int gcd_w = get_gcd(dst_w, src_w);//gcd:最大公約数、つまりdstとsrcの最大公約数
const int gcd_h = get_gcd(dst_h, src_h);//dst*src/gcd=最小公倍数(lcm)
const int lps_w = dst_w / gcd_w;//目的解像度*lps=lcm
const int lps_h = dst_h / gcd_h;
const int lpd_w = src_w / gcd_w;//元の解像度*lps=lcm
const int lpd_h = src_h / gcd_h;
for(int index_y = 0; index_y < dst_h; index_y++){
for(int index_x = 0; index_x < dst_w; index_x++){
int yc_y = 0, yc_cb = 0, yc_cr = 0;//テンポラリ
for(int offset_y = 0; offset_y < lpd_h; offset_y++){//ここが腐ってる
for(int offset_x = 0; offset_x < lpd_w; offset_x++){
//さぁここは何をやってるでしょうΛ||Λ
yc_y += fpip->ycp_edit[(index_x * lpd_w + offset_x) / lps_w + ((index_y * lpd_h + offset_y) / lps_h) * max_w].y;
yc_cb += fpip->ycp_edit[(index_x * lpd_w + offset_x) / lps_w + ((index_y * lpd_h + offset_y) / lps_h) * max_w].cb;
yc_cr += fpip->ycp_edit[(index_x * lpd_w + offset_x) / lps_w + ((index_y * lpd_h + offset_y) / lps_h) * max_w].cr;
}
}
//総和で割るとこ
fpip->ycp_temp[index_x + index_y * max_w].y = static_cast
fpip->ycp_temp[index_x + index_y * max_w].cb = static_cast
fpip->ycp_temp[index_x + index_y * max_w].cr = static_cast
}
}
//swap
PIXEL_YC * const temp_ycp = fpip->ycp_edit;
fpip->ycp_edit = fpip->ycp_temp;
fpip->ycp_temp = temp_ycp;
//枠合わせ
fpip->w = dst_w;
fpip->h = dst_h;
return TRUE;
}
全部は書いてないし、やらないとは思いますが
間違ってもこのコードでビルドしようとしないでくださいね☆
要するに1からnまで足すのを地でやってるコードなので、
最小公倍数=元の解像度×目的解像度となる場合に計算量が爆発します。
具体的に言うと一コマ処理するのに10秒超えるのはザラ。下手すれば10分も超える。
そんでこれをかなり処理を縮めたわけだが長くなるのでまた次に。
PR
Comment Form