Main Content

アプリケーションにおける C の main の例の使用

この例では、イメージのエッジ検出を行う単純なソーベル フィルターを実装する MATLAB® コードから C 実行可能ファイルをビルドする方法を示します。実行可能ファイルはディスクからイメージを読み取り、ソーベル フィルター アルゴリズムを適用して、変更されたイメージを保存します。

この例では、実行可能ファイルをビルドする際に使用する main 関数の例を生成して変更する方法を示します。

必要条件

この例を実行するには、次の製品をインストールします。

  • MATLAB

  • MATLAB Coder™

  • C コンパイラ (ほとんどのプラットフォーム用に、既定の C コンパイラが MATLAB に付属しています)。サポートされているコンパイラのリストは、サポートされるコンパイラを参照してください。

    mex -setup を使用して既定のコンパイラを変更できます。既定のコンパイラの変更を参照してください。

チュートリアル ファイル: ソーベル フィルター

この例を開いて、このチュートリアルのファイル sobel.mhello.jpg を取得します。

チュートリアル ファイルの説明

この例では次のファイルを使用します。

ファイル名ファイルの種類説明
sobel.m関数のコードMATLAB によるソーベル フィルター アルゴリズムの実装。sobel.m はイメージ (double 行列) およびしきい値を入力として取得します。アルゴリズムはイメージのエッジを (しきい値に基づいて) 検出します。sobel.m はエッジを表示する変更されたイメージを返します。
hello.jpgイメージ ファイルソーベル フィルターによって変更されるイメージ。

 ファイル sobel.m の内容

 hello.jpg の内容

イメージに対するソーベル フィルターの実行

  1. 元のイメージを MATLAB 行列に読み取り、表示します。

    im = imread('hello.jpg');
  2. ソーベル フィルターの結果との比較対象としてイメージを表示します。

    image(im);

    Color photograph of the sentence "Hello!", which is hand-written in large letters on a notepad

  3. ソーベル フィルター アルゴリズムはグレースケール イメージで動作します。正規化された値 (0.0 が黒、1.0 が白) を使ってカラー イメージを等価のグレースケール イメージに変換します。

    gray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;
  4. ソーベル フィルターに対して MATLAB 関数を実行するには、グレースケール イメージ行列 gray としきい値を関数 sobel に渡します。この例では 0.7 をしきい値に使用します。

    edgeIm = sobel(gray, 0.7);
  5. 変更したイメージを表示するには、行列 edgeIm の形式を関数 repmat で変更し、image コマンドに渡せるようにします。

    im3 = repmat(edgeIm, [1 1 3]);
    image(im3);

    Greyscale rendering of the color photograph after Sobel filtering. The notepad, the letters in the word "Hello," and the exclamation point are outlined in white on a black background.

MEX 関数の生成とテスト

  1. 生成されたコードが元の MATLAB コードと機能的に等価であり、ランタイム エラーが発生しないことをテストするには、MEX 関数を生成します。

    codegen -report sobel

    codegen は現在の作業フォルダーに sobel_mex という名前の MEX 関数を生成します。

  2. ソーベル フィルターに対して MEX 関数を実行するには、グレースケール イメージ行列 gray としきい値を関数 sobel_mex に渡します。この例では 0.7 をしきい値に使用します。

    edgeImMex = sobel_mex(gray, 0.7);
  3. 変更したイメージを表示するには、行列 edgeImMex の形式を関数 repmat で変更し、image コマンドに渡せるようにします。

    im3Mex = repmat(edgeImMex, [1 1 3]);
    image(im3Mex);

    このイメージは MATLAB 関数を使用して作成されたイメージと同じです。

sobel.m 用の main 関数の例の生成

アプリケーション用にカスタム main 関数を作成することはできますが、main 関数の例は生成されたコードを組み込む際に役立つテンプレートを提供します。

