見出し画像

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

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


2025年1月4初稿

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

実行関数「execute( pimgA, pimgB );」を高速化する方法を
解説して行きますのでメインプログラム「main(){}」を
ココでは解説しません!高速化した関数「execute()」を
置き換えて実行実験して下さい!

1.高速化版execute( pimgA, pimgB )アルゴリズム

void    execute(
    TypeArray*  pimgA,                          // テンプレート画像全体
    TypeArray*  pimgB                           // サーチ対象画像
){
    TypeXY      bufXY[2000];                    // 座標結果格納バッファー
    double      buf[2000];                      // 相関値結果格納バッファー
    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;                            // 計測個数カウント
    int         cnt1;                           // 計測個数カウント:詳細
    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   = 5;                                // テンプレートマッチングする座標移動量を
    stepY   = 5;                                // 5画素単位≪備考:間引く事で処理時間減少!
                                                // 説明用なので5に設定:高速化処理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 ); // 算出し
            if( abs(data) > 0.1){               // 条件「絶対値(相関値)が0.1超え」
                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 );          // 座標結果も連動してソーティング
    printf( "予備的サーチ個数=%d\n", cnt );	// 予備的サーチ結果数値表示
    for( int i=0; i < cnt; i++ ){               // ソーティングした結果バッファーをインデックスで
        printf( "data=%e,(%d,%d)\n",            // 例文なのでソーティング結果(一致率、座標)
            buf[i], bufXY[i].x, bufXY[i].y );   // 表示
    }                                           // ループ
    cnt1 = cnt;                                 // 詳細個数カウント初期化
    for( int i=0; i < cnt; i++ ){               // ソーティングした結果バッファーをインデックスで
        int x1 = bufXY[i].x - stepX;            // forループ内ローカル変数:X座標始点
        int y1 = bufXY[i].y - stepY;            // forループ内ローカル変数:Y座標始点
        int x2 = x1 + stepX * 2;                // forループ内ローカル変数:X座標終点
        int y2 + stepY * 2;                     // forループ内ローカル変数:Y座標終点
        int xy;                                 // forループ内ローカル変数:座標作業用
        x1 = (x1 < 0) ? 0: x1;                  // 始点が0未満なら0に補正
        y1 = (y1 < 0) ? 0: y1;                  // 始点が0未満なら0に補正
        xy = h - n - 1;                         // サーチ画像右端X座標算出
        x2 = (x2 > xy) ? xy: x2;                // 終点が右端を超えたら右端に補正
        xy = v - m - 1;                         // サーチ画像下端Y座標算出
        y2 = (x2 > xy) ? yy: y2;                // 終点が下端を超えたら下端に補正
        for( int yy=y1; yy <= y2; yy++ ){       // 詳細Y座標方向サーチループ
            for( int xx=x1; xx <= x2; xx++ ){   // 詳細X座標方向サーチループ
                BYTE* ptrBXY =                  // B画像:詳細処理ポインタ
                    pimgB->getPtrByte(xx, yy);  // 
                data = FUN.CorrNM( ptrA,		// n×m画素の正規相関を
                    ptrBXY, incA, incB, n, m ); // 算出し
                if( abs(data) > 0.1){           // 条件「絶対値(相関値)が0.1超え」
                    if( cnt1 < 2000 ){          // 再条件「格納数が2000未満」の場合で
                        cnt1++;                 // 格納数をカウントアップ
                        *pbuf++ = data;         // バッファーに格納
                        pXY->x  = x;            // X座標格納
                        pXY->y  = y;            // Y座標格納
                        pXY++;                  // 座標結果格納バッファー実行ポインタ増加
                    }                           //
                }                               //
            }                                   // 
        }                                       // 
    }                                           // 詳細サーチループ終端
    printf( "詳細サーチ個数=%d\n", cnt1-cnt ); // 詳細サーチ結果数値表示
    for( int i = cnt; i < cnt1; i++ ){          //
        printf( "data=%e,(%d,%d)\n",            // 例文なのでソーティング結果(一致率、座標)
            buf[i], bufXY[i].x, bufXY[i].y );   // 表示
    }                                           // ループ終端
}

