This example shows how to build a C executable from MATLAB® code that implements a simple Sobel filter to perform edge detection on images. The executable reads an image from the disk, applies the Sobel filtering algorithm, and then saves the modified image.
The example shows how to generate and modify an example main function that you can use when you build the executable.
To complete this example, install the following products:
MATLAB
MATLAB Coder™
C compiler (for most platforms, a default C compiler is supplied with MATLAB). For a list of supported compilers, see Supported Compilers.
You can use mex -setup
to change the default
compiler. See Change Default Compiler.
The files you use in this example are:
File Name | File Type | Description |
---|---|---|
sobel.m | Function code | MATLAB implementation of a Sobel filtering algorithm. sobel.m takes
an image (represented as a double matrix) and a threshold value as
inputs. The algorithm detects edges in the image (based on the threshold
value). sobel.m returns a modified image displaying
the edges. |
hello.jpg | Image file | Image that the Sobel filter modifies. |
To copy the example files to a local working folder:
Create a local working folder. For example, c:\coder\edge_detection
.
Navigate to the working folder.
Copy the files sobel.m
and hello.jpg
from
the examples folder sobel
to your working folder.
copyfile(fullfile(docroot, 'toolbox', 'coder', 'examples', 'sobel'))
Read the original image into a MATLAB matrix and display it.
im = imread('hello.jpg');
Display the image as a basis for comparison to the result of the Sobel filter.
image(im);
The Sobel filtering algorithm operates on grayscale images. Convert the color image to an equivalent grayscale image with normalized values (0.0 for black, 1.0 for white).
gray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;
To run the MATLAB function for the Sobel filter,
pass the grayscale image matrix gray
and a threshold
value to the function sobel
. This example uses
0.7 for a threshold value.
edgeIm = sobel(gray, 0.7);
To display the modified image, reformat the matrix edgeIm
with
the function repmat
so that you can pass it to
the image
command.
im3 = repmat(edgeIm, [1 1 3]); image(im3);
To test that generated code is functionally equivalent to the original MATLAB code and that run-time errors do not occur, generate a MEX function.
codegen -report sobel
codegen
generates a MEX function named sobel_mex
in
the current working folder.
To run the MEX function for the Sobel filter, pass
the grayscale image matrix gray
and a threshold
value to the function sobel_mex
. This example uses
0.7 for a threshold value.
edgeImMex = sobel_mex(gray, 0.7);
To display the modified image, reformat the matrix edgeImMex
with
the function repmat
so that you can pass it to
the image
command.
im3Mex = repmat(edgeImMex, [1 1 3]); image(im3Mex);
This image is the same as the image created using the MATLAB function.
Although you can write a custom main function for your application, an example main function provides a template to help you incorporate the generated code.
To generate an example main function for the Sobel filter:
Create a configuration object for a C static library.
cfg = coder.config('lib');
For configuration objects for C/C++ source code, static libraries,
dynamic libraries, and executables, the setting GenerateExampleMain
controls
generation of the example main function. The setting is set to 'GenerateCodeOnly'
by
default, which generates the example main function but does not compile
it. For this example, do not change the value of the GenerateExampleMain
setting.
Generate a C static library using the configuration object.
codegen -report -config cfg sobel
The generated files for the static library are in the folder codegen/lib/sobel
.
The example main files are in the subfolder codegen/lib/sobel/examples
.
Do not modify the files main.c
and main.h
in
the examples
subfolder. If you do, when you regenerate
code, MATLAB Coder does not regenerate the example main files.
It warns you that it detects changes to the generated files.
Copy the files main.c
and main.h
from
the folder codegen/lib/sobel/examples
to another
location. For this example, copy the files to the current working
folder. Modify the files in the new location.
The example main function declares and initializes data, including dynamically allocated data, to zero values. It calls entry-point functions with arguments set to zero values, but it does not use values returned from the entry-point functions.
The C main function must meet the requirements of your application. This example modifies the example main function to meet the requirements of the Sobel filter application.
This example modifies the file main.c
so
that the Sobel filter application:
Reads in the grayscale image from a binary file.
Applies the Sobel filtering algorithm.
Saves the modified image to a binary file.
Modify the function main
to:
Accept the file containing the grayscale image data and a threshold value as input arguments.
Call the function main_sobel
with
the address of the grayscale image data stream and the threshold value
as input arguments.
In the function main
:
Remove the declarations void(argc)
and (void)argv
.
Declare the variable filename
to
hold the name of the binary file containing the grayscale image data.
const char *filename;
Declare the variable threshold
to
hold the threshold value.
double threshold;
Declare the variable fd
to hold
the address of the grayscale image data that the application reads
in from filename
.
FILE *fd;
Add an if
statement that checks
for three arguments.
if (argc != 3) { printf("Expected 2 arguments: filename and threshold\n"); exit(-1); }
Assign the input argument argv[1]
for
the file containing the grayscale image data to filename
.
filename = argv[1];
Assign the input argument argv[2]
for
the threshold value to threshold
, converting the
input from a string to a numeric double.
threshold = atof(argv[2]);
Open the file containing the grayscale image data
whose name is specified in filename
. Assign the
address of the data stream to fd
.
fd = fopen(filename, "rb");
To verify that the executable can open filename
,
write an if
-statement that exits the program if
the value of fd
is NULL
.
if (fd == NULL) { exit(-1); }
Replace the function call for main_sobel
by
calling main_sobel
with input arguments fd
and threshold
.
main_sobel(fd, threshold);
Close the grayscale image file after calling sobel_terminate
.
fclose(fd);
In the example main file, the function argInit_d1024xd1024_real_T
creates
a dynamically allocated variable-size array (emxArray) for the image
that you pass to the Sobel filter. This function initializes the emxArray
to a default size and the elements of the emxArray to 0. It returns
the initialized emxArray.
For the Sobel filter application, modify the function to read the grayscale image data from a binary file into the emxArray.
In the function argInit_d1024xd1024_real_T
:
Replace the input argument void
with
the argument FILE *fd
. This variable points to
the grayscale image data that the function reads in.
static emxArray_real_T *argInit_d1024xd1024_real_T(FILE *fd)
Change the values of the variable iv2
to
match the dimensions of the grayscale image matrix gray
. iv2
holds
the size values for the dimensions of the emxArray that argInit_d1024xd1024_real_T
creates.
static int iv2[2] = { 484, 648 };
MATLAB stores matrix data in column-major format, while C stores matrix data in row-major format. Declare the dimensions accordingly.
Define a variable element
to hold
the values read in from the grayscale image data.
double element;
Change the for
-loop construct to
read data points from the normalized image into element
by
adding an fread
command to the inner for
-loop.
fread(&element, 1, sizeof(element), fd);
Inside the for
-loop, assign element
as
the value set for the emxArray data.
result->data[b_j0 + result->size[0] * b_j1] = element;
Modified Initialization Function argInit_d1024xd1024_real_T
The MATLAB function sobel.m
interfaces
with MATLAB arrays, but the Sobel filter application interfaces
with binary files.
To save the image modified by the Sobel filtering algorithm
to a binary file, create a function saveImage
.
The function saveImage
writes data from an emxArray
into a binary file. It uses a construction that is similar to the
one used by the function argInit_d1024xd1024_real_T
.
In the file main.c
:
Define the function saveImage
that
takes the address of emxArray edgeImage
as an input
and has output type void.
static void saveImage(emxArray_uint8_T *edgeImage) { }
Define the variables b_j0
and b_j1
like
they are defined in the function argInit_d1024xd1024_real_T
.
int b_j0; int b_j1;
Define the variable element
to
store data read from the emxArray.
uint8_T element;
Open a binary file edge.bin
for
writing the modified image. Assign the address of edge.bin
to FILE
*fd
.
FILE *fd = fopen("edge.bin", "wb");
To verify that the executable can open edge.bin
,
write an if
-statement that exits the program if
the value of fd
is NULL
.
if (fd == NULL) { exit(-1); }
Write a nested for
-loop construct
like the one in the function argInit_d1024xd1024_real_T
.
for (b_j0 = 0; b_j0 < edgeImage->size[0U]; b_j0++) { for (b_j1 = 0; b_j1 < edgeImage->size[1U]; b_j1++) { } }
Inside the inner for
-loop, assign
the values from the modified image data to element
.
element = edgeImage->data[b_j0 + edgeImage->size[0] * b_j1];
After the assignment for element
,
write the value from element
to the file edge.bin
.
fwrite(&element, 1, sizeof(element), fd);
After the for
-loop construct, close fd
.
fclose(fd);
In the example main function, the function main_sobel
creates
emxArrays for the data for the grayscale and modified images. It calls
the function argInit_d1024xd1024_real_T
to initialize
the emxArray for the grayscale image. main_sobel
passes
both emxArrays and the threshold value of 0 that the initialization
function argInit_real_T
returns to the function sobel
.
When the function main_sobel
ends, it discards
the result of the function sobel
.
For the Sobel filter application, modify the function main_sobel
to:
Take the address of the grayscale image data and the threshold value as inputs.
Read the data from the address using argInit_d1024xd1024_real_T
.
Pass the data to the Sobel filtering algorithm with
the threshold value threshold
.
Save the result using saveImage
.
In the function main_sobel
:
Replace the input arguments to the function with the
arguments FILE *fd
and double threshold
.
static void main_sobel(FILE *fd, double threshold)
Pass the input argument fd
to the
function call for argInit_d1024xd1024_real_T
.
originalImage = argInit_d1024xd1024_real_T(fd);
Replace the threshold value input in the function
call to sobel
with threshold
.
sobel(originalImage, threshold, edgeImage);
After calling the function sobel
,
call the function saveImage
with the input edgeImage
.
saveImage(edgeImage);
To match the changes that you made to the function definitions, make the following changes to the function declarations:
Change the input of the function *argInit_d1024xd1024_real_T
to FILE
*fd
.
static emxArray_real_T *argInit_d1024xd1024_real_T(FILE *fd);
Change the inputs of the function main_sobel
to FILE
*fd
and double threshold
.
static void main_sobel(FILE *fd, double threshold);
Add the function saveImage
.
static void saveImage(emxArray_uint8_T *edgeImage);
Modified Function Declarations
For input/output functions that you use in main.c
,
add the header file stdio.h
to the included files
list.
#include <stdio.h>
main.c
Navigate to the working folder if you are not currently in it.
Create a configuration object for a C standalone executable.
cfg = coder.config('exe');
Generate a C standalone executable for the Sobel filter using the configuration object and the modified main function.
codegen -report -config cfg sobel main.c main.h
By default, if you are running MATLAB on a Windows® platform,
the executable sobel.exe
is generated in the current
working folder. If you are running MATLAB on a platform other
than Windows, the file extension is the corresponding extension
for that platform. By default, the code generated for the executable
is in the folder codegen/exe/sobel
.
Create the MATLAB matrix gray
if
it is not currently in your MATLAB workspace:
im = imread('hello.jpg');
gray = (0.2989 * double(im(:,:,1)) + 0.5870 * double(im(:,:,2)) + 0.1140 * double(im(:,:,3)))/255;
Write the matrix gray
into a binary
file using the fopen
and fwrite
commands.
The application reads in this binary file.
fid = fopen('gray.bin', 'w'); fwrite(fid, gray, 'double'); fclose(fid);
Run the executable, passing to it the file gray.bin
and
the threshold value 0.7.
To run the example in MATLAB on a Windows platform:
system('sobel.exe gray.bin 0.7');
The executable generates the file edge.bin
.
Read the file edge.bin
into a MATLAB matrix edgeImExe
using
the fopen
and fread
commands.
fd = fopen('edge.bin', 'r'); edgeImExe = fread(fd, size(gray), 'uint8'); fclose(fd);
Pass the matrix edgeImExe
to the
function repmat
and display the image.
im3Exe = repmat(edgeImExe, [1 1 3]); image(im3Exe);
The image matches the images from the MATLAB and MEX functions.