В этом примере показано, как сгенерировать автономную библиотеку C из кода MATLAB®, который реализует простой фильтр Sobel, который выполняет обнаружение ребра на изображениях. Пример также показывает, как сгенерировать и протестировать MEX-функцию в MATLAB до генерации кода С, чтобы проверить, что код MATLAB подходит для генерации кода.
sobel Функцияsobel.m функционируйте берет изображение (представленный как двойная матрица) и пороговое значение и возвращает изображение с обнаруженными ребрами (на основе порогового значения).
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 команда.
codegen sobelCode generation successful.
Прежде, чем сгенерировать код С, необходимо сначала протестировать MEX-функцию в MATLAB, чтобы гарантировать, что это функционально эквивалентно оригинальному коду MATLAB и что никакие ошибки времени выполнения не происходят. По умолчанию, codegen генерирует MEX-функцию под названием sobel_mex в текущей папке. Это позволяет вам тестировать код MATLAB и MEX-функцию и сравнивать результаты.
Используйте стандартный imread команда.
im = imread('hello.jpg');
image(im);
Преобразуйте цветное изображение (показанный выше) к эквивалентному полутоновому изображению с нормированными значениями (0.0 для черного цвета, 1.0 для белого).
gray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;
Передайте нормированное изображение и пороговое значение.
edgeIm = sobel_mex(gray, 0.7);
im3 = repmat(edgeIm, [1 1 3]); image(im3);

codegen -config coder.config('lib') sobel
Code generation successful.
Используя codegen с -config coder.config('lib') опция производит автономную библиотеку C. По умолчанию код, сгенерированный для библиотеки, находится в папке codegen/lib/sobel/.
type codegen/lib/sobel/sobel.c/*
* File: sobel.c
*
* MATLAB Coder version : 5.3
* C/C++ source code generated on : 25-Aug-2021 05:29:29
*/
/* 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 *H, const emxArray_real_T *V);
/* Function Definitions */
/*
* Arguments : emxArray_real_T *H
* const emxArray_real_T *V
* Return Type : void
*/
static void binary_expand_op(emxArray_real_T *H, const emxArray_real_T *V)
{
emxArray_real_T *b_H;
const double *V_data;
double H_tmp;
double *H_data;
double *b_H_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;
V_data = V->data;
H_data = H->data;
emxInit_real_T(&b_H, 2);
i = b_H->size[0] * b_H->size[1];
if (V->size[0] == 1) {
b_H->size[0] = H->size[0];
} else {
b_H->size[0] = V->size[0];
}
if (V->size[1] == 1) {
b_H->size[1] = H->size[1];
} else {
b_H->size[1] = V->size[1];
}
emxEnsureCapacity_real_T(b_H, i);
b_H_data = b_H->data;
stride_0_0 = (H->size[0] != 1);
stride_0_1 = (H->size[1] != 1);
stride_1_0 = (V->size[0] != 1);
stride_1_1 = (V->size[1] != 1);
aux_0_1 = 0;
aux_1_1 = 0;
if (V->size[1] == 1) {
loop_ub = H->size[1];
} else {
loop_ub = V->size[1];
}
for (i = 0; i < loop_ub; i++) {
if (V->size[0] == 1) {
b_loop_ub = H->size[0];
} else {
b_loop_ub = V->size[0];
}
for (i1 = 0; i1 < b_loop_ub; i1++) {
H_tmp = V_data[i1 * stride_1_0 + V->size[0] * aux_1_1];
b_H_data[i1 + b_H->size[0] * i] =
H_data[i1 * stride_0_0 + H->size[0] * aux_0_1] *
H_data[i1 * stride_0_0 + H->size[0] * aux_0_1] +
H_tmp * H_tmp;
}
aux_1_1 += stride_1_1;
aux_0_1 += stride_0_1;
}
i = H->size[0] * H->size[1];
H->size[0] = b_H->size[0];
H->size[1] = b_H->size[1];
emxEnsureCapacity_real_T(H, i);
H_data = H->data;
loop_ub = b_H->size[1];
for (i = 0; i < loop_ub; i++) {
b_loop_ub = b_H->size[0];
for (i1 = 0; i1 < b_loop_ub; i1++) {
H_data[i1 + H->size[0] * i] = b_H_data[i1 + b_H->size[0] * i];
}
}
emxFree_real_T(&b_H);
}
/*
* 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 nx;
unsigned char *edgeImage_data;
if (!isInitialized_sobel) {
sobel_initialize();
}
emxInit_real_T(&H, 2);
emxInit_real_T(&V, 2);
/* 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. */
conv2AXPYSameCMP(originalImage, H);
H_data = H->data;
b_conv2AXPYSameCMP(originalImage, V);
V_data = V->data;
if ((H->size[0] == V->size[0]) && (H->size[1] == V->size[1])) {
nx = H->size[0] * H->size[1];
for (k = 0; k < nx; 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);
nx = H->size[0] * H->size[1];
for (k = 0; k < nx; 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;
nx = H->size[0] * H->size[1];
for (k = 0; k < nx; k++) {
edgeImage_data[k] = (unsigned char)((H_data[k] > threshold) * 255U);
}
emxFree_real_T(&H);
}
/*
* File trailer for sobel.c
*
* [EOF]
*/