![見出し画像](https://assets.st-note.com/production/uploads/images/158284920/rectangle_large_type_2_4407827aec84dafc8401b56ce19806b8.jpeg?width=1200)
画像フィルターの概念説明用画像処理ライブラリ仕様ソースコード
画像フィルターの概念説明用画像処理ライブラリ仕様ソースコード
2024年10月18初稿
エッセイ『画像フィルターの概念説明用ソースコード』では
一般の教科書的な記載≪2次元風定義【BYTE a[][]】等を
使用した添え字での配列アクセス風に記載して居ます≫を
行いましたが、【画像処理ライブラリ仕様】は、基本、
画像を1次元配列とし定義し、ポインタアクセスを行って
いますので画像処理ライブラリ説明との溝を埋める為の
エッセイ『画像フィルターの概念説明』の為のソースコード
を説明します!
1.ヘッダー
(1)インクルードするファイル
Code:
#include "ImageFunc.h" // 画像処理ライブラリヘッダーファイル
ココで使用する画像処理ライブラリは、画像ファイルの読み
書きも入っているので実際に動作させて確認出来ます!
「画像ファイルの読み書き」は最低原の使用方法説明だけ行
います!
一番、重要なのは、解説『画像メモリ概要』で説明した画像
処理ライブラリでのソースコード上での画像の扱い方≪具体
的には、「TypeArray」クラスで画像を定義する事≫です!
(2)ライブラリ関数を使う、前準備
// 画像処理ライブラリのソースコードを読み解く予備とし
// 画像フィルターの概念説明用ソースコードを画像処理ライブラリ仕様
// ライブラリの画像ファイル使用方法やポインタを多用した処理
// ここからは、コメントも画像処理ライブラリ仕様は「C++」なのでC++仕様
// 画像処理ライブラリ自身のソースコードを読んで頂ければ、更にポインタの性質と
// ローカル変数がCPUのレジスターに割り当て易い様に工夫した高速化処理で教科書的記載と
// は、似て似つかない記述に成って居ますが、その高速化記述の中間の過渡期コードをここでは
// 紹介します!
#include "ImageFunc.h" // 画像処理ライブラリヘッダーファイル
#define HSIZE 1000 // 水平方向サイズが1000*/
#define VSIZE 1000 // 垂直方向サイズが1000*/
ImageFunc FUN; // 画像処理ライブラリ駆動メソッドベース用大域変数
int k[9]; // 係数Kのテーブル3×3を1次元配列のデータ構造で
// 表現?!
TypeArray* pa; // 元画像Aを示すポインタ
TypeArray* pb; // 結果画像Bを示すポインタ
で示した様にクラス「ImageFunc」をデータ型として
大域変数「FUN」を定義します!全て英大文字にしたのは
目立たせる為です!
![](https://assets.st-note.com/img/1729178588-J1XOq9HGeh4Q8gSPdA2zwriL.png?width=1200)
で示した様にクラス「ImageFunc」を使用すれば、全ての
関数の機能が使用出来ます!
「int k[9];」は、係数Kを格納するテーブルです!
教科書的記述との違いは、1次元配列にして居ることです!
「int」型にして有るのは、負の数もセット出来る事と、
コンパイル時に無駄な型変換が起きない機械コードが生成
出来る為と基本、常に高速化処理を考えて居る為も有ります
私は、基本カリカリに車をチューンアップする人種と似た
ソースコードも基本、分かり易い記述よりも高速化を求める
阿呆です!
「TypeArray* pa;」は、元画像を意味する画像型として
ポインタアクセスを基本としたデータ構造です!
「TypeArray* pb;」は、結果画像を意味する画像型として
ポインタアクセスを基本としたデータ構造です!
(3)元画像Aと結果画像Bのサイズサイズ&実態メモリ
code:
// 元画像Aと結果画像Bのメモリ実態メモリ取得
void initImage(void)
{
pa->Malloc( 1, HSIZE, VSIZE ); // 元画像Aの実態メモリ取得
pb->Malloc( 1, HSIZE, VSIZE ); // 結果画像Bの実態メモリ取得
}
「pa->Malloc( 1, HSIZE, VSIZE );」で元画像に実体メモリ
を割り付ける!
「pb->Malloc( 1, HSIZE, VSIZE );」で結果画像に実体
メモリを割り付ける!
処理する前に関数「initImage();」を実行すると
「TypeArray* pa;TypeArray* pb;」が使用可能に成ります!
(4)実際に実行する関数群
// (ΣΣK(i,j)×A(x+i-1,y+j-1))÷9⇒
// 画像フィルターの概念説明の数式で一番、肝に成る部分のソースコード */
int Ave33( int x, int y ) // 仮引数(注視点XY座標)で辺値は3×3平均値
{
int* pk; // 係数Kへのアクセスポインタ変数
BYTE* pax; // 元画像AへのX座標方向ポインタ変数
BYTE* pay; // 元画像AへのX座標方向ポインタ変数
int inc; // Y座標方向への増加幅
int i; // カウンタ:3⇒0と計数
int j; // カウンタ:3⇒0と計数
int sum = 0; // 合計値:初期値=0
inc = pa->inc; // 増加幅を内部変数にセット:高速化
pk = k; // 係数Kへのアクセスポインタ=先頭セット
pay = pa->getPtrByte( x - 1, y - 1 ); // 注視点の左上の位置を画像アクセスポインタとしセット
for( j = 3; --j >= 0;pay += inc ){ // お馴染みforループ構文ですが依り高速化表記
pax = pay; // 元画像AへのX座標方向ポインタ変数セット
for( i = 3; --i >= 0; ){ // お馴染みforループ構文ですが依り高速化表記
sum += *pk++ * pax++; // 計算式本体*/
} // forループ構文終端
} // forループ構文終端
return( sum / 9 ); // 平均値を関数辺値とし返す
}
// 画像1枚を元画像「A」から結果画像「B」へ */
void exeFlt33( // 関数名「exeFlt33」で実行・フィルター演算・3×3*/
int xs, int xe, // 仮引数(X座標左端・右端) */
int ys, int ye ) // 仮引数(Y座標上端・下端) */
{
BYTE* pbx; // 結果画像BへのX座標方向ポインタ変数
BYTE* pby; // 結果画像BへのX座標方向ポインタ変数
int inc; // Y座標方向への増加幅
int x; // X座標 */
int y; // Y座標 */
inc = pb->inc; // 増加幅を内部変数にセット:高速化
pby = pb->getPtrByte( x, y ); // 注視点位置を結果画像アクセスポインタとしセット
for( y = ys; y <= ye; y++, pby += inc ){ // Y座標を上端⇒下端へ増分ループ
pbx = pby; // 結果画像AへのX座標方向ポインタ変数セット
for( x = xs; x <= xe; x++ ){ // X座標を左端⇒右端へ増分ループ */
*pbx++ = Ave33( x, y ); // 3×3空間フィルター演算の値を結果書き込み */
} // forループ構文終端:内側(X座標) */
} // forループ構文終端:外側(Y座標) */
}
「int Ave33(int x,int y)」は、関数名「Ave33」と
「Ave」は、平均値(average)省略で「33」は、3×3と
3掛ける3のマス目を意味します!関数辺値「int型」で
計算した平均値を答えにします!
「int* pk;」は、計数K(3×3)をサイズ9の1次元配列
としポインタアクセスを行うポインタ変数!
「BYTE* pax;」は、元画像の実アクセスをX座標方向
「BYTE* pay;」は、元画像の実アクセスをY座標方向
「int inc;」は、画像のY座標方向へポインタ移動用増加幅
「int i;」は、カウンター3回ループ用
「int j;」は、カウンター3回ループ用
「int sum=0;」は、平均値を算出する為の合計値格納する
場所を用意して初期値とし0にして居ます!
「inc=pa->inc;」は、元画像の増加幅を高速化の為にロー
カル変数に取り出す!
「pk=k;」は、係数Kの先頭をポインタ変数にセット
「pay=pa->getPtrByte(x-1,y-1);」は、元画像の注視点(
x,y)の左上の実画素ポインタをポインタ変数にセット
「for(j=3;--j>=0;pay+=inc){・・ループ中身・・}」は、
「for(j=3;--j>=0;){}」で教科書的な
「for(j=0;j<3;j++){}」の記述依りCPUでの機械コード
はより効率的で高速なコードにコンパイルされます!
Y座標方向に3回ループして居る事は理解して居る筈!
「pay+=inc」は、Y座標方向にポインタ変数にを増加です!
「pax=pay;」は、X座標方向にポインタ変数をセット
「for( i = 3; --i >= 0; ){・・ループ中身・・}」は、
X座標方向に3回ループして居る事は理解して居る筈!
「sum+=*pk++*pax++;」は、係数K×元画像Aを算出し合計
「 return(sum/9);」は、合計値を9≪3×3升なので9個
画素×係数が有るので9個≫で除算した値を関数辺値として
返す!
「void exeFlt33(int xs,int xe,int ys,int ye)」は、
関数名「exeFlt33」と「exe」は実行、「Flt」は空間フィル
ター、「33」は3×3と3掛ける3のマス目を意味し、
「void」なので関数辺値は返しません!
仮引数「int xs,int xe,」は、X座標の処理始点・終点を
意味し、仮引数「int ys,int ye」は、Y座標の処理始点・
終点を意味します!
「BYTE* pbx;」は、結果画像の実アクセスをX座標方向
「BYTE* pby;」は、結果画像の実アクセスをY座標方向
「int inc;」は、画像のY座標方向へポインタ移動用増加幅
ローカル変数「int x;int y;」は、XY座標を示します!
ココは、教科書的な記載と同じにします!何故かは、
関数「Ave33(x,y);」を使用するからです?!但し、
画像処理ライブラリでの記述は、完全にポインタ変数を
使用する方式ですから、途中のメタモルフォーゼ中と考え
て下さい!
「for(y=ys;y<=ye;y++,pby+=inc){・・ループ中身・・}」
は、外側ループとし「y=ys~ye」を昇順にカウントアップ
します!
※何故、「Y座標」方向を外側にして居るかは、画像処理
ライブラリのアルゴリズムを記載する時に依り高速化処理に
成るから、外側が「Y座標」方向、内側が「X座標」方向と
成る事に馴れて欲しいからです!
「pby+=inc」は、Y座標ポインタ変数をY方向に増加!
「pbx=pby;」は、X座標方向にポインタ変数をセット
「for(x=xs;x<=xe;x++){・・ループ中身・・}」は、内側
ループとし「x=xs~xe」を昇順にカウントアップします!
「*pbx++=Ave33(x,y);」は、結果B「x,y」に対応する
元画像のA「x,y」の空間フィルター3×3演算≪関数「
Ave33(x,y)」で計算処理≫を行い結果B「x,y」に格納!