(1)ローカル変数

){
    TypeXY      bufXY[2000];                    // 座標結果格納バッファー
    double      buf[2000];                      // 相関値結果格納バッファー
    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;                            // 計測個数カウント
    int         cnt1;                           // 計測個数カウント:詳細
    double      data;                           // 相関値≒一致率

基本的にエッセイ『欅坂46から櫻坂46に改名した事を
画像処理的に考察例文ソースコード説明』の
「2.execute( pimgA, pimgB );実際の処理部」の
「(3)ローカル変数」に追加した物です、ここの説明は、
追加・変更した所をだけ行います!
「TypeXY bufXY[2000];」は、XY座標格納用ですが、
配列のサイズ「[2000]」と元のサイズ「[1000]」の倍に増や
しています!
「double buf[2000];」は、相関値結果格納用ですが、
配列のサイズ「[2000]」と元のサイズ「[1000]」の倍に増や
しています!
「int cnt1;」は、詳細計測用の計数カウンタです!

(2)アルゴリズム

    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   = 5;                                // テンプレートマッチングする座標移動量を
    stepY   = 5;                                // 5画素単位≪備考:間引く事で処理時間減少!
                                                // 説明用なので5に設定:高速化処理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 ); // 算出し
            if( abs(data) > 0.1){               // 条件「絶対値(相関値)が0.1超え」
                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 );          // 座標結果も連動してソーティング
    printf( "予備的サーチ個数=%d\n", cnt );	// 予備的サーチ結果数値表示
    for( int i=0; i < cnt; i++ ){               // ソーティングした結果バッファーをインデックスで
        printf( "data=%e,(%d,%d)\n",            // 例文なのでソーティング結果(一致率、座標)
            buf[i], bufXY[i].x, bufXY[i].y );   // 表示
    }                                           // ループ
    cnt1 = cnt;                                 // 詳細個数カウント初期化
    for( int i=0; i < cnt; i++ ){               // ソーティングした結果バッファーをインデックスで
        int x1 = bufXY[i].x - stepX;            // forループ内ローカル変数:X座標始点
        int y1 = bufXY[i].y - stepY;            // forループ内ローカル変数:Y座標始点
        int x2 = x1 + stepX * 2;                // forループ内ローカル変数:X座標終点
        int y2 + stepY * 2;                     // forループ内ローカル変数:Y座標終点
        int xy;                                 // forループ内ローカル変数:座標作業用
        x1 = (x1 < 0) ? 0: x1;                  // 始点が0未満なら0に補正
        y1 = (y1 < 0) ? 0: y1;                  // 始点が0未満なら0に補正
        xy = h - n - 1;                         // サーチ画像右端X座標算出
        x2 = (x2 > xy) ? xy: x2;                // 終点が右端を超えたら右端に補正
        xy = v - m - 1;                         // サーチ画像下端Y座標算出
        y2 = (x2 > xy) ? yy: y2;                // 終点が下端を超えたら下端に補正
        for( int yy=y1; yy <= y2; yy++ ){       // 詳細Y座標方向サーチループ
            for( int xx=x1; xx <= x2; xx++ ){   // 詳細X座標方向サーチループ
                BYTE* ptrBXY =                  // B画像:詳細処理ポインタ
                    pimgB->getPtrByte(xx, yy);  // 
                data = FUN.CorrNM( ptrA,		// n×m画素の正規相関を
                    ptrBXY, incA, incB, n, m ); // 算出し
                if( abs(data) > 0.1){           // 条件「絶対値(相関値)が0.1超え」
                    if( cnt1 < 2000 ){          // 再条件「格納数が2000未満」の場合で
                        cnt1++;                 // 格納数をカウントアップ
                        *pbuf++ = data;         // バッファーに格納
                        pXY->x  = x;            // X座標格納
                        pXY->y  = y;            // Y座標格納
                        pXY++;                  // 座標結果格納バッファー実行ポインタ増加
                    }                           //
                }                               //
            }                                   // 
        }                                       // 
    }                                           // 詳細サーチループ終端
    printf( "詳細サーチ個数=%d\n", cnt1-cnt ); // 詳細サーチ結果数値表示
    for( int i = cnt; i < cnt1; i++ ){          //
        printf( "data=%e,(%d,%d)\n",            // 例文なのでソーティング結果(一致率、座標)
            buf[i], bufXY[i].x, bufXY[i].y );   // 表示
    }                                           // ループ終端
}

