Adding image borders

In this demo, we show how to use the OpenCV function cv.copyMakeBorder to set the borders (extra image padding).

Sources:

Contents

Theory

The explanation below belongs to the book Learning OpenCV by Bradski and Kaehler.

One problem that naturally arises when performing convolution to operate on images is how to handle the boundaries. How can we convolve them if the evaluated points are at the edge of the image?

What most of OpenCV functions do is to copy a given image onto another slightly larger image and then automatically pads the boundary (by any of the methods explained below). This way, the convolution can be performed over the needed pixels without problems (the extra padding is cut after the operation is done).

In this demo, we will briefly explore two ways of defining the extra padding (border) for an image:

Code

First we load an image. Next we let the user choose what kind of padding to use on the input image:

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

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

function padSz = padSize(sz)
    %PADSIZE  Size of image padding [top, bottom, left, right]

    % pad by 5% of the image size
    padSz = round(sz([1 1 2 2]) * 0.05);
end

function onType(~,e,h)
    %ONTYPE  Event handler for key press on figure

    % handle keys
    switch e.Key
        case 'h'
            helpdlg({
                'Hot keys:'
                'h - this help dialog'
                'q - quit the program'
                'f - pad the image by reflecting borders'
                'r - pad the image by replicating borders'
                'w - pad the image by wrapping borders'
                'c - pad the image with constant value'
                's - save current image'
            });

        case {'q', 'escape'}
            % quit
            close(h.fig);

        case {'f', 'r', 'w', 'c'}
            % border type
            [~,idx] = ismember(e.Key, {'f', 'r', 'w', 'c'});
            set(h.pop, 'Value',idx);
            onChange([], [], h);

        case {'s', 'space'}
            % save image
            img = get(h.img, 'CData');
            fname = fullfile(tempdir(), ...
                sprintf('out_%s.png', datestr(now(),'yyyymmddTHHMMSS')));
            cv.imwrite(fname, img);
            disp(['Saved ' fname]);
    end
end

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

    % border type
    types = get(h.pop, 'String');
    idx = get(h.pop, 'Value');
    props = {'BorderType',types{idx}};

    % border value
    if strcmp(types{idx}, 'Constant')
        if mexopencv.isOctave()
            %HACK: uisetcolor not implemented in Octave
            clr = randi([0 255], [1 3]);
        else
            clr = round(uisetcolor() * 255);
        end
        props = [props, 'Value',clr];
    end

    % perform padding
    out = cv.copyMakeBorder(h.src, padSize(size(h.src)), props{:});

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

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

    % initial padding
    out = cv.copyMakeBorder(img, padSize(size(img)));
    sz = size(out);

    % build the user interface (no resizing to keep it simple)
    h = struct();
    h.src = img;
    h.fig = figure('Name','CopyMakeBorder Demo', ...
        'NumberTitle','off', 'Menubar','none', 'Resize','off', ...
        'Position',[200 200 sz(2) sz(1)+29]);
    if ~mexopencv.isOctave()
        %HACK: not implemented in Octave
        movegui(h.fig, 'center');
    end
    h.ax = axes('Parent',h.fig, 'Units','pixels', 'Position',[1 30 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.pop = uicontrol('Parent',h.fig, 'Style','popupmenu', ...
        'Position',[5 5 90 20], ...
        'String',{'Reflect101','Replicate','Wrap','Constant'});

    % hook event handlers
    opts = {'Interruptible','off', 'BusyAction','cancel'};
    set(h.fig, 'WindowKeyPressFcn',{@onType,h}, opts{:});
    set(h.pop, 'Callback',{@onChange,h}, opts{:});
end