ソーベル フィルター用に main 関数の例を生成するには、次の手順に従います。

  1. C スタティック ライブラリ用に構成オブジェクトを作成します。

    cfg = coder.config('lib');

    C/C++ ソース コード、スタティック ライブラリ、ダイナミック ライブラリおよび実行可能ファイルの構成オブジェクトに対して、設定 GenerateExampleMain は main 関数の例の生成を制御します。この設定は main 関数の例を生成してもコンパイルはしない 'GenerateCodeOnly' に、既定で設定されます。この例では、GenerateExampleMain 設定の値は変更しないでください。

  2. 構成オブジェクトを使用して C スタティック ライブラリを生成します。

    codegen -report -config cfg sobel

スタティック ライブラリに生成されたファイルはフォルダー codegen/lib/sobel に格納されています。メイン ファイルの例は、サブフォルダー codegen/lib/sobel/examples に格納されています。

 ファイル main.c の例の内容

メイン ファイルの例のコピー

ファイル main.cmain.hexamples サブフォルダーで変更しないでください。変更すると、コードの再生成時に MATLAB Coder でメイン ファイルの例が再生成されません。生成されたファイルに対する変更が検出されたことを警告します。

ファイル main.cmain.h をフォルダー codegen/lib/sobel/examples から別の場所へコピーします。この例では、ファイルを現在の作業フォルダーへコピーします。新しい場所でファイルを変更します。

生成された main 関数の例の変更

main 関数の例は動的に割り当てられたデータなどのデータを宣言して、ゼロ値に初期化します。これは、ゼロ値に設定された引数でエントリポイント関数を呼び出しますが、エントリポイント関数から返される値は使用しません。

C の main 関数はアプリケーションの要件を満たしていなければなりません。この例では、ソーベル フィルター アプリケーションの要件を満たすように main 関数の例を変更しています。

この例では、ソーベル フィルター アプリケーションが次を実行するように、ファイル main.c を変更しています。

  • バイナリ ファイルからグレースケール イメージを読み込む。

  • ソーベル フィルター アルゴリズムを適用する。

  • 変更されたイメージをバイナリ ファイルに保存する。

main 関数の変更

次を実行するように main 関数を変更します。

  • グレースケール イメージ データとしきい値を含むファイルを入力引数として受け入れます。

  • グレースケール イメージ データ ストリームのアドレスとしきい値を入力引数として指定して関数 main_sobel を呼び出します。

main 関数で次を実行します。

  1. 宣言 (void)argc(void)argv を削除します。

  2. 変数 filename を宣言し、グレースケール イメージ データを含むバイナリ ファイルの名前を保持します。

    const char *filename;
  3. 変数 threshold を宣言し、しきい値を保持します。

    double threshold;
  4. 変数 fd を宣言し、アプリケーションが filename から読み取るグレースケール イメージ データのアドレスを保持します。

    FILE *fd;
  5. 3 つの引数をチェックする if ステートメントを追加します。

    if (argc != 3) {
          printf("Expected 2 arguments: filename and threshold\n");
          exit(-1);
    }
  6. グレースケール イメージ データを含むファイルの入力引数 argv[1]filename に代入します。

    filename = argv[1];
  7. しきい値の入力引数 argv[2]threshold に代入し、入力を文字列から double の数値に変換します。

    threshold = atof(argv[2]);
  8. 名前が filename に指定されているグレースケール イメージ データを含んだファイルを開きます。データ ストリームのアドレスを fd に代入します。

    fd = fopen(filename, "rb");
  9. 実行可能ファイルが filename を開くことを検証するには、fd の値が NULL の場合にプログラムを終了する if ステートメントを記述します。

    if (fd == NULL) {
       exit(-1);
    }
  10. 入力引数 fdthreshold を指定して main_sobel を呼び出し、main_sobel の関数呼び出しを置き換えます。

    main_sobel(fd, threshold);
  11. sobel_terminate を呼び出した後、グレースケール イメージ ファイルを閉じます。

    fclose(fd);

 変更した main 関数

初期化関数 argInit_d1024xd1024_real_T の変更

メイン ファイルの例で、関数 argInit_d1024xd1024_real_T はソーベル フィルターに渡すイメージに対して動的に割り当てられた可変サイズの配列 (emxArray) を作成します。この関数は emxArray を既定サイズに初期化し、emxArray の要素を 0 にします。これは初期化された emxArray を返します。

