Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

イメージのエッジを検出するコードの生成

この例では、イメージのエッジ検出を行う単純なソーベル フィルターを実装する MATLAB® コードからスタンドアロン C ライブラリを生成する方法を示します。また、MATLAB コードがコードの生成に適していることを確認するために、C コードの生成前に MEX 関数を生成してテストする方法も示します。

関数 sobel について

関数 sobel.m は、イメージ (double 行列) およびしきい値を取得し、イメージと (しきい値に基づいて) 検出されたエッジを返します。

type sobel
% edgeImage = sobel(originalImage, threshold)
% Sobel edge detection. Given a normalized image (with double values)
% return an image where the edges are detected w.r.t. threshold value.
function edgeImage = sobel(originalImage, threshold) %#codegen
assert(all(size(originalImage) <= [1024 1024]));
assert(isa(originalImage, 'double'));
assert(isa(threshold, 'double'));

k = [1 2 1; 0 0 0; -1 -2 -1];
H = conv2(double(originalImage),k, 'same');
V = conv2(double(originalImage),k','same');
E = sqrt(H.*H + V.*V);
edgeImage = uint8((E > threshold) * 255);

MEX 関数の生成

codegen コマンドを使用して MEX 関数を生成します。

codegen sobel
Code generation successful.

C コードを生成する前に、MATLAB で MEX 関数をテストして、その関数が元の MATLAB コードと機能的に等価であることと実行時のエラーが発生しないことを確認しなければなりません。既定で、codegen は、現在のフォルダーに sobel_mex という名前の MEX 関数を生成します。これにより、MATLAB コードと MEX 関数をテストして結果を比較することができます。

元のイメージの読み取り

標準の imread コマンドを使用します。

im = imread('hello.jpg');
image(im);

Figure contains an axes object. The axes object contains an object of type image.

グレースケール バージョンへの変換

正規化された値 (0.0 が黒、1.0 が白) を使って上記のカラー イメージを等価のグレースケール イメージに変換します。

gray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;

MEX 関数の実行 (ソーベル フィルター)

正規化されたイメージとしきい値を渡します。

edgeIm = sobel_mex(gray, 0.7);

結果の表示

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

Figure contains an axes object. The axes object contains an object of type image.

スタンドアロン C コードの生成

codegen -config coder.config('lib') sobel
Code generation successful.

-config coder.config('lib') オプションを指定して codegen を使用すると、スタンドアロン C ライブラリが生成されます。既定では、ライブラリ用に生成されたコードは codegen/lib/sobel/ フォルダーにあります。

生成された関数の確認

type codegen/lib/sobel/sobel.c
/*
 * Prerelease License - for engineering feedback and testing purposes
 * only. Not for sale.
 * File: sobel.c
 *
 * MATLAB Coder version            : 23.2
 * C/C++ source code generated on  : 27-Jul-2023 14:58:09
 */

/* Include Files */
#include "sobel.h"
#include "conv2AXPYSameCMP.h"
#include "sobel_data.h"
#include "sobel_emxutil.h"
#include "sobel_initialize.h"
#include "sobel_types.h"
#include <math.h>

/* Function Declarations */
static void binary_expand_op(emxArray_real_T *in1, const emxArray_real_T *in2);

/* Function Definitions */
/*
 * Arguments    : emxArray_real_T *in1
 *                const emxArray_real_T *in2
 * Return Type  : void
 */
static void binary_expand_op(emxArray_real_T *in1, const emxArray_real_T *in2)
{
  emxArray_real_T *b_in1;
  const double *in2_data;
  double *b_in1_data;
  double *in1_data;
  int aux_0_1;
  int aux_1_1;
  int b_loop_ub;
  int i;
  int i1;
  int loop_ub;
  int stride_0_0;
  int stride_0_1;
  int stride_1_0;
  int stride_1_1;
  in2_data = in2->data;
  in1_data = in1->data;
  emxInit_real_T(&b_in1, 2);
  if (in2->size[0] == 1) {
    loop_ub = in1->size[0];
  } else {
    loop_ub = in2->size[0];
  }
  i = b_in1->size[0] * b_in1->size[1];
  b_in1->size[0] = loop_ub;
  if (in2->size[1] == 1) {
    b_loop_ub = in1->size[1];
  } else {
    b_loop_ub = in2->size[1];
  }
  b_in1->size[1] = b_loop_ub;
  emxEnsureCapacity_real_T(b_in1, i);
  b_in1_data = b_in1->data;
  stride_0_0 = (in1->size[0] != 1);
  stride_0_1 = (in1->size[1] != 1);
  stride_1_0 = (in2->size[0] != 1);
  stride_1_1 = (in2->size[1] != 1);
  aux_0_1 = 0;
  aux_1_1 = 0;
  for (i = 0; i < b_loop_ub; i++) {
    for (i1 = 0; i1 < loop_ub; i1++) {
      double b_in1_tmp;
      double in1_tmp;
      in1_tmp = in1_data[i1 * stride_0_0 + in1->size[0] * aux_0_1];
      b_in1_tmp = in2_data[i1 * stride_1_0 + in2->size[0] * aux_1_1];
      b_in1_data[i1 + b_in1->size[0] * i] =
          in1_tmp * in1_tmp + b_in1_tmp * b_in1_tmp;
    }
    aux_1_1 += stride_1_1;
    aux_0_1 += stride_0_1;
  }
  i = in1->size[0] * in1->size[1];
  in1->size[0] = b_in1->size[0];
  in1->size[1] = b_in1->size[1];
  emxEnsureCapacity_real_T(in1, i);
  in1_data = in1->data;
  loop_ub = b_in1->size[1];
  for (i = 0; i < loop_ub; i++) {
    b_loop_ub = b_in1->size[0];
    for (i1 = 0; i1 < b_loop_ub; i1++) {
      in1_data[i1 + in1->size[0] * i] = b_in1_data[i1 + b_in1->size[0] * i];
    }
  }
  emxFree_real_T(&b_in1);
}

/*
 * Arguments    : const emxArray_real_T *originalImage
 *                double threshold
 *                emxArray_uint8_T *edgeImage
 * Return Type  : void
 */
void sobel(const emxArray_real_T *originalImage, double threshold,
           emxArray_uint8_T *edgeImage)
{
  emxArray_real_T *H;
  emxArray_real_T *V;
  double *H_data;
  double *V_data;
  int k;
  int loop_ub;
  unsigned char *edgeImage_data;
  if (!isInitialized_sobel) {
    sobel_initialize();
  }
  /*  edgeImage = sobel(originalImage, threshold) */
  /*  Sobel edge detection. Given a normalized image (with double values) */
  /*  return an image where the edges are detected w.r.t. threshold value. */
  emxInit_real_T(&H, 2);
  conv2AXPYSameCMP(originalImage, H);
  H_data = H->data;
  emxInit_real_T(&V, 2);
  b_conv2AXPYSameCMP(originalImage, V);
  V_data = V->data;
  if ((H->size[0] == V->size[0]) && (H->size[1] == V->size[1])) {
    loop_ub = H->size[0] * H->size[1];
    for (k = 0; k < loop_ub; k++) {
      H_data[k] = H_data[k] * H_data[k] + V_data[k] * V_data[k];
    }
  } else {
    binary_expand_op(H, V);
    H_data = H->data;
  }
  emxFree_real_T(&V);
  loop_ub = H->size[0] * H->size[1];
  for (k = 0; k < loop_ub; k++) {
    H_data[k] = sqrt(H_data[k]);
  }
  k = edgeImage->size[0] * edgeImage->size[1];
  edgeImage->size[0] = H->size[0];
  edgeImage->size[1] = H->size[1];
  emxEnsureCapacity_uint8_T(edgeImage, k);
  edgeImage_data = edgeImage->data;
  for (k = 0; k < loop_ub; k++) {
    edgeImage_data[k] =
        (unsigned char)((unsigned int)(H_data[k] > threshold) * 255U);
  }
  emxFree_real_T(&H);
}

/*
 * File trailer for sobel.c
 *
 * [EOF]
 */