Main Content

Create an App for Comparing Edge Detection Methods

R2026b
Since R2026b

This example shows how to build an app to interactively detect edges in images using App Designer. Using the EdgeDetectionComparisonApp app, users can interactively detect edges in the same image using two different edge detection methods and compare the results side by side. The app can compare the results of edge detection methods supported by the edge function.

In this example, you first build a custom UI component you can use to detect edges in an image, and then build an app that uses the custom UI component to compare edge detection results. The custom UI component inherits from the matlab.ui.componentcontainer.ComponentContainer class. You can reuse the custom UI component in different apps to improve code reusability, logic isolation, and maintainability.

Open App Designer

App Designer is an interactive development environment for designing custom UI components and apps and programming their behavior.

To build the app from scratch, open App Designer using this command. Alternatively, you can open App Designer by selecting the Design App option on the Apps tab of the MATLAB® toolstrip.

appdesigner

In this example, you build the EdgeDetector custom UI component and the EdgeDetectionComparisonApp app. The EdgeDetector component and the EdgeDetectionComparisonApp app are also attached to this example as supporting files. For information on running the app, see the Compare Edge Detection Methods Using the App section.

You can also open this example from the App Designer home page by clicking Show examples in the Apps section of the home page and selecting Compare Edge Detection Results from the list of examples.

You can customize the code of the app in the attached supporting files. For information on customizing the app, see the Customize the App section.

App Layout Design

The EdgeDetectionComparisonApp app has two main regions: a toolstrip and a working area.

The toolstrip contains these sections:

  • Import Image — Consists of UI components used to import image data from a file or the workspace.

  • Export — Consists of UI components used to export the detected edges.

The working area of the app consists of a single section containing two instances of the custom UI component EdgeDetector, which detect edges in the imported image using two different methods.

Each EdgeDetector component contains these sections.

  1. Image view — Consists of a Viewer UI component that displays the imported image with edges detected using the selected method. The component displays the image using the imageshow function. The handle of the displayed image is an Image object, for which the Viewer object is the parent. For more information about the Viewer object, see Viewer Properties. For more information about the Image object, see Image Properties.

  2. Edge detection — Consists of UI components to interactively select an edge detection method and its parameters.

App layout.

The app uses this grid layout structure to create the defined layout.

  • Main app figure

    • Main app grid layout

      • Toolstrip grid layout

        • Toolstrip elements like import, export

      • Working area grid layout

        • EdgeDetector custom UI component

For more information on using grid layout with App Designer, see Use Grid Layout Managers in App Designer.

Create the EdgeDetector Custom UI Component

Each EdgeDetector custom component includes these properties:

  • OriginalImage — Original image loaded by the user of the app.

  • Image — Displayed image. Initially, Image is the same as OriginalImage. When you apply an edge detection method to the image, the app updates Image to the edge detection image being displayed.

  • UpdateRequestedFlag — Flag to trigger the update method of the component. This is a private flag, not accessible to users of the app.

Custom UI components inherit from the matlab.ui.componentcontainer.ComponentContainer class and have two primary methods: setup and update.

The setup method and other custom functions of the EdgeDetector custom component create and set up its layout, including these UI components.

  • A grid layout for the UI components.

  • The Viewer objects used to display the image.

  • UI elements used to interactively select an edge detection method and its parameters.

The EdgeDetector component stores the image in which to detect edges in the Image property. When the user sets the Image property of the component, the component resets to the default view. The set.Image method defines this behavior.

function set.Image(comp,img)
    % Save the input image to OriginalImage and display it.
    if ~((ismatrix(img) || (ndims(img)==3 && size(img,3)==1)))
        error("Input image must be specified as a 2-D grayscale image or 2-D binary image.");
    end
    comp.OriginalImage = img;
    comp.ImageshowHandle.Data = img;
    % Reset edge detection selection on new data load
    comp.SelectEdgeMethodDropDown.Value = comp.DefaultDropDownValue;
    comp.SelectMethodLabel.Enable = "on";
    comp.SelectEdgeMethodDropDown.Enable = "on";
    comp.enableThreshold(false,false);
    comp.enableNoThinning(false);
    comp.Param3Label.Visible = "off";
    delete(comp.Param3UIComponent);
end

When the user changes the edge detection method or the parameters of the selected edge detection method, the EdgeDetector component triggers the update method. The update method detects the edges based on the original image and current input values and displays the results.