ソーベル フィルター アプリケーションの場合、バイナリ ファイルからグレースケール イメージ データを emxArray に読み取るように関数を変更します。

関数 argInit_d1024xd1024_real_T で次を実行します。

  1. 入力引数 void を引数 FILE *fd と置き換えます。この変数は関数が読み取るグレースケール イメージ データを指します。

    static emxArray_real_T *argInit_d1024xd1024_real_T(FILE *fd)
  2. グレースケール イメージ行列 gray の次元と一致するように変数 idx0 および idx1 の値を変更します。これらの変数は argInit_d1024xd1024_real_T で作成される emxArray の次元のサイズ値を保持します。

    int idx0 = 484;
    int idx1 = 648;

    MATLAB は列優先の形式でデータを格納し、C は行優先の形式で行列データを格納します。次元を適宜宣言します。

  3. 関数 emxCreate_real_T の値をイメージ サイズに変更します。

    result = emxCreate_real_T(484, 648);
  4. グレースケール イメージ データから読み取る値を保持する変数 element を定義します。

    double element;
  5. for ループの構成を変更し、fread コマンドを内部 for ループに追加してデータ点を正規化イメージから element に読み取ります。

    fread(&element, 1, sizeof(element), fd);
  6. for ループ内部で element を emxArray データの値セットとして代入します。

    result->data[idx0 + result->size[0] * idx1] = element;

 変更された初期化関数 argInit_d1024xd1024_real_T

関数 saveImage の作成

MATLAB 関数 sobel.m は MATLAB 配列とインターフェイスを取りますが、ソーベル フィルター アプリケーションはバイナリ ファイルとインターフェイスを取ります。

ソーベル フィルター アルゴリズムで変更されたイメージをバイナリ ファイルに保存するには、関数 saveImage を作成します。関数 saveImage は emxArray のデータをバイナリ ファイルに書き込みます。これは関数 argInit_d1024xd1024_real_T で使用する構成と同様の構成を使用します。

main.c ファイルで次のことを行います。

  1. emxArray edgeImage のアドレスを入力として受け取り、出力タイプ void をもつ関数 saveImage を定義します。

    static void saveImage(emxArray_uint8_T *edgeImage)
    {
    }
  2. 変数 idx0 と変数 idx1 を関数 argInit_d1024xd1024_real_T で定義する場合と同じように定義します。

    int idx;
    int idx1;
  3. emxArray から読み取るデータを格納するように変数 element を定義します。

    uint8_T element;
  4. 変更されたイメージの書き込み用にバイナリ ファイル edge.bin を開きます。edge.bin のアドレスを FILE *fd に代入します。

    FILE *fd = fopen("edge.bin", "wb");
  5. 実行可能ファイルが edge.bin を開くことを検証するには、fd の値が NULL の場合にプログラムを終了する if ステートメントを記述します。

    if (fd == NULL) {
       exit(-1);
    }
  6. 入れ子にされた for ループの構成を関数 argInit_d1024xd1024_real_T の構成と同じように書き込みます。

    for (idx0 = 0; idx0 < edgeImage->size[0U]; idx0++)
    {
        for (idx1 = 0; idx1 < edgeImage->size[1U]; idx1++)
        {
        }
    }
  7. 内部 for ループで、変更されたイメージ データの値を element に代入します。

    element = edgeImage->data[idx0 + edgeImage->size[0] * idx1];
  8. element の代入後、element の値をファイル edge.bin に書き込みます。

    fwrite(&element, 1, sizeof(element), fd);
  9. for ループの構成後、fd を閉じます。

    fclose(fd);

 関数 saveImage

関数 main_sobel の変更

この main 関数の例では、関数 main_sobel はグレースケールのデータと変更されたイメージに emxArrays を作成します。これは、グレースケール イメージの emxArray を初期化する関数 argInit_d1024xd1024_real_T を呼び出します。main_sobel は、emxArrays と、初期化関数 argInit_real_T が関数 sobel に返すしきい値 0 の両方を渡します。関数 main_sobel が終了すると、関数 sobel の結果を破棄します。