基本的にエッセイ『欅坂46から櫻坂46に改名した事を
画像処理的に考察例文ソースコード説明』

「2.execute( pimgA, pimgB );実際の処理部」の
「(4)アルゴリズム」に追加した物です、ここの説明は、
追加・変更した所をだけ行います!
「stepX=5;stepY=5;」は、テンプレートマッチングする座標
移動量ですが、元は、「stepX=1;stepY=1;」と1画素単位で
移動していたが、今回は、高速化と言う事で5画素単位で
移動する事が、異なります!そして5画素単位でサーチ処理
を【予備的サーチ】と言う事にして、一致率が高かった周辺
を改めて詳細にサーチする事でサーチ時間の高速化と言う事
です!※備考:念押し説明としてオリジナルが1画素単位で
の移動で今回の予備的サーチが、5画素単位での移動と言う
事は、サーチ基本部「CorrNM()」関数の処理回数が5×5=25分の1に激減した事を理解して下さい!この関数の
処理時間が一番重い処理です!
目印とし「FUN.SortCopy(bufXY,bufix,cnt);」の後に
「printf("予備的サーチ個数=%d\n",cnt);」と例文なので
デバッグ用に中間結果表示の表題「予備的サーチ個数=」と
既に相関値の一致率で降順≪大⇒小に整理≫した相関値と
その相関値のXY座標値を表示する個数を表示し、降順に
ソートした相関値とその相関値のXY座標値を表示する
「for(inti=0;i<cnt;i++){printf("data=%e,(%d,%d)\n",
buf[i],bufXY[i].x,bufXY[i].y);}」でデバッグ用に表示
そしてコノ予備的サーチでの相関値とその相関値のXY座標
値を表示した後こそ、今回追加した詳細計測用の部分です!
「cnt1=cnt;」は、詳細計測用の個数を予備的サーチ個数で
初期化!
「for(int i=0;i<cnt;i++){・・詳細サーチループ・・}」は
forループ構文「int i=0;i<cnt;i++」で所謂、教科書的
な解り易いループローカル変数「int i=0;」で初期値「0」
から始めループ条件「i<cnt;」で予備的サーチ個数分繰り返
し「i++」と増分で・・詳細サーチループ・・を繰り返し、
その・・詳細サーチループ・・で
「int x1=bufXY[i].x-stepX;」は、ループローカル変数の
「int x1」を用意して初期値として「bufXY[i].x-stepX;」
と予備的サーチでのX座標結果「bufXY[i].x」と添字「i」
のX座標結果を詳細サーチX座標始点とし算出しセット
※備考:「-stepX」とマイナス方向にして居るのは予備的
サーチで相関値が高かった場所が予備的に候補とし結果保存
して居るのでソノ一つ前の座標から細かく詳細サーチを行う
との理由です!
「int y1=bufXY[i].y-stepY;」は、上記と同じく、ループ
ローカル変数の「int y1」を用意して初期値として
「bufXY[i].y-stepY;」とY座標始点をセット
「int x2=x1+stepX2;」は、上記と同じく、ループローカル
変数の「int x2」を用意して初期値としてX座標終点を
「x1+stepX2;」と算出し※備考:「stepX2」は、始点が、
「-stepX;」と一旦、「stepX」減じて居るので「2」で終点
を算出したと考えて下さい!
「int y2+stepY2;」は、上記と同じく、ループローカル
変数の「int y2」を用意して初期値としてY座標終点を
「y1+stepY2;」と算出し初期値としセット
「int xy;」は、ループローカル変数の「int xy」を用意し
この変数は作業用でしす!
※備考:この様にforループの中でローカル変数を用意す
ると実用として多くのコンパイラは高速CPUレジスタ優先
順位を高く割り付ける事が多いので速度向上します!
「x1=(x1<0)?0:x1;y1=(y1<0)?0:y1;」は、XY座標始点が
0未満に成る事を阻止し「0」に補正!
「xy=h-n-1;x2=(x2>xy)?xy:x2;」は、サーチ画像のX座標
上限を「xy=h-n-1;」と算出し、「x2=(x2>xy)?xy:x2;」で
上限内に納める様に補正です!
「xy=v-m-1;y2=(x2>xy)?yy:y2;」は、サーチ画像のY座標
上限を「xy=v-m-1;」と算出し、「y2=(x2>xy)?yy:y2;」で
上限内に納める様に補正です!
備考:これでXY座標範囲「x1..x2、y1..y2」をセット
「for(int yy=y1;yy<=y2;yy++){・・Y座標方向処理・・}」
は、詳細サーチでのY座標方向処理としてforループ構文
「int yy=y1;yy<=y2;yy++」でループローカル変数「yy」を
用意して「yy=y1;」とY座標方向始点から始めループ条件
「yy<=y2;」と終点まで繰り返し増分「yy++」で1画素づつ
増加し、・・Y座標方向処理・・を繰り返し、その
・・Y座標方向処理・・では、
「for(int xx=x1;xx<=x2;xx++){・・X座標方向処理・・}」
は、詳細サーチでのX座標方向処理としてforループ構文
「int xx=x1;xx<=x2;xx++」でループローカル変数「xx」を
用意して「xx=x1;」とX座標方向始点から始めループ条件
「xx<=x2;」と終点まで繰り返し増分「xx++」で1画素づつ
増加し、・・X座標方向処理・・を繰り返し、その
・・X座標方向処理・・では、
「BYTE* ptrBXY=pimgB->getPtrByte(xx,yy);」は、ループ
ローカル変数「BYTE* ptrBXY」を詳細サーチ用画素処理
ポインタとし用意して
初期値「pimgB->getPtrByte(xx,yy);」と座標の位置のポイ
ンタをセット
「data=FUN.CorrNM(ptrA,ptrBXY,incA,incB,n,m);」は、
詳細サーチを関数「FUN.CorrNM()」で算出し
「if(abs(data)>0.1){・・詳細サーチ格納・・}」は、
if構文条件「abs(data)>0.1」で相関値が絶対値で「0.1」
を超えたならば、・・詳細サーチ格納・・で格納する、
その・・詳細サーチ格納・・で
「if(cnt1<2000){cnt1++;*pbuf++=data;pXY->x=x;pXY->y=y;
pXY++;}」は、結果格納バッファーのサイズ「2000」なので
超えた場合は、格納を止める条件です!
備考:例文作者としては、十分に大きなサイズを用意した
心算ですが、OSが許す限り大きな物を用意して結構です!
画像を今回使用した「欅・櫻」で無く、色々、行う場合は、
余裕を持ってサイズとか、相関値が絶対値で「0.1」を超え
た場合と言う条件は、色々、考えて設定して下さい!
次は、デバッグ用に用意して計測結果表示です!
「printf("詳細サーチ個数=%d\n",cnt1-cnt);」は、
タイトル表示&詳細サーチ個数表示です!そして個別の
詳細サーチデータ表示を
「for(int i=cnt;i<cnt1;i++){printf(
"data=%e,(%d,%d)\n",buf[i],bufXY[i].x,bufXY[i].y);}」
でforループ構文「int i=cnt;i<cnt1;i++」でバッファー
に格納したインデックス位置が「cnt」から始まり「cnt1」
で終わりなのでこのループを使用しC言語標準の
「printf()」関数で標準します!

2.備考

今回の「欅坂46から櫻坂46に改名した事を画像処理的に
考察」シリーズは、ココで終わります!
小間切れにトピックスとして読者様に興味を抱かせる「欅・
櫻」を使用する等、姑息な細かいエッセイとして発表したの
は、個人的な都合≪note毎日連続投稿(記事)記録が、
365日でバッジが得られるとの事で無理な投稿の一部に
していた為≫で、本来は、
解説『解説クラスCopyClear(○○)』で正規に
授業とし、ここの正規化相関の関数を解説する予定で既に
毎日連続投稿チャレンジは終了なので毎週連続投稿記録に
チャレンジする為に本格的な分量の有る
解説『解説クラスCopyClear(○○)』を発表す
る予定です!解説『受講順番の手引き』に従って受講する
事をお願い致します!!

文末

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