Bright edges detection

A new approach for visualizing edges. It uses the absolute difference of two blurs to compute gradients creating local minimas for edges. The histogram equalization makes the edges appears darker within a bright zone.

If a contrast value of zero is given no additional process is performed.

Otherwise a contrasting correction finds the local minimas and sets the edge to black, while setting the surrounding to white. A pixel correction restores line continuity and removes dark spots.

The default contrast value is 1 over a range of 255. This default contrast ensures visualizing edges on chessboard like images or low resolution images where small objects edges may be needed. Other contrast values will look for deeper local minimas, removing smaller details and only leaving higher gradient variations.

Souces:

function varargout = brightedges_demo_gui(im)
    % load source image
    if nargin < 1
        im = fullfile(mexopencv.root(),'test','butterfly.jpg');
        img = cv.imread(im, 'Color',true);
    elseif ischar(im)
        img = cv.imread(im, 'Color',true);
    else
        img = im;
    end
    assert(size(img,3) == 3, 'RGB image expected');

    % create the UI
    h = buildGUI(img);
    if nargout > 0, varargout{1} = h; end
end

function onChange(~,~,h)
    %ONCHANGE  Event handler for UI controls

    % retrieve current values from UI controls
    longRange = round(get(h.slid(1), 'Value')) * 2 + 1;
    shortRange = round(get(h.slid(2), 'Value')) * 2 + 1; % odd for GaussianBlur
    contrst = round(get(h.slid(3), 'Value'));
    set(h.txt(1), 'String',sprintf('LongRange: %d',longRange));
    set(h.txt(2), 'String',sprintf('ShortRange: %d',shortRange));
    set(h.txt(3), 'String',sprintf('Contrast: %d',contrst));

    % histogram equalization
    out = cv.BrightEdges(h.src, ...
        'Contrast',contrst, 'ShortRange',shortRange, 'LongRange',longRange);

    % show result
    set(h.img, 'CData',out);
    drawnow;
end

function h = buildGUI(img)
    %BUILDGUI  Creates the UI

    % parameters
    contrst = 1;
    shortRange = 1;
    longRange = 4;
    out = cv.BrightEdges(img);
    sz = size(img);
    sz(2) = max(sz(2), 300);  % minimum figure width

    % build the user interface (no resizing to keep it simple)
    h = struct();
    h.src = img;
    h.fig = figure('Name','BrightEdges Demo', ...
        'NumberTitle','off', 'Menubar','none', 'Resize','off', ...
        'Position',[200 200 sz(2) sz(1)+80-1]);
    if ~mexopencv.isOctave()
        %HACK: not implemented in Octave
        movegui(h.fig, 'center');
    end
    h.ax = axes('Parent',h.fig, 'Units','pixels', 'Position',[1 80 sz(2) sz(1)]);
    if ~mexopencv.isOctave()
        h.img = imshow(out, 'Parent',h.ax);
    else
        %HACK: https://savannah.gnu.org/bugs/index.php?45473
        axes(h.ax);
        h.img = imshow(out);
    end
    h.txt(1) = uicontrol('Parent',h.fig, 'Style','text', 'FontSize',11, ...
        'Position',[5 5 130 20], 'String','LongRange:');
    h.txt(2) = uicontrol('Parent',h.fig, 'Style','text', 'FontSize',11, ...
        'Position',[5 30 130 20], 'String','ShortRange:');
    h.txt(3) = uicontrol('Parent',h.fig, 'Style','text', 'FontSize',11, ...
        'Position',[5 55 130 20], 'String','Contrast:');
    h.slid(1) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Value',longRange, 'Min',1, 'Max',30, 'SliderStep',[1 5]./(30-1), ...
        'Position',[135 5 sz(2)-135-5 20]);
    h.slid(2) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Value',shortRange, 'Min',1, 'Max',30, 'SliderStep',[1 5]./(30-1), ...
        'Position',[135 30 sz(2)-135-5 20]);
    h.slid(3) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Value',contrst, 'Min',0, 'Max',100, 'SliderStep',[1 10]./(100-0), ...
        'Position',[135 55 sz(2)-135-5 20]);

    % hook event handlers, and trigger default start
    set(h.slid, 'Callback',{@onChange,h}, ...
        'Interruptible','off', 'BusyAction','cancel');
    onChange([],[],h);
end