生成代码以检测图像边缘
此示例说明如何从 MATLAB® 代码生成独立 C 库,该库实现一个简单的索贝尔滤波器,该滤波器对图像执行边缘检测。示例还说明如何在生成 C 代码之前在 MATLAB 中生成和测试 MEX 函数,以验证该 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 命令生成 MEX 函数。
codegen sobelCode generation successful.
在生成 C 代码之前,应首先在 MATLAB 中测试 MEX 函数,以确保它在功能上等同于原始 MATLAB 代码,并且不会出现任何运行时错误。默认情况下,codegen 在当前文件夹中生成名为 sobel_mex 的 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;
运行 MEX 函数(索贝尔滤波器)
传递归一化图像和阈值。
edgeIm = sobel_mex(gray, 0.7);
显示结果
im3 = repmat(edgeIm, [1 1 3]); image(im3);

生成独立 C 代码。
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 : 25.2
* C/C++ source code generated on : 09-Aug-2025 10:02:00
*/
/* 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 "sqrt.h"
#include "omp.h"
#include <emmintrin.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];
}
stride_0_0 = 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, stride_0_0);
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;
}
stride_0_0 = in1->size[0] * in1->size[1];
in1->size[0] = loop_ub;
in1->size[1] = b_loop_ub;
emxEnsureCapacity_real_T(in1, stride_0_0);
in1_data = in1->data;
for (i = 0; i < b_loop_ub; i++) {
for (i1 = 0; i1 < 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 i;
int i1;
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])) {
int scalarLB;
int vectorUB;
loop_ub = H->size[0] * H->size[1];
scalarLB = (loop_ub / 2) << 1;
vectorUB = scalarLB - 2;
for (i = 0; i <= vectorUB; i += 2) {
__m128d r;
__m128d r1;
r = _mm_loadu_pd(&H_data[i]);
r1 = _mm_loadu_pd(&V_data[i]);
_mm_storeu_pd(&H_data[i],
_mm_add_pd(_mm_mul_pd(r, r), _mm_mul_pd(r1, r1)));
}
for (i = scalarLB; i < loop_ub; i++) {
H_data[i] = H_data[i] * H_data[i] + V_data[i] * V_data[i];
}
} else {
binary_expand_op(H, V);
}
emxFree_real_T(&V);
b_sqrt(H);
H_data = H->data;
loop_ub = edgeImage->size[0] * edgeImage->size[1];
edgeImage->size[0] = H->size[0];
edgeImage->size[1] = H->size[1];
emxEnsureCapacity_uint8_T(edgeImage, loop_ub);
edgeImage_data = edgeImage->data;
loop_ub = H->size[0] * H->size[1];
if (loop_ub < 400) {
for (i1 = 0; i1 < loop_ub; i1++) {
edgeImage_data[i1] =
(unsigned char)((unsigned int)(H_data[i1] > threshold) * 255U);
}
} else {
#pragma omp parallel for num_threads(omp_get_max_threads())
for (i1 = 0; i1 < loop_ub; i1++) {
edgeImage_data[i1] =
(unsigned char)((unsigned int)(H_data[i1] > threshold) * 255U);
}
}
emxFree_real_T(&H);
}
/*
* File trailer for sobel.c
*
* [EOF]
*/