function update(comp)
    % Based on the current selection of method, compute the
    % edge detected image and display it
    value = comp.SelectEdgeMethodDropDown.Value;
    try
        switch value
            case {"Sobel","Prewitt","Roberts"}
                if comp.NoThinningCheckBox.Value
                    comp.ImageshowHandle.Data = edge(comp.OriginalImage, ...
                        value, ...
                        comp.ThresholdEditField.Value, ...
                        comp.Param3UIComponent.Value, ...
                        "nothinning");
                else
                    comp.ImageshowHandle.Data = edge(comp.OriginalImage, ...
                        value,...
                        comp.ThresholdEditField.Value, ...
                        comp.Param3UIComponent.Value, ...
                        "thinning");
                end
            case "log"
                comp.ImageshowHandle.Data = edge(comp.OriginalImage,"log", ...
                    comp.ThresholdEditField.Value, ...
                    comp.Param3UIComponent.Value);
            case "zerocross"
                if ~strcmp(comp.Param3UIComponent.Value,comp.DefaultDropDownValue)
                    filterH = evalin("base",comp.Param3UIComponent.Value);
                    comp.ImageshowHandle.Data = edge(comp.OriginalImage,"zerocross", ...
                        comp.ThresholdEditField.Value, ...
                        filterH);
                else
                    comp.ImageshowHandle.Data = edge(comp.OriginalImage,"zerocross", ...
                        comp.ThresholdEditField.Value);
                end
            case "Canny"
                comp.ImageshowHandle.Data = edge(comp.OriginalImage,"canny", ...
                    [comp.ThresholdEditField.Value comp.HighThresholdEditField.Value], ...
                    comp.Param3UIComponent.Value);
            case "approxcanny"
                comp.ImageshowHandle.Data = edge(comp.OriginalImage,"approxcanny", ...
                    [comp.ThresholdEditField.Value comp.HighThresholdEditField.Value]);
            otherwise
                comp.ImageshowHandle.Data = comp.OriginalImage;
        end
    catch ME
        comp.displayError(ME.message);
    end
end

Define Callbacks for EdgeDetector Custom UI Component

The EdgeDetector component uses callback functions to handle user interactions. The callback functions ensure that the EdgeDetector component triggers the update method when you change the image, edge detection method, or parameters.

For example, when you change the selected edge detection method, the EdgeDetector component deletes the existing UI elements for the parameters of the previous edge detection method and creates UI elements for the parameters of the newly selected method. The SelectEdgeMethodDropDownValueChanged callback, as shown here, invokes a method-specific function. For example, if you select the zerocross edge detection method, the callback invokes the createInputForZerocross function. The method-specific function creates the UI elements for the edge detection parameters and invokes the updateImage function when you change any parameter. The updateImage function in turn sets the UpdateRequestedFlag to true, which triggers the update method of the EdgeDetector component.

function SelectEdgeMethodDropDownValueChanged(comp, event)
    % Callback function to create the UI components 
    % of the selected edge detection method
    delete(comp.Param3UIComponent);
    value = comp.SelectEdgeMethodDropDown.Value;
    switch value
        case {"Sobel","Prewitt","Roberts"}
            comp.createInputForSobelPrewittRoberts();
        case "log"
            comp.createInputForLog();
            comp.Param3UIComponent.Value = 2;
        case "zerocross"
            comp.createInputForZerocross();
        case "Canny"
            comp.createInputForCanny();
            comp.Param3UIComponent.Value = sqrt(2);
        case "approxcanny"
            comp.createInputForApproxCanny();
        otherwise
            comp.enableThreshold(false,false);
            comp.enableNoThinning(false);
            comp.Param3Label.Visible = "off";
    end
end

function createInputForZerocross(comp)
    % Function to create UI components to get zerocross method parameters
    % from user
    comp.enableThreshold(true,false);
    comp.enableNoThinning(false);

    % Create Filter drop-down
    comp.Param3Label.Visible = "on";
    comp.Param3Label.Text = "Filter";
    filterDropdown = uidropdown(Parent=comp.EdgePropertiesGridLayout, ...
        Items=comp.DefaultDropDownValue);
    filterDropdown.Layout.Row = 2;
    filterDropdown.Layout.Column = 2;
    filterDropdown.DropDownOpeningFcn = @(src,~)comp.getVarFromWorkspace(src);
    filterDropdown.ValueChangedFcn = @(~,~)comp.updateImage();
    comp.Param3UIComponent = filterDropdown;
end

function updateImage(comp)
    % Function to request update when user updates a UI input
    comp.UpdateRequestedFlag = true;
end

