Edge Detection with Sobel Method in Half-Precision

This example shows how to generate a standalone C++ library from a MATLAB® function that performs Sobel edge detection of images by using half-precision floating point numbers. The Sobel edge algorithm takes an image (represented as a matrix) and returns an image emphasizing the high spatial frequency regions that correspond to its edges. This example also shows how to generate and test the Sobel edge detection algorithm by using a MEX function.

Sobel Edge Detection Algorithm

In the Sobel edge detection algorithm, a 2-D spatial gradient operation is performed on a grayscale image. This operation emphasizes the high spatial frequency regions that correspond to the edges in the image.

type sobelEdgeDetectionAlg
function edgeImg = sobelEdgeDetectionAlg(img,thresh)  %#codegen
%sobelEdgeDetection Example MATLAB function for edge detection.
% Copyright 2018 The MathWorks, Inc.

kern = half([1 2 1; 0 0 0; -1 -2 -1]);

% Finding horizontal and vertical gradients.
h = conv2(img(:,:,2),kern,'same');
v = conv2(img(:,:,2),kern','same');

% Finding magnitude of the gradients.
e = sqrt(h.*h + v.*v);

% Threshold the edges
edgeImg = uint8((e > thresh) * 240);

end

The Sobel edge algorithm computes the horizontal gradient resX and the vertical gradient resY of the input image by using two orthogonal filter kernels maskX and maskY. After the filtering operation, the algorithm computes the gradient magnitude and applies a threhold to find the regions of the images that are considered to be edges.

Read Images and Pack Data Into RGBA Packed Column Major Order

Use the standard imread command to read the images. imread represents the RGB channels of an images with integers, one for each pixel. The integers range from 0 to 255. Simply casting inputs to half type might result in overflow during convolutions. In this case, we can scale the images to values between 0 and 1.

im = imread('peppers.png');
figure();
image(im);
imPacked = half(im)/255;
thresh = half(100)/255;

Generate MEX

Generate a C++ MEX function by using the codegen command.

cfg = coder.config('mex');
cfg.TargetLang = 'C++';
cfg.GenerateReport = true;
codegen -config cfg -args {imPacked,thresh} sobelEdgeDetectionAlg
Code generation successful: To view the report, open('codegen/mex/sobelEdgeDetectionAlg/html/report.mldatx').

Run Generated MEX and Show the Detected Edge

Before generating C++ code, you must first test the MEX function in MATLAB to make sure that it is functionally equivalent to the original MATLAB code and that no run-time errors occur. By default, codegen generates a MEX function named sobelEdgeDetectionAlg_mex in the current folder. This allows you to test the MATLAB code and MEX function and compare the results.

out_disp = sobelEdgeDetectionAlg_mex(imPacked,thresh);
figure();
imagesc(out_disp);

Generate Static C++ Library

Use the codegen command to produces a C++ static library. By default, the generated library is located in the folder codegen/lib/sobelEdgeDetectionAlg/.

cfg = coder.config('lib');
cfg.TargetLang = 'C++';
cfg.GenerateReport = true;
codegen -config cfg -args {imPacked,thresh} sobelEdgeDetectionAlg;
Code generation successful: To view the report, open('codegen/lib/sobelEdgeDetectionAlg/html/report.mldatx').

Inspect the Generated Function

type codegen/lib/sobelEdgeDetectionAlg/sobelEdgeDetectionAlg.cpp
//
// File: sobelEdgeDetectionAlg.cpp
//
// MATLAB Coder version            : 5.1
// C/C++ source code generated on  : 30-Jul-2020 01:28:02
//

// Include Files
#include "sobelEdgeDetectionAlg.h"
#include "conv2MovingWindowSameCM.h"
#include "rtwhalf.h"
#include "sobelEdgeDetectionAlg_data.h"
#include "sobelEdgeDetectionAlg_initialize.h"

// Function Definitions
//
// sobelEdgeDetection Example MATLAB function for edge detection.
//  Copyright 2018 The MathWorks, Inc.
// Arguments    : const real16_T img[589824]
//                real16_T thresh
//                unsigned char edgeImg[196608]
// Return Type  : void
//
void sobelEdgeDetectionAlg(const real16_T img[589824], real16_T thresh, unsigned
  char edgeImg[196608])
{
  static const real16_T hv[9] = { real16_T(1.0F), real16_T(0.0F), real16_T(-1.0F),
    real16_T(2.0F), real16_T(0.0F), real16_T(-2.0F), real16_T(1.0F), real16_T
    (0.0F), real16_T(-1.0F) };

  static const real16_T hv1[9] = { real16_T(1.0F), real16_T(2.0F), real16_T(1.0F),
    real16_T(0.0F), real16_T(0.0F), real16_T(0.0F), real16_T(-1.0F), real16_T
    (-2.0F), real16_T(-1.0F) };

  static real16_T h[196608];
  static real16_T v[196608];
  int k;
  if (!isInitialized_sobelEdgeDetectionAlg) {
    sobelEdgeDetectionAlg_initialize();
  }

  //  Finding horizontal and vertical gradients.
  coder::conv2MovingWindowSameCM(*(real16_T (*)[196608])&img[196608], hv, h);
  coder::conv2MovingWindowSameCM(*(real16_T (*)[196608])&img[196608], hv1, v);

  //  Finding magnitude of the gradients.
  for (k = 0; k < 196608; k++) {
    real16_T b_h;
    real16_T h1;
    b_h = h[k];
    h1 = v[k];
    b_h = b_h * b_h + h1 * h1;
    h[k] = b_h;
  }

  for (k = 0; k < 196608; k++) {
    h[k] = sqrt_half(h[k]);
  }

  //  Threshold the edges
  for (k = 0; k < 196608; k++) {
    edgeImg[k] = static_cast<unsigned char>((h[k] > thresh) * 240U);
  }
}

//
// File trailer for sobelEdgeDetectionAlg.cpp
//
// [EOF]
//

See Also

| |

Related Topics