ソーベル フィルター アプリケーションの場合、関数 main_sobel を次に変更します。

  • グレースケール イメージ データのアドレスとしきい値を入力として受け取ります。

  • argInit_d1024xd1024_real_T を使用してアドレスからデータを読み取ります。

  • しきい値 threshold でデータをソーベル フィルター アルゴリズムに渡します。

  • saveImage を使用して結果を保存します。

関数 main_sobel で次を実行します。

  1. 引数 FILE *fddouble threshold をもつ関数と入力引数を置き換えます。

    static void main_sobel(FILE *fd, double threshold)
  2. 入力引数 fdargInit_d1024xd1024_real_T の関数呼び出しに渡します。

    originalImage = argInit_d1024xd1024_real_T(fd);
  3. 関数呼び出し内のしきい値の入力を threshold をもつ sobel に置き換えます。

    sobel(originalImage, threshold, edgeImage);
  4. 関数 sobel を呼び出した後、入力 edgeImage をもつ関数 saveImage を呼び出します。

    saveImage(edgeImage);

 変更された関数 main_sobel

関数宣言の変更

関数宣言に加えた変更と一致させるには、関数宣言に次の変更を加えます。

  1. 関数 *argInit_d1024xd1024_real_T の入力を FILE *fd に変更します。

    static emxArray_real_T *argInit_d1024xd1024_real_T(FILE *fd);
  2. 関数 main_sobel の入力を FILE *fddouble threshold に変更します。

    static void main_sobel(FILE *fd, double threshold);
  3. 関数 saveImage を追加します。

    static void saveImage(emxArray_uint8_T *edgeImage);

 変更された関数宣言

インクルード ファイルの変更

main.c で使用する入出力関数の場合、ヘッダー ファイル stdio.h をインクルード ファイル リストに追加します。

#include <stdio.h>

 変更されたインクルード ファイル

変更されたファイル main.c の内容

 main.c

ソーベル フィルター アプリケーションの生成

  1. 作業フォルダーに移動します (現在作業フォルダー以外にいる場合)。

  2. C スタンドアロンの実行可能ファイルに構成オブジェクトを作成します。

    cfg = coder.config('exe');
  3. 構成オブジェクトと変更された main 関数を使用して、ソーベル フィルターに C スタンドアロンの実行可能ファイルを生成します。

    codegen -report -config cfg sobel main.c main.h

既定では、MATLAB を Windows® プラットフォームで実行している場合、実行可能ファイル sobel.exe は現在の作業フォルダーに生成されます。MATLAB を Windows 以外のプラットフォームで実行している場合、ファイルの拡張子はそのプラットフォームに対応する拡張子になります。既定の設定では、実行可能ファイルの生成されたコードはフォルダー codegen/exe/sobel にあります。

ソーベル フィルター アプリケーションの実行

  1. MATLAB 行列 gray が現在 MATLAB ワークスペースにない場合は、作成します。

    im = imread('hello.jpg');
    gray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;
  2. 行列 grayfopenfwrite コマンドを使用してバイナリ ファイルに書き込みます。アプリケーションはこのバイナリ ファイルを読み取ります。

    fid = fopen('gray.bin', 'w');
    fwrite(fid, gray, 'double');
    fclose(fid);
  3. 実行可能ファイルを実行して、ファイル gray.bin およびしきい値 0.7 を渡します。

    この例を Windows プラットフォームの MATLAB で実行するには、次を行います。

    system('sobel.exe gray.bin 0.7');

    実行可能ファイルはファイル edge.bin を生成します。

結果として得たイメージの表示

  1. fopenfread コマンドを使用して、ファイル edge.bin を MATLAB 行列 edgeImExe に読み取ります。

    fd = fopen('edge.bin', 'r');
    edgeImExe = fread(fd, size(gray), 'uint8');
    fclose(fd);
  2. 行列 edgeImExe を関数 repmat に渡し、イメージを表示します。

    im3Exe = repmat(edgeImExe, [1 1 3]);
    image(im3Exe);

    イメージは MATLAB と MEX 関数のイメージと一致します。

関連するトピック