The EdgeDetector component displays error messages when an error occurs in execution. The component displays the error message in a dialog box using the uialert function. Because uialert requires a figure to display the message, the EdgeDetector component attempts to get the ancestor figure of the component to display the message. If it fails to get an ancestor figure, it displays the error message in the command window by using the error function instead of a dialog box. You can capture this behavior of displaying error messages by defining the displayError function as follows.

function displayError(comp,errorMsg)
    % Function to display error messages. To display the error
    % message as a uialert, this function tries to get an ancestor
    % figure to which the custom UI component is parented. If
    % it fails to find an ancestor figure, the error passes to the command window.
    fig = ancestor(comp,"figure");
    if isempty(fig)
        error(errorMsg);
    else
        uialert(fig,errorMsg,"Error");
    end
end

Define App Methods

The app uses methods to import and visualize data, process user input and update the display, export the detected edges, and control the app state. The app also uses some helper functions to improve code readability and code reusability. These are some of the important app methods.

Create Two EdgeDetector Components

To enable users to view the results of two different edge detection operations side by side, the working area of the app is split into two components, defined as the LeftComponent and RightComponent properties of the app class. Each component of the working area contains an instance of the EdgeDetector custom UI component and the Viewer objects from the EdgeDetector components are linked using the linkviewers function. Linking the viewers enables the user to pan and zoom both images synchronously. The startupFcn method defines the creation and placement of the custom UI components.

function startupFcn(app)
    % Initialization function to create the component containers
    % and link their viewers
    app.LeftComponent = EdgeDetector(app.WorkingAreaGridLayout);
    app.RightComponent = EdgeDetector(app.WorkingAreaGridLayout);
    linkviewers([app.LeftComponent.Viewer app.RightComponent.Viewer],"on");

    % Set a name for each component to make it easy to identity them
    app.LeftComponent.ImageName = "Left Image";
    app.RightComponent.ImageName = "Right Image";
end

Reset App on New Image Load

When the user loads a new image into the app, both EdgeDetector components clear the existing data and display the loaded image with no edge detection applied. The app also enables the Export section of the app toolstrip. The resetAppOnNewDataLoad method defines this behavior.

function resetAppOnNewDataLoad(app,img)
    % Function to set input image and reset app on new data load
    app.LeftComponent.Image = img;
    app.RightComponent.Image = img;

    % Enable exporting
    app.ToFileLabel.Enable = "on";
    app.ToFileDropDown.Enable = "on";
    app.ToWorkspaceLabel.Enable = "on";
    app.ToWorkspaceDropDown.Enable = "on";
end

Import Images in App

Users can load an image into the app from a file or from the workspace using the Import Image section of the app toolstrip. If the user loads the image from a file by selecting the Browse option, the app opens a dialog box enabling the user to browse for files that have image file formats. When the user selects a new image file, the app resets. The BrowseButtonPushed method defines the file browsing behavior.

% Button pushed function: BrowseButton
function BrowseButtonPushed(app,event)
    % Function to import an image file by browsing file system
    filterSpec = app.getSupportedFileFilter();

    [file,location] = uigetfile(filterSpec,"Select an image file");
    if ~isequal(file,0)
        try
            imageData = imread(fullfile(location,file));
            if ~((ismatrix(imageData) || (ndims(imageData)==3 && size(imageData,3)==1)))
                uialert(app.EdgeDetectionComparisonToolFigure,...
                    "Input image must be specified as a 2-D grayscale image or 2-D binary image.", ...
                    "Invalid File");
                return;
            end
        catch
            uialert(app.EdgeDetectionComparisonToolFigure,"Unable to read image file.","Invalid File");
            return;
        end
        app.resetAppOnNewDataLoad(imageData);
    end
end

If the user loads the image from the workspace by selecting the Select option, the app filters workspace variables for potential images and displays the variable names in the drop-down. When the user selects a new image from the workspace, the app resets. The FromWorkspaceDropDownOpening and FromWorkspaceDropDownValueChanged methods define these behaviors.

% Drop-down opening function: FromWorkspaceDropDown
function FromWorkspaceDropDownOpening(app,event)
    % Callback function to filter possible images in workspace and
    % display them in FromWorkspaceDropDown for input selection
    vars = evalin("base","whos");
    supportedClasses = ["int8","uint8","int16","uint16","int32","uint32","int64","uint64","single","double","logical"];
    ValidInputVariables = app.DefaultImportFromWorkspaceDropDownValue;
    for idx = 1:numel(vars)
        entry = vars(idx);
        TF = ismember(entry.class,supportedClasses) && ((length(entry.size) == 2) || (length(entry.size) == 3 && entry.size(3) == 1));
        if TF
            ValidInputVariables(end+1) = convertCharsToStrings(entry.name);%#ok<AGROW>
        end
    end
    app.FromWorkspaceDropDown.Items = ValidInputVariables;
