見出し画像

欅坂46から櫻坂46に改名した事を画像処理的に考察例文ソースコード説明

欅坂46から櫻坂46に改名した事を画像処理的に考察例文
ソースコード説明


2024年12月28初稿

ここのソースコードは、エッセイ『欅坂46から櫻坂46に
改名した事を画像処理的に考察』
用です!上記エッセイの
ファイル「欅BMP白黒.bmp」・
ファイル「櫻BMP白黒.bmp」を使用します!

1.単純正規化相関比較

(1)画像処理ライブラリを使う前準備

#include"ImageFunc.h"           // 画像処理ライブラリ用
ImageFunc FUN;                  // ライブラリ関数使用定義

main()
{

「#include"ImageFunc.h"」は、画像処理ライブラリの関数
(メソッド)群を使用可能に成る定義をインクルード
「ImageFunc FUN;」は、メソッドを実際に呼び出す、
例えば、ローカル変数とし
「int h;int v;int c;long xPixPerMeter;long xPiyPerMeter;
int sti;」を用意して
「sti=FUN.ReadBitmapAttribute("欅BMP白黒.bmp",
&h,&v,&c,&xPixPerMeter,&yPixPerMeter);」の様にメソッド
を実行するソースコードを記載出来、上記は、
画像ファイル「欅BMP白黒.bmp」の画像ファイル特徴と
して「&h,」は、画像水平幅(今回は、640の筈)、
「&v」は、画像垂直幅(今回は、480の筈)、
「,&c,」は、画像画素のビット幅≪「1」なら1ビット画素
なので2色、「8」なら8ビット(1バイト)画素なので
256色(色と表現だが「0・・255」と濃淡と言うか輝度で
今回は、8の筈)を「&変数」で変数にセットする!
「main(){」は、今回の例文のメインプログラムの書き出し

(2)画像ファイル読み出しとメインプログラム

main()
{
    TypeArray   imgA;           // 画像型変数A
    TypeArray*  pimgA=&imgA;    // 上記へのポインタ
    TypeArray   imgB;           // 画像型変数B
    TypeArray*  pimgB=&imgB;    // 上記へのポインタ
    int         h;              // 水平幅
    int         v;              // 垂直幅
    int         c;              // Bit幅(1,4,8,16,24,32)
    long        xPixPerMeter;   // 水平解像度(Pix/m)
    long        yPixPerMeter;   // 垂直解像度(Pix/m)

    sti=FUN.ReadBitmapAttribute(            // ファイル情報読み出し
        "欅BMP白黒.bmp",                 // ファイル「欅BMP白黒.bmp」情報読出
        &h, &v, &c,                         // 今回、必要な情報格納変数
        &xPixPerMeter,                      // 今回、不要な情報だが、引数とし
        &yPixPerMeter);                     // てダミー使用
    if( sti != STI_END ){                   // エラー発生なら
        printf("画像ファイル「欅BMP白黒.bmp」がオカシイ\n");
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    if( h != 640 || v != 480 || c != 8 ){   // 想定したファイル仕様と異なる
        printf("画像ファイル「欅BMP白黒.bmp」がオカシイ\n");
        printf( "h=%d,v=%d,c=%d\n", h, v, c );
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    pimgA->MallocBYTE (h,v);                // 画像ファイルサイズで画像情報セット
    FUN.Clear(pimgA,0);                     // 一旦、画像を0クリア
    FUN.ReadBitmap("欅BMP白黒.bmp",      // ファイル「欅BMP白黒.bmp」を
                                pimgA );    // 画像とし画像「imgA」に格納
    sti=FUN.ReadBitmapAttribute(            // ファイル情報読み出し
        "櫻BMP白黒.bmp",                 // ファイル「櫻BMP白黒.bmp」情報読出
        &h, &v, &c,                         // 今回、必要な情報格納変数
        &xPixPerMeter,                      // 今回、不要な情報だが、引数とし
        &yPixPerMeter);                     // てダミー使用
    if( sti != STI_END ){                   // エラー発生なら
        printf("画像ファイル「櫻BMP白黒.bmp」がオカシイ\n");
        pimgA->freeMem();                   // 画像メモリ解放画像「imgA」
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    if( h != 640 || v != 480 || c != 8 ){   // 想定したファイル仕様と異なる
        printf("画像ファイル「櫻BMP白黒.bmp」がオカシイ\n");
        pimgA->freeMem();                   // 画像メモリ解放画像「imgA」
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    pimgB->MallocBYTE (h,v);                // 画像ファイルサイズで画像情報セット
    FUN.Clear(pimgB,0);                     // 一旦、画像を0クリア
    FUN.ReadBitmap("櫻BMP白黒.bmp",      // ファイル「櫻BMP白黒.bmp」を
                                pimgB );    // 画像とし画像「imgB」に格納
    execute( pimgA, pimgB );                // 例文の実行部
    pimgA->freeMem();                       // 画像メモリ解放画像「imgA」
    pimgB->freeMem();                       // 画像メモリ解放画像「imgB」
}

「main(){・・本体・・}」は、ご存知、C言語標準のメイン
プログラムを記載する方法!

(2-1)ローカル変数

{
    TypeArray   imgA;           // 画像型変数A
    TypeArray*  pimgA=&imgA;    // 上記へのポインタ
    TypeArray   imgB;           // 画像型変数B
    TypeArray*  pimgB=&imgB;    // 上記へのポインタ
    int         h;              // 水平幅
    int         v;              // 垂直幅
    int         c;              // Bit幅(1,4,8,16,24,32)
    long        xPixPerMeter;   // 水平解像度(Pix/m)
    long        yPixPerMeter;   // 垂直解像度(Pix/m)

「TypeArray imgA;」は、画像情報「imgA」の定義!
「TypeArray* pimgA=&imgA;」は、画像情報ポインタ変数
「TypeArray* pimgA」に画像情報「imgA」をセット
「TypeArray imgB;」は、画像情報「imgB」の定義!
「TypeArray* pimgB=&imgB;」は、画像情報ポインタ変数
「TypeArray* pimgB」に画像情報「imgB」をセット
「int h;」は、画像の水平幅
「int v;」は、画像の垂直幅
「int c;」は、画像ファイルの画素ビット幅
「long xPixPerMeter;」は、画像ファイルの水平解像度
「long yPixPerMeter;」は、画像ファイルの垂直解像度

(2-2)アルゴリズム

    sti=FUN.ReadBitmapAttribute(            // ファイル情報読み出し
        "欅BMP白黒.bmp",                 // ファイル「欅BMP白黒.bmp」情報読出
        &h, &v, &c,                         // 今回、必要な情報格納変数
        &xPixPerMeter,                      // 今回、不要な情報だが、引数とし
        &yPixPerMeter);                     // てダミー使用
    if( sti != STI_END ){                   // エラー発生なら
        printf("画像ファイル「欅BMP白黒.bmp」がオカシイ\n");
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    if( h != 640 || v != 480 || c != 8 ){   // 想定したファイル仕様と異なる
        printf("画像ファイル「欅BMP白黒.bmp」がオカシイ\n");
        printf( "h=%d,v=%d,c=%d\n", h, v, c );
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    pimgA->MallocBYTE (h,v);                // 画像ファイルサイズで画像情報セット
    FUN.Clear(pimgA,0);                     // 一旦、画像を0クリア
    FUN.ReadBitmap("欅BMP白黒.bmp",      // ファイル「欅BMP白黒.bmp」を
                                pimgA );    // 画像とし画像「imgA」に格納
    sti=FUN.ReadBitmapAttribute(            // ファイル情報読み出し
        "櫻BMP白黒.bmp",                 // ファイル「櫻BMP白黒.bmp」情報読出
        &h, &v, &c,                         // 今回、必要な情報格納変数
        &xPixPerMeter,                      // 今回、不要な情報だが、引数とし
        &yPixPerMeter);                     // てダミー使用
    if( sti != STI_END ){                   // エラー発生なら
        printf("画像ファイル「櫻BMP白黒.bmp」がオカシイ\n");
        pimgA->freeMem();                   // 画像メモリ解放画像「imgA」
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    if( h != 640 || v != 480 || c != 8 ){   // 想定したファイル仕様と異なる
        printf("画像ファイル「櫻BMP白黒.bmp」がオカシイ\n");
        pimgA->freeMem();                   // 画像メモリ解放画像「imgA」
        exit( 0 );                          // C言語標準関数でプログラム終了
    }
    pimgB->MallocBYTE (h,v);                // 画像ファイルサイズで画像情報セット
    FUN.Clear(pimgB,0);                     // 一旦、画像を0クリア
    FUN.ReadBitmap("櫻BMP白黒.bmp",      // ファイル「櫻BMP白黒.bmp」を
                                pimgB );    // 画像とし画像「imgB」に格納
    execute( pimgA, pimgB );                // 例文の実行部
    pimgA->freeMem();                       // 画像メモリ解放画像「imgA」
    pimgB->freeMem();                       // 画像メモリ解放画像「imgB」
}

「sti=FUN.ReadBitmapAttribute("欅BMP白黒.bmp",
&h,&v,&c,&xPixPerMeter,&yPixPerMeter);」は、
画像ファイル「欅BMP白黒.bmp」のファイルとしての諸元
情報≪画像としての水平幅・垂直幅・画素のビット単位・
水平垂直の解像度≫を取得する関数です!
「if( sti != STI_END ){printf(メッセージ);exit(0);}」
は、エラー発生時にエラーメッセージ≪ここでは、
「("画像ファイル「欅BMP白黒.bmp」がオカシイ」≫を
表示し、「exit(0);」でプログラム終了!
「if(h!=640||v!=480||c!=8){printf(メッセージ);
exit(0);}」は、
条件「h!=640||v!=480||c!=8」で例文用に用意した画像ファ
イル「欅BMP白黒.bmp」なら水平幅=640、垂直幅=480、
画素のビット数=8に成る筈が異なるのでエラーと判断して
「printf(メッセージ);」とエラーメッセージを出して
因みにメッセージ
「("画像ファイル「欅BMP白黒.bmp」がオカシイ」です!
「exit(0);」でプログラム終了!
「pimgA->MallocBYTE(h,v);FUN.Clear(pimgA,0);」は、
画像メモリ「pimgA」実態を動的に確保し、0クリア、
「FUN.ReadBitmap("欅BMP白黒.bmp",pimgA);」は、
画像メモリ「pimgA」に画像ファイル「欅BMP白黒.bmp」
の画像を読み出す!
「sti=FUN.ReadBitmapAttribute("櫻BMP白黒.bmp",
&h,&v,&c,&xPixPerMeter,&yPixPerMeter);」は、
画像ファイル「櫻BMP白黒.bmp」のファイルとしての諸元
情報≪画像としての水平幅・垂直幅・画素のビット単位・
水平垂直の解像度≫を取得する関数です!
「if( sti != STI_END ){printf(メッセージ);
pimgA->freeMem();exit(0);}」
は、エラー発生時にエラーメッセージ≪ここでは、
「("画像ファイル「櫻BMP白黒.bmp」がオカシイ」≫を
表示し、
「pimgA->freeMem();」は、画像メモリ解放「imgA」
「exit(0);」でプログラム終了!
「if(h!=640||v!=480||c!=8){printf(メッセージ);
pimgA->freeMem();exit(0);}」は、
条件「h!=640||v!=480||c!=8」で例文用に用意した画像ファ
イル「櫻BMP白黒.bmp」なら水平幅=640、垂直幅=480、
画素のビット数=8に成る筈が異なるのでエラーと判断して
「printf(メッセージ);」とエラーメッセージを出して
因みにメッセージ
「("画像ファイル「櫻BMP白黒.bmp」がオカシイ」です!
「pimgA->freeMem();」は、画像メモリ解放「imgA」
「exit(0);」でプログラム終了!
「pimgB->MallocBYTE(h,v);FUN.Clear(pimgB,0);」は、
画像メモリ「pimgB」実態を動的に確保し、0クリア、
「FUN.ReadBitmap("櫻BMP白黒.bmp",pimgB);」は、
画像メモリ「pimgB」に画像ファイル「櫻BMP白黒.bmp」
の画像を読み出す!
「execute( pimgA, pimgB );」は、実際の処理部
「pimgA->freeMem();」は、画像メモリ解放「imgA」
「pimgB->freeMem();」は、画像メモリ解放「imgB」

2.execute(pimgA,pimgB);実際の処理部

void    execute(
    TypeArray*  pimgA,                          // テンプレート画像全体
    TypeArray*  pimgB                           // サーチ対象画像
){
    TypeXY      bufXY[1000];                    // 座標結果格納バッファー
    double      buf[1000];                      // 相関値結果格納バッファー
    short       bufix[1000];                    // ソート用補助バッファー
    TypeXY*     pXY;                            // 座標結果格納バッファー実行ポインタ
    double*     pbuf;                           // 相関値結果格納バッファー実行ポインタ
    BYTE*       ptrA;                           // A画像:処理ポインタ
    BYTE*       ptrBX;                          // B画像:処理ポインタX座標方向
    BYTE*       ptrBY;                          // B画像:処理ポインタY座標方向
    int         incA;                           // A画像:増加幅
    int         incB;                           // B画像:増加幅
    int         x;                              // マッチング用部分画像X座標
    int         y;                              // マッチング用部分画像Y座標
    int         n;                              // マッチング用部分水平幅(N×MのN)
    int         m;                              // マッチング用部分垂直幅(N×MのM)
    int         h;                              // マッチング用画像水平幅
    int         v;                              // マッチング用画像垂直幅
    int         stepX;                          // マッチング用画像X座標移動ステップ
    int         stepY;                          // マッチング用画像Y座標移動ステップ
    int         cnt;                            // 計測個数カウント
    double      data;                           // 相関値≒一致率

    getPatternSize( pimgA, x, y, n, m );        // テンプレート画像サイズ範囲取得
    ptrA    = pimgA->getPtrByte( x, y );        // A画像:テンプレート画像ポインタをセット
    ptrBY   = pimgB->getPtrByte( 0, 0 );        // B画像:サーチ画像ポインタを画像左上隅セット
    h       = pimgB->h;                         // B画像:サーチ画像の水平幅
    v       = pimgB->v;                         // B画像:サーチ画像の垂直幅
    incA    = pimgA->inc;                       // A画像:増加幅ローカル変数セット
    incB    = pimgB->inc;                       // B画像:増加幅ローカル変数セット
    stepX   = 1;                                // テンプレートマッチングする座標移動量を
    stepY   = 1;                                // 1画素単位≪備考:処理時間甚大だが、
                                                // 説明用なので1に設定:後で高速化説明予定≫
    pXY     = bufXY;                            // 座標結果格納バッファー実行ポインタ
    pbuf    = buf;                              // 相関値結果格納バッファー実行ポインタ
    cnt     = 0;                                // 個数カウント初期化
    for( y = 0; y < v; y += stepY ){            // 外側ループとし垂直方向処理
        ptrBX = ptrBY;                          // 水平方向サーチ原点セット
        for( x = 0; x < h; x += stepX ){        // 内側ループとし水平方向処理
            data = FUN.CorrNM( ptrA, ptrBX,     // n×m画素の正規相関を
                            incA, incB, n, m ); // 算出し
            printf( "data=%e,(%d,%d)\n",        // 例文なので途中結果(一致率、座標)表示
                        data, x, y );           // 
            if( abs(data) > 0.5){               // 条件「絶対値(相関値)が0.5超え」
                if( cnt < 1000 ){               // 再条件「格納数が1000未満」の場合で
                    cnt++;                      // 格納数をカウントアップ
                    *pbuf++ = data;             // バッファーに格納
                    pXY->x  = x;                // X座標格納
                    pXY->y  = y;                // Y座標格納
                    pXY++;                      // 座標結果格納バッファー実行ポインタ増加
                }                               //
            }                                   //
            ptrBX += stepX;                     // サーチ画像ポインタを水平方向増加
        }                                       //
        ptrBY += incB * stepY;                  // サーチ画像ポインタを垂直方向増加
    }
    FUN.SortIndex( 1, buf, bufix, cnt );        // リンク用インデックス付きで相関値で降順≪
                                                // 大⇒小≫にソーティング
    FUN.SortCopy( bufXY, bufix, cnt );          // 座標結果も連動してソーティング
    for( int i=0; i < cnt; i++ ){               // ソーティングした結果バッファーをインデックスで
        printf( "data=%e,(%d,%d)\n",            // 例文なのでソーティング結果(一致率、座標)
            buf[i], bufXY[i].x, bufXY[i].y );   // 表示
    }                                           // ループ
}


(1)関数名

「execute」英単語ソノママ「実行する」です!

(2)仮引数

void    execute(
    TypeArray*  pimgA,                      // テンプレート画像全体
    TypeArray*  pimgB                       // サーチ対象画像
){

「TypeArraypimgA,」は、テンプレート画像全体
「TypeArraypimgB 」は、サーチ対象画像

(3)ローカル変数

){
    TypeXY      bufXY[1000];                    // 座標結果格納バッファー
    double      buf[1000];                      // 相関値結果格納バッファー
    short       bufix[1000];                    // ソート用補助バッファー
    TypeXY*     pXY;                            // 座標結果格納バッファー実行ポインタ
    double*     pbuf;                           // 相関値結果格納バッファー実行ポインタ
    BYTE*       ptrA;                           // A画像:処理ポインタ
    BYTE*       ptrBX;                          // B画像:処理ポインタX座標方向
    BYTE*       ptrBY;                          // B画像:処理ポインタY座標方向
    int         incA;                           // A画像:増加幅
    int         incB;                           // B画像:増加幅
    int         x;                              // マッチング用部分画像X座標
    int         y;                              // マッチング用部分画像Y座標
    int         n;                              // マッチング用部分水平幅(N×MのN)
    int         m;                              // マッチング用部分垂直幅(N×MのM)
    int         h;                              // マッチング用画像水平幅
    int         v;                              // マッチング用画像垂直幅
    int         stepX;                          // マッチング用画像X座標移動ステップ
    int         stepY;                          // マッチング用画像Y座標移動ステップ
    int         cnt;                            // 計測個数カウント
    double      data;                           // 相関値≒一致率

「TypeXY bufXY[1000];」は、XY座標結果バッファー
「double buf[1000];」は、相関値結果バッファー
「short bufix[1000];」は、ソーティング用補助バッファー
「TypeXY* pXY;」は、XY座標結果バッファー操作ポインタ
「double* pbuf;」は、相関値結果バッファー操作ポインタ
「BYTE* ptrA;」は、テンプレート画像処理ポインタ
「BYTE* ptrBX;」は、サーチ対象画像X座標処理ポインタ
「BYTE* ptrBY;」は、サーチ対象画像Y座標処理ポインタ
「int incA;」は、テンプレート画像の垂直方向増加幅
「int incB;」は、サーチ対象画像の垂直方向増加幅
「int x;」は、サーチ対象画像のX座標
「int y;」は、サーチ対象画像のY座標
「int n;」は、正規相関N×MのN
「int m;」は、正規相関N×MのM
「int h;」は、サーチ対象画像の水平幅
「int v;」は、サーチ対象画像の垂直幅
「int stepX;」は、サーチ対象への水平方向画素進行単位
「int stepY;」は、サーチ対象への垂直方向画素進行単位
「int cnt;」は、計測個数
「double data;」は、相関値

(4)アルゴリズム

    getPatternSize( pimgA, x, y, n, m );        // テンプレート画像サイズ範囲取得
    ptrA    = pimgA->getPtrByte( x, y );        // A画像:テンプレート画像ポインタをセット
    ptrBY   = pimgB->getPtrByte( 0, 0 );        // B画像:サーチ画像ポインタを画像左上隅セット
    h       = pimgB->h;                         // B画像:サーチ画像の水平幅
    v       = pimgB->v;                         // B画像:サーチ画像の垂直幅
    incA    = pimgA->inc;                       // A画像:増加幅ローカル変数セット
    incB    = pimgB->inc;                       // B画像:増加幅ローカル変数セット
    stepX   = 1;                                // テンプレートマッチングする座標移動量を
    stepY   = 1;                                // 1画素単位≪備考:処理時間甚大だが、
                                                // 説明用なので1に設定:後で高速化説明予定≫
    pXY     = bufXY;                            // 座標結果格納バッファー実行ポインタ
    pbuf    = buf;                              // 相関値結果格納バッファー実行ポインタ
    cnt     = 0;                                // 個数カウント初期化
    for( y = 0; y < v; y += stepY ){            // 外側ループとし垂直方向処理
        ptrBX = ptrBY;                          // 水平方向サーチ原点セット
        for( x = 0; x < h; x += stepX ){        // 内側ループとし水平方向処理
            data = FUN.CorrNM( ptrA, ptrBX,     // n×m画素の正規相関を
                            incA, incB, n, m ); // 算出し
            printf( "data=%e,(%d,%d)\n",        // 例文なので途中結果(一致率、座標)表示
                        data, x, y );           // 
            if( abs(data) > 0.5){               // 条件「絶対値(相関値)が0.5超え」
                if( cnt < 1000 ){               // 再条件「格納数が1000未満」の場合で
                    cnt++;                      // 格納数をカウントアップ
                    *pbuf++ = data;             // バッファーに格納
                    pXY->x  = x;                // X座標格納
                    pXY->y  = y;                // Y座標格納
                    pXY++;                      // 座標結果格納バッファー実行ポインタ増加
                }                               //
            }                                   //
            ptrBX += stepX;                     // サーチ画像ポインタを水平方向増加
        }                                       //
        ptrBY += incB * stepY;                  // サーチ画像ポインタを垂直方向増加
    }
    FUN.SortIndex( 1, buf, bufix, cnt );        // リンク用インデックス付きで相関値で降順≪
                                                // 大⇒小≫にソーティング
    FUN.SortCopy( bufXY, bufix, cnt );          // 座標結果も連動してソーティング
    for( int i=0; i < cnt; i++ ){               // ソーティングした結果バッファーをインデックスで
        printf( "data=%e,(%d,%d)\n",            // 例文なのでソーティング結果(一致率、座標)
            buf[i], bufXY[i].x, bufXY[i].y );   // 表示
    }                                           // ループ
}

「getPatternSize(pimgA,x,y,n,m);」は、下請け関数
「getPatternSize()」でパターン画像「pimgA」の
範囲「x,y,n,m」を算出
「ptrA=pimgA->getPtrByte(x,y);」は、パターン画像の
先頭(左上隅)の画像画素ポインタをセット
「ptrBY=pimgB->getPtrByte(0,0);」は、サーチ対象画像の
先頭(左上隅)の画像画素ポインタをセット
「h=pimgB->h;v=pimgB->v;」は、サーチ対象画像の
水平幅・垂直幅をローカル変数にセット
「incA=pimgA->inc;incB=pimgB->inc;」は、パターン画像と
サーチ対象画像の増加幅≪垂直方向に増加する為の幅≫を
ローカル変数にセット
「stepX=1;stepY=1;」は、パターン画像とサーチ対象画像の
マッチング≪相関演算≫する移動画素単位をセット、ここで
は1画素と最小の値をセット
「pXY=bufXY;」は、XY座標結果バッファーへのポインタを
セット
「pbuf=buf;」は、相関値結果バッファーへのポインタを
セット
「cnt=0;」は、有効相関値結果個数を初期化=0
「for(y=0;y<v;y+=stepY){・・外側ループ・・}」は、
forループ「(y=0;y<v;y+=stepY)」でY座標方向に繰り返
し初期値「y=0;」でループ条件「y<v;」Y座標が垂直幅未満
で繰り返し、増分「y+=stepY」でY座標を増加し、ループ
中身を繰り返す!その外側ループ中身は
「ptrBX=ptrBY;」は、水平方向の画像画素処理始点セット
「for(x=0;x<h;x+=stepX){・・内側ループ・・}」は、
forループ「(x=0;x<h;x+=stepX)」でX座標方向に繰り返
し初期値「x=0;」でループ条件「x<h;」X座標が水平幅未満
で繰り返し、増分「x+=stepX」でX座標を増加し、ループ
中身を繰り返す!その内側ループ中身は
「data=FUN.CorrNM(ptrA,ptrBX,incA,incB,n,m);」は、
下請け関数「FUN.CorrNM(ptrA,ptrBX,incA,incB,n,m)」で
「FUN.」と画像処理ライブラリ関数の「CorrNM()」でN×M
サイズ≪ココではN×MのN=「n」・M=「m」≫で正規相
関算出し答えの相関値を「data」にセット、
「printf("data=%e,(%d,%d)\n",data,x,y);」は、デバッグ
用に途中結果を表示
「if(abs(data)>0.5){・・外側分岐本体・・}」は、
条件「abs(data)>0.5」で相関値の絶対値≪相関値は負の数
に成る場合有り≫が「0.5」を超える場合は有効とし外側
分岐本体を処理、その本体で
「if(cnt<1000){
cnt++;*pbuf++=data;pXY->x=x;pXY->y=y;pXY++;}」は、
条件「cnt<1000」と計測個数が「1000」未満なら、
「cnt++;」で計測個数をカウントアップ、
「*pbuf++=data;」で相関値結果バッファーに相関値を
追加、
「pXY->x=x;pXY->y=y;」でXY座標を座標結果バッファーに
追加、「pXY++;」でXY座標を座標結果バッファーを指す
ポインタを増加、if分岐が外側内側と終わったら、
「ptrBX+=stepX;」で水平方向(X座標方向)ポインタ増加
forループ内側が終わったら、
「ptrBY+=incBstepY;」で垂直方向(Y座標方向)ポインタ
増加≪「incBstepY」で垂直方向への増分を算出≫
forループ外側が終わったら、
「FUN.SortIndex(1,buf,bufix,cnt);」は、相関値をキー
ソートのキーとして下請け関数「FUN.SortIndex()」で
「FUN.」と画像処理ライブラリ関数の「SortIndex()」で
「1,」と降順≪大⇒小に整列≫に「buf,」と相関値結果の値
で整列し同時に「bufix,」と連動インデックスを整列し、
そのソートする数は「cnt」でソーティングする!
「FUN.SortCopy(bufXY,bufix,cnt);」は、連動インデックス
「bufix,」を使用して座標結果バッファー「bufXY,」を
「cnt」数分整列する!
「for(int i=0;i<cnt;i++){・・表示ループ・・}」は、
forループ「for(int i=0;i<cnt;i++)」で
内部添字「int i=0;」とループカウンタを初期化し、
ループ条件「i<cnt;」と整列したバッファーをアクセスして
「printf("data=%e,(%d,%d)\n",buf[i],bufXY[i].x,
bufXY[i].y);」と相関値で降順≪大⇒小≫に成った整列デー
タをデバッグ用に表示します

2025年1月2変更

「*buf++=data;」で相関値結果バッファーに相関値を追加を
「*pbuf++=data;」で相関値結果バッファーに相関値を
に修正しました

3.getPatternSize();範囲「x,y,n,m」算出

void    getPatternSize( pimgA, x, y, h, v )
    TypeArray*  pimgA,      // テンプレート画像全体
    int&        x,          // マッチング用部分画像X座標始点
    int&        y,          // マッチング用部分画像Y座標始点
    int&        h,          // マッチング用部分水平幅
    int&        v           // マッチング用部分垂直幅
){
    TypeArray   BinImg;                         // 2値化画像
    TypeArray*  pBinImg=&BinImg;                // 2値化画像情報へのポインタ
    TypeMB      bufMB[1000];                    // 図形計測バッファー
    TypeMB      *pMB;                           // 上記へのポインタ
    long*       buf[256];                       // ヒストグラム(度数分布)バッファー
    int         t;                              // 2値化しきい値
    int         n;                              // 計測図形個数
    int         xy;                             // XY座標補助
    int         x1;                             // X座標左側
    int         x2;                             // X座標右側
    int         y1;                             // Y座標上側
    int         y2;                             // Y座標下側

    FUN.HistogramImage( pimgA, buf );               // 画像のヒストグラム算出
    t = FUN.GetBinOotu( buf, 256 );                 // 大津法で2値化しきい値作成
    pBinImg->MallocByte( pimgA->h, pimgA->v);       // 2値化画像の実体メモリ動的確保
    FUN.Binarization( pimgA, pBinImg, t, 1 );       // 2値化(0,1)
    pMB = bufMB;                                    // 図形計測バッファーポインタセット
    n   = FUN.MeasureFere( 8, pBinImg, pMB,         // 図形計測としフェレ計測を行う
                                        1000 );     // 
    printf( "n=%d\n", n );                          // デバッグ用計測図形数表示
    x1  = pimgA->h;                                 // X座標左側初期化
    x2  = 0;                                        // X座標右側初期化
    y1  = pimgA->v;                                 // Y座標上側初期化
    y2  = 0;                                        // Y座標下側初期化
    for( int i = 0; i < n; i++, pMB++ ){            // 計測結果内をループして
        x1 = ( x1 > pMB->x ) ? pMB->x : x1;         // X座標左側更新
        y1 = ( y1 > pMB->y ) ? pMB->y : y1;         // Y座標上側更新
        xy = pMB->x + pMB->h - 1;                   // フェレ計測X座標右側算出
        x2 = ( x2 < xy ) ? xy : x2;                 // X座標右側更新
        xy = pMB->y + pMB->v - 1;                   // フェレ計測Y座標下側算出
        y2 = ( y2 < xy ) ? xy : y2;                 // Y座標下側更新
    }                                               // 
    printf("左上隅(%d,%d)⇒右下隅(%d,%d)\n",    // デバッグ用計測座標表示
                            x1, y1, x2, y2 );       //
    x = x1;                                         // 引数返値としX座標セット
    y = y1;                                         // 引数返値としY座標セット
    h = x2 - x1 + 1;                                // 引数返値とし水平幅セット
    v = y2 - y1 + 1;                                // 引数返値とし垂直幅セット
    pBinImg->freeMem();                             // 動的確保メモリ解放
}

(1)関数名

「get」は、カタカナ語「ゲット」で取得するです!
「Pattern」は、カタカナ語「パターン」でパターン画像を
意味
「Size」は、カタカナ語「サイズ」で「PatternSize」で
パターン画像のサイズ≒範囲を算出し、
「getPatternSize」でパターン画像の範囲とサイズ取得

(2)仮引数

void    getPatternSize( pimgA, x, y, h, v )
    TypeArray*  pimgA,      // テンプレート画像全体
    int&        x,          // マッチング用部分画像X座標始点
    int&        y,          // マッチング用部分画像Y座標始点
    int&        h,          // マッチング用部分水平幅
    int&        v           // マッチング用部分垂直幅
){

「TypeArray*pimgA,」は、テンプレート画像全体
「int& x,」は、X座標始点
「int& y,」は、Y座標始点
「int& h,」は、水平幅
「int& v」は、垂直幅

(3)ローカル変数

){
    TypeArray   BinImg;                         // 2値化画像
    TypeArray*  pBinImg=&BinImg;                // 2値化画像情報へのポインタ
    TypeMB      bufMB[1000];                    // 図形計測バッファー
    TypeMB      *pMB;                           // 上記へのポインタ
    long*       buf[256];                       // ヒストグラム(度数分布)バッファー
    int         t;                              // 2値化しきい値
    int         n;                              // 計測図形個数
    int         xy;                             // XY座標補助
    int         x1;                             // X座標左側
    int         x2;                             // X座標右側
    int         y1;                             // Y座標上側
    int         y2;                             // Y座標下側

「TypeArray BinImg;」は、2値化画像情報
「TypeArray* pBinImg=&BinImg;」は、上記へのポインタ
セット
「TypeMB bufMB[1000];」は、2値化画像の図形計測バッ
ファー≪備考:少し前、エッセイ『
この仕事は天職だと感じたアルゴリズム開発(続1)』

使用した事を説明した型「TypeSf」と言う計測結果格納用
型と同じ事が出来るが項目を必要最小限に絞った
型「TypeMB」にも関数「MeasureFere()」とフェレ計測を行
うオーバーロード(多重定義)サレタ関数で使用しますが、
バッファーのサイズが小さく成る為にココでは使用しました
解説『解説クラスTypeSf』に「TypeSf」・「TypeMB」
の説明は記載しています!≫
「TypeMB* pMB;」は、バッファー「TypeMB bufMB[1000];」
のポインタアクセス用ポインタです
「long* buf[256];」は、ヒストグラム(度数分布)算出用
≪画像画素のヒストグラムなので1バイト画素=「0」から
「255」の値の画素なので配列として256個用意≫
「int t;」は、2値化しきい値≪自然多値画像=「画素が
0..255」を2値化画像=「黒(0)か白(1とか255)」に
変換≫用の値
「int n;」は、図形計測した数で図形≪連結した塊≫事の
計測した図形自体の数
「int xy;」は、XY座標を計算する途中結果
「int x1;」は、X座標左側
「int x2;」は、X座標右側
「int y1;」は、Y座標上側
「int y2;」は、Y座標下側

(4)アルゴリズム

    FUN.HistogramImage( pimgA, buf );               // 画像のヒストグラム算出
    t = FUN.GetBinOotu( buf, 256 );                 // 大津法で2値化しきい値作成
    pBinImg->MallocByte( pimgA->h, pimgA->v);       // 2値化画像の実体メモリ動的確保
    FUN.Binarization( pimgA, pBinImg, t, 1 );       // 2値化(0,1)
    pMB = bufMB;                                    // 図形計測バッファーポインタセット
    n   = FUN.MeasureFere( 8, pBinImg, pMB,         // 図形計測としフェレ計測を行う
                                        1000 );     // 
    printf( "n=%d\n", n );                          // デバッグ用計測図形数表示
    x1  = pimgA->h;                                 // X座標左側初期化
    x2  = 0;                                        // X座標右側初期化
    y1  = pimgA->v;                                 // Y座標上側初期化
    y2  = 0;                                        // Y座標下側初期化
    for( int i = 0; i < n; i++, pMB++ ){            // 計測結果内をループして
        x1 = ( x1 > pMB->x ) ? pMB->x : x1;         // X座標左側更新
        y1 = ( y1 > pMB->y ) ? pMB->y : y1;         // Y座標上側更新
        xy = pMB->x + pMB->h - 1;                   // フェレ計測X座標右側算出
        x2 = ( x2 < xy ) ? xy : x2;                 // X座標右側更新
        xy = pMB->y + pMB->v - 1;                   // フェレ計測Y座標下側算出
        y2 = ( y2 < xy ) ? xy : y2;                 // Y座標下側更新
    }                                               // 
    printf("左上隅(%d,%d)⇒右下隅(%d,%d)\n",    // デバッグ用計測座標表示
                            x1, y1, x2, y2 );       //
    x = x1;                                         // 引数返値としX座標セット
    y = y1;                                         // 引数返値としY座標セット
    h = x2 - x1 + 1;                                // 引数返値とし水平幅セット
    v = y2 - y1 + 1;                                // 引数返値とし垂直幅セット
    pBinImg->freeMem();                             // 動的確保メモリ解放
}

「FUN.HistogramImage(pimgA,buf);」は、ヒストグラム算出
を画像処理ライブラリ関数「FUN.HistogramImage()」で
接頭語「FUN.」と画像処理ライブラリ関数を使う事を示し、
実引数「pimgA,buf」と画像「pimgA」のヒストグラム算出(
度数分布)し結果バッファー「buf」に格納
「t=FUN.GetBinOotu(buf,256);」は、画像処理ライブラリ
関数「GetBinOotu()」でヒストグラム結果バッファー「buf
」から大津法≪恐らく統計学の大昔の教授の名前から命名と
思う≫と言う統計的手法で2値化しきい値を算出!
「pBinImg->MallocByte(pimgA->h,pimgA->v);」は、画像処
理ライブラリ関数「MallocByte()」で動的に画像メモリ実体
を確保≪解説『解説クラスTypeArray』参考≫し
「FUN.Binarization(pimgA,pBinImg,t,1);」は、画像処理ラ
イブラリ関数「Binarization()」で多値画像「pimgA」を
2値化画像「pBinImg」にしきい値「t」未満を「0」に、
「t」以上を「1」に2値化画像変換を行う!
「pMB=bufMB;」は、図形計測バッファーポインタをセット
「n=FUN.MeasureFere(8,pBinImg,pMB,1000);」は、8連結で
2値化画像「pBinImg」の図形計測としてフェレ計測を行い
結果バッファー「pMB」に計測した図形情報を格納し、図形
の個数を「n」にセット
「printf("n=%d\n",n);」は、デバッグ用の図形個数を表示
≪備考:今回使用した「欅」の画像ファイルでは漢字のツナ
ガル画素が8連結では全てツナガル様に思うので恐らく、
実行すれば「n=1」と表示される筈です!しかしながら、私
がド貧乏人で使用出来る環境【ウィンドウズ11で動作する
ビジュアルスタジオ11でのコンパイル⇒実行を1年間無償
期間にウィンドウズXPで快適に動いていたビジュアルスタ
ジオ6.0と同じくダイアログベースで例文作成に挑んだが
ダイアログ用のプログラムを作成する糸口も脳梗塞経験者で
衰えたか継続して訓練が出来て無いので期限切れで過去に
サードパーティー無償コンパイラで画像ファイルベースでの
作成「これは、別のアカウントで発表しました」も既に無償
期間を超えて予算が無いので使用不能】と言う残念な状態で
実際にコンパイルも動かしてもいませんので多分動くとしか
言いようが有りませんので使用される読者様が確認出来る様
に「printf()」を挟んでいます!と言う事で「n=1」では、
1個の図形として図形のフェレ計測情報は一組だけですが、
以下のプログラムコードの様に複数個の個数が出た場合に
対応可能な処理を記載しました≫
「x1=pimgA->h;」は、複数個フェレ計測結果が有るとしての
最左側を計測する変数を真逆の右側を初期値セット
「x2=0;」は、最右を計測する変数を真逆の「0」を初期値
セット
「y1=pimgA->v;」は、最上側を計測する変数を真逆の下側を
初期値セット
「y2=0;」は、最下を計測する変数を真逆の右側を初期値
セット
「for(int i=0;i<n;i++,pMB++){・・座標最大最小・・}」
は、forループ「for(int i=0;i<n;i++,pMB++)」で
初期化「int i=0;」でループカウンタ初期化し、
ループ条件「i<n;」で計測結果個数分繰り返し、
増分「i++,pMB++」でループカウンタ「i」増加と計測結果
バッファー「bufMB」へのポインタ「pMB」を進行させ座標
最大最小の中身、
「x1=(x1>pMB->x)?pMB->x:x1;」でX座標最小値更新
「y1=(y1>pMB->y)?pMB->y:y1;」でY座標最小値更新
「xy=pMB->x+pMB->h-1;x2=(x2<xy)?xy:x2;」の
「xy=pMB->x+pMB->h-1;」でX座標右側を算出し、
「x2=(x2<xy)?xy:x2;」でX座標最大値更新
「xy=pMB->y+pMB->v-1;y2=(y2<xy)?xy:y2;」の
「xy=pMB->y+pMB->v-1;」でY座標上側を算出し、
「y2=(y2<xy)?xy:y2;」でY座標最大値更新
「printf("左上隅(%d,%d)⇒右下隅(%d,%d)\n",
x1,y1,x2,y2);」は、デバッグ用表示です
「x=x1;y=y1;」は、XY座標最小値(左上隅)の値を引数
辺値とし返す
「h=x2-x1+1;v=y2-y1+1;」は、パターン画像の水平垂直幅
を算出し、引数辺値とし返す
「pBinImg->freeMem();」は、内部で動的にメモリ確保した
2値化画像の実体メモリを解放≪OSに返す≫

4.考察

この画像処理ライブラリ関数を使用したソースコードを
コンパイルして実行すると「欅」と「櫻」の画像として
見たら、一致率「execute(pimgA,pimgB);実際の処理部」の
中のデバッグ用に入れた「printf()」での表示で一致率が
フォーマット「%e」なので浮動小数点形式で表示される筈
です、
しかしながら、アルゴリズム中ほどの
「if(abs(data)>0.5){・・・}」と相関値が「0.5」を超え無
いとデータとしては排除して居るので私は、図形を見た経験
から「0.5」程度で丁度いいと判断したが、動作させて無い
ので「0.1」程度に下げる必要が有るかもしれません?!
試行錯誤とし、ソースコードでの提供ですから、数値を変更
して色々試して下さい!
そして、今の画像ファイル「欅」・「櫻」とも、恐らく元々
白黒ハッキリし過ぎた画像と思います!此れでは、ハッキリ
し過ぎてパターン画像のマッチングには、少し画像をボカシ
た方が、一致率が高い気がするので、次の
「欅坂46から櫻坂46に改名した事を画像処理的に考察例
文ソースコード説明その2」
では、画像をボカシてからマッ
チングを掛ける方法を説明します!
今回は、アルゴリズムの説明の為に出来るだけシンプルに
しました!
画像をボカシての方法の後は、高速化≪今回は、パターン
画像(欅)をサーチ対象画像(櫻)の一致率が高い所を探す
手法が二次元XY座標方向に虱潰し的にベターと処理時間の
掛かるが解り易いとして採用しましたが、実用では高速化と
して色々考えラレルので紹介する心算です!≫

文末

いいなと思ったら応援しよう!