Code covered by the BSD License  

Highlights from
Plot on an image- addMarkerLines2Img

image thumbnail

Plot on an image- addMarkerLines2Img

by

 

09 Jul 2012 (Updated )

Plot a curve line/points on an image

addMarkerLines2Img.m
function markedImg=addMarkerLines2Img(img, trajectory, varargin)

%% addMarkerLines2Img
% Plot a trajectory line on an image
%
%% Syntax
% markedImg=addMarkerLines2Img(img, trajectory, 'lineWidth', lineWidth,...
%   'lineColor', lineColor, 'lineStyle', lineStyle);
%
%% Description
% This functions allows marking objects of interest/path/ trajectory on an image,
%  returning the marked image. The functionality is similar to usage of plot with a
%  background image, but here plot command is not used. The resulting image can thus be
%  used- saved as image file, added to a video, processed etc.. To achieve connection
%  between trajectory points (plot style) calculate dense trajectory without holed.
%  mask2poly does this for mask borders.
%  To achieve this functionality with videos using plot command one must present an image
%  in a figure, holding it, draw a line plot above it, and getting the marked image with
%  the getframe command. This will also result in connection between dots (again, note the
%  example), and option to use marker style and colors supported by plot function. However
%  will present figure on screen, and demands usage of plot command- isnt supported by
%  Matlab compiler.
%  Similar functionality is available as part of the Computer Vision Toolbox.
%
%% Input arguments (defaults exist):
%  img-  Input image.
%  trajectory- a [N,2] matrix [rows, cols] describibg the indexes to be marked.
%  lineWidth- the marker line width.
%  lineColor- marker lineColor.
%  lineStyle- a string describing the style of the presented line 
%   {-, --, -., [none]}. Default value is 'none'
%  markerOpacity- marker opacity, [0:1] determeneing whether the markers/lines will be
%   transparent (will the original image be seen through them) 
%
%% Output arguments
%  markedImg- resulting marked image [N,M,3] in RGB either uint8 or double
%
%% Issues & Comments 
% Logical mask targectory can be found via mask2poly function
%  (http://www.mathworks.com/matlabcentral/fileexchange/32112-mask2poly) followed by
%  fliplr function. See example for details.
%
%% Example I
% img=imread('peppers.png');
% figure;
% subplot(2, 2, 1)
% imshow(img);
% title('Select trajectory vertexes by clicking the image. Double click to finish',...
%    'FontSize', 18, 'Color', [1,0,0]);
% impolyH=impoly;
% title('Original user defined contour', 'FontSize', 18, 'Color', [1,0,0]);
% 
% pos = getPosition(impolyH);
% pos=cat( 1, pos, pos(1, :) ); % closing the shape
% subplot(2, 2, 2)
% imshow( addMarkerLines2Img(img, fliplr(pos), 'lineWidth', 7, 'lineColor', 'w',...
%   'lineStyle', 'none', 'markerOpacity', 0.8) );
% title('Marked Vertexes border. Trajectory from user clicks positions', 'FontSize', 13);
% 
% subplot(2, 2, 3)
% imshow( addMarkerLines2Img(img, fliplr(pos), 'lineWidth', 5, 'lineColor', 'b',...
%   'lineStyle', '-') );
% title('Marked ROI border. Trajectory via local servise function', 'FontSize', 13);
% 
% subplot(2, 2, 4)
% imshow( addMarkerLines2Img(img, fliplr(pos), 'lineWidth', 5, 'lineColor', 'b',...
%   'lineStyle', '-.') );
% title('Marked ROI border. partial Trajectory via local servise function', 'FontSize', 13);
%
%% Example II
% figure;
% img=imread('peppers.png');
% imshow(img);
% title('Select ROI by left clicking mouse and moving it around.',...
%    'FontSize', 18, 'Color', [1,0,0]);
% imfreehandH=imfreehand;
% currMask=createMask(imfreehandH);
% pos = getPosition(imfreehandH);
% delete(imfreehandH);
% imshow(addMarkerLines2Img(img, fliplr(pos), 'lineWidth', 5, 'lineColor', 'b'))
% title('Marked ROI border. Trajectory via getPosition', 'FontSize', 13);
% 
% % Note position is not laways avalible. Sometimes, all you have is a mask...
% maskTraj=mask2poly(currMask, 'Inner', 'None');
% maskTraj=fliplr(maskTraj); % X-Y Cols-Raws issue
% markedImg=addMarkerLines2Img(img, maskTraj, 'lineWidth', 3, 'lineColor', 'g');
% 
% figure;
% imshow(markedImg);
% title('marked ROI border. Trajectory via mask2poly.', 'FontSize', 13);
%
%% See also
% plot, line
%
%% Revision history
% First version: Nikolay S. 2011-08-10. 
% Last update:   Nikolay S. 2013-12-19.
%
% *List of Changes:*
% 2014-08-19- Added markerOpacity input parameter
% 2014-07-22- Supporting lineColor numeric tprilet inputs together with characters
% 2013-12-19- Added lineStyle option to fill gaps between points. Chnaged input style to
%   name-value pairs, replaced filter2 with imdilate.

%% Default inputs
lineWidth=2;
lineColor='b';
lineStyle='none';
markerOpacity=1;

%% Load uses params, overifding default ones
% The list of all legal input parameter names. Others will be ignored
funcParamsNames={'lineWidth', 'lineColor', 'lineStyle', 'markerOpacity'};
assignUserInputs(funcParamsNames, varargin{:});


%% Validate inputs legality
% deal with empty trajectory
if isempty(trajectory) || markerOpacity==0 ||...
        isempty(lineColor)|| strcmpi(lineColor, 'none')
    markedImg=img;
    return;
end
% Make trajectory to be [N,2] [rows,cols] trajectory coordinates vector
if (size(trajectory,1)==2) && (size(trajectory,2)~=2)
   trajectory=transpose(trajectory); 
end

% deal with trajectory NaN points
isNaNPoint=any( isnan(trajectory), 2);
trajectory=trajectory(~isNaNPoint, :);
if isempty(trajectory)
    markedImg=img;
    return;
end

lineWidth=round(lineWidth);
%lineWidth=lineWidth+mod(lineWidth+1,2); % use only odd values- in case of even value
imageHeigth=size(img,1);
imageWidth=size(img,2);

% Fill gaps between trajectory edges if needed
trajectory=fillTrajGaps(trajectory, lineStyle, lineWidth);

%% Verify integer values are used
trajectory=round(trajectory);

% This will prevent erros, but you will not see attempts to put a marking beyong the image
isLegalPoint=( trajectory(:,1 )>= 1 ) & ( trajectory(:,1) <= imageHeigth ) &...
    ( trajectory(:,2) >= 1 ) & ( trajectory(:,2) <= imageWidth );
trajectory=trajectory(isLegalPoint, :);

if ischar(lineColor)
    % Convert lineColor char or string to legal RGB value
    lineColor=colorName2Val(lineColor);
end

% create a mask of user defined width, where elements are true in the appropriate
% locations
trajInd=sub2ind([size(img,1),size(img,2)], trajectory(:,1), trajectory(:,2));
trajectoryMask=false(imageHeigth, imageWidth);
trajectoryMask(trajInd)=true;
if lineWidth>1
    % dilateStrel=strel('disk', ceil(lineWidth/2), 4);
    dilateStrel=true(lineWidth);
    if all(lineWidth)>2 
        dilateStrel(1, 1)=false;
        dilateStrel(end, 1)=false;
        dilateStrel(1, end)=0;
        dilateStrel(end, end)=0;
    end

    trajectoryMask=imdilate(trajectoryMask, dilateStrel);
end


if size(img,3)==1 % convert image to RGB, even if the input image was grayscale
   img=repmat(img, [1, 1, 3]);
end

% lineColor can be a double [0:1] or an integer [0:255], it's type must suit image data type
% if  strcmpi('uint8',class(img)) && max(lineColor)<=1 && ~strcmpi('uint8',class(lineColor))
isImgUINT8=strcmpi( 'uint8', class(img) );
if  max( img(:) )>1 || isImgUINT8 && max(lineColor)<=1 &&...
      ~strcmpi( 'uint8',class(lineColor) )
   lineColor=255*lineColor;
end

if isImgUINT8 && markerOpacity~=1
    R=single( img(:,:,1) );
    G=single( img(:,:,2) );
    B=single( img(:,:,3) );
else
    R=img(:,:,1);
    G=img(:,:,2);
    B=img(:,:,3);
end

if markerOpacity==1
    R(trajectoryMask)=lineColor(1);
    G(trajectoryMask)=lineColor(2);
    B(trajectoryMask)=lineColor(3);
else
    R(trajectoryMask)=markerOpacity*lineColor(1)+(1-markerOpacity)*R(trajectoryMask);
    G(trajectoryMask)=markerOpacity*lineColor(2)+(1-markerOpacity)*G(trajectoryMask);
    B(trajectoryMask)=markerOpacity*lineColor(3)+(1-markerOpacity)*B(trajectoryMask);
end

if isImgUINT8
    markedImg=uint8( cat(3, R, G, B) );
else
    markedImg=cat(3, R, G, B);
end


%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%
%% --------------------------- Service sub functions --------------------------- %%
%&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%
function paddedTrajectory=fillTrajGaps(trajectory, lineStyle, lineWidth)
% Fill gaps between line vertexes, accourding to user choise of lineStyle
if strcmpi(lineStyle, 'none')
    paddedTrajectory=trajectory;
    return;
end

nVertex=size(trajectory, 1);
iRow=1;
iCol=2;
nEdge=round( max(abs( diff(trajectory, 1) ), [], 2) );
edgeTragectory=zeros(sum(nEdge), 2);
iPointStart=1;
iPointEnd=nEdge(1);
for iVertex=2:nVertex
    rowStart=trajectory(iVertex-1, iRow);
    rowEnd=trajectory(iVertex, iRow);
    colStart=trajectory(iVertex-1, iCol);
    colEnd=trajectory(iVertex, iCol);
    
    edgeTragectory(iPointStart:iPointEnd, iRow)=linspace( rowStart, rowEnd,...
        nEdge(iVertex-1) );
    edgeTragectory(iPointStart:iPointEnd, iCol)=linspace( colStart, colEnd,...
        nEdge(iVertex-1) );
    
    if iVertex < nVertex
        iPointStart=iPointEnd+1;
        iPointEnd=iPointStart+nEdge(iVertex)-1;
    end
end

switch(lineStyle)
    case('-')
        % Do nothing
    case('--') 
        % Delete every second point
        edgeTragectory=edgeTragectory( round(1:1.4*lineWidth:end), : ); 
    case('-.')
        % Delete every third point
        edgeTragectory=edgeTragectory(1:3*lineWidth:end, :); 
end
paddedTrajectory=cat(1, trajectory, edgeTragectory); 

Contact us