end

% Value changed function: FromWorkspaceDropDown
function FromWorkspaceDropDownValueChanged(app, vent)
    % Callback function to read an image variable from the workspace and
    % load it to the app
    value = app.FromWorkspaceDropDown.Value;
    if ~strcmp(value,app.DefaultImportFromWorkspaceDropDownValue)
        imageData = evalin("base",value);
        app.resetAppOnNewDataLoad(imageData);
    end
    app.FromWorkspaceDropDown.Value = app.DefaultImportFromWorkspaceDropDownValue;
end

Export Detected Edges

Users can export the edge-detected images to files or to the workspace using the Export section of the app toolstrip. In both the To File and To Workspace options, the user can select either one of the edge-detected images to export to a file or to the workspace. The ToFileDropDownValueChanged and ToWorkspaceDropDownValueChanged methods define these respective behaviors.

% Value changed function: ToFileDropDown
function ToFileDropDownValueChanged(app,event)
    % Callback function to write edge-detected image to disk
    value = app.ToFileDropDown.Value;
    switch value
        case "Left Image"
            imageToExport = app.LeftComponent.Image;
        case "Right Image"
            imageToExport = app.RightComponent.Image;
        otherwise
            return;
    end
    filterSpec = app.getSupportedFileFilter(true);
    [file,location] = uiputfile(filterSpec,"Save edge detected image","edgeDetectedImage.png");
    if file~=0
        try
            imwrite(imageToExport,fullfile(location,file));
            uialert(app.EdgeDetectionComparisonToolFigure, ...
                "Edge detected image saved successfully", ...
                "Export Success", ...
                Icon="success");
        catch ME
            uialert(app.EdgeDetectionComparisonToolFigure,ME.message,"Export Failed");
        end
    end
end

% Value changed function: ToWorkspaceDropDown
function ToWorkspaceDropDownValueChanged(app,event)
    % Callback function to write edge detected image to base workspace
    value = app.ToWorkspaceDropDown.Value;
    switch value
        case "Left Image"
            imageToExport = app.LeftComponent.Image;
            assignin("base","edgeDetectedImageLeft",imageToExport);
        case "Right Image"
            imageToExport = app.RightComponent.Image;
            assignin("base","edgeDetectedImageRight",imageToExport);
        otherwise
            return;
    end
    uialert(app.EdgeDetectionComparisonToolFigure, ...
        "Edge detected image saved to workspace successfully", ...
        "Export Success", ...
        Icon="success");
end

Compare Edge Detection Methods Using the App

Run the EdgeDetectionComparisonApp app.

Import an image either from a file or from the workspace using the options in the Import Image section of the app toolstrip. If you choose to import the image from a file, the app opens a dialog box enabling you to browse files that have image file formats. If you choose to import the image from the workspace, the app filters workspace variables for potential images and displays the variable names in the drop-down. When you import an image, the app resets and displays the imported image as both the Left Image and Right Image.

Import image into the app.

Select edge detection methods for both the Left Image and Right Image from the Left Image's edge detection and Right Image's edge detection sections, respectively. For example, to compare the result of the Canny edge detection and zero-cross edge detection methods on the image, select Canny from the Select Method drop-down for the left image, and zerocross from the Select Method drop-down for the right image. Specify parameters for the left image method. Observe that the left image updates immediately. Similarly, specify parameters for the right image method. Observe that the right image updates immediately.

Compare edge detection methods in the app.

You can export the results to files or to the workspace. For example, to export the left image to a file, select the Left Image option in the To File drop-down. To export the right image to workspace, select the Right Image option in the To Workspace drop-down.

Customize the App

You can customize the code of the EdgeDetector custom UI component and EdgeDetectionComparisonApp app in the attached supporting files. You can support more edge detection functions by adding them to the list of edge detection methods, adding the UI elements required for their parameters, and adding the corresponding edge detection function call to the update method of the EdgeDetector component. You can also add support for comparing more than two edge detection methods by adding more cells to the grid layout of the app and associating EdgeDetector components with them.

To customize the app, you can choose one of these options:

  • Open the attached MLAPP files in App Designer and edit the code in the Code View.

  • Open the attached MLAPP files in App Designer, select Share in the Designer tab and then Export to MATLAB Class (.m), and save the M file. You can then edit the M file.

See Also

Apps

Properties

Functions

Topics