gusucode.com > vision工具箱matlab源码程序 > vision/showMatchedFeatures.m
function hImage = showMatchedFeatures(I1, I2, matchedPoints1, matchedPoints2, varargin) %showMatchedFeatures Display corresponding feature points. % showMatchedFeatures(I1, I2, matchedPoints1, matchedPoints2) displays a % falsecolor overlay of images I1 and I2, with a color-coded plot of the % corresponding points connected by a line. matchedPoints1 and % matchedPoints2 are the coordinates of corresponding points in I1 and % I2. Points can be an M-by-2 matrix of [x y] coordinates, a SURFPoints % an MSERRegions, a cornerPoints, or a BRISKPoints object. % % showMatchedFeatures(I1, I2, matchedPoints1, matchedPoints2, method) % displays images I1 and I2 using the visualization style specified by % method. Values of method can be: % % 'falsecolor' : Overlay the images by creating a composite red-cyan % image showing I1 as red and I2 as cyan. % 'blend' : Overlay I1 and I2 using alpha blending. % 'montage' : Place I1 and I2 next to each other in the same image. % % Default: 'falsecolor' % % hImage = showMatchedFeatures(...) returns the handle to the image object % returned by showMatchedFeatures. % % showMatchedFeatures(...,Name,Value) specifies additional name-value pair % arguments described below: % % 'PlotOptions' Specify custom plot options in a cell array containing % three string values, {MarkerStyle1, MarkerStyle2, LineStyle}, % corresponding to marker specification in I1, marker % specification in I2, and line style and color. Each of % the specifiers is defined by the <a href="matlab:doc('linespec')">LineSpec</a> of PLOT function. % % Default: {'ro','g+','y-'} % % 'Parent' Specify an output axes for displaying the visualization. % % Class Support % ------------- % I1 and I2 are numeric arrays. % % Example 1 % --------- % % Use Harris features to find corresponding points between two images. % I1 = rgb2gray(imread('parkinglot_left.png')); % I2 = rgb2gray(imread('parkinglot_right.png')); % % points1 = detectHarrisFeatures(I1); % points2 = detectHarrisFeatures(I2); % % [f1, vpts1] = extractFeatures(I1, points1); % [f2, vpts2] = extractFeatures(I2, points2); % % indexPairs = matchFeatures(f1, f2) ; % matchedPoints1 = vpts1(indexPairs(1:20, 1)); % matchedPoints2 = vpts2(indexPairs(1:20, 2)); % % % Visualize putative matches % figure; showMatchedFeatures(I1,I2,matchedPoints1,matchedPoints2,'montage'); % % title('Putative point matches'); % legend('matchedPts1','matchedPts2'); % % Example 2 % --------- % % Use SURF features to find corresponding points between two images % % rotated and scaled with respect to each other % I1 = imread('cameraman.tif'); % I2 = imresize(imrotate(I1,-20), 1.2); % % points1 = detectSURFFeatures(I1); % points2 = detectSURFFeatures(I2); % % [f1, vpts1] = extractFeatures(I1, points1); % [f2, vpts2] = extractFeatures(I2, points2); % % indexPairs = matchFeatures(f1, f2) ; % matchedPoints1 = vpts1(indexPairs(:, 1)); % matchedPoints2 = vpts2(indexPairs(:, 2)); % % % Visualize putative matches % figure; showMatchedFeatures(I1,I2,matchedPoints1,matchedPoints2); % % title('Putative point matches'); % legend('matchedPts1','matchedPts2'); % % See also matchFeatures, estimateGeometricTransform, imshowpair, % legend, SURFPoints, MSERRegions, cornerPoints % Copyright 2011 The MathWorks, Inc. narginchk(4,7); [matchedPoints1, matchedPoints2, method, lineSpec, hAxes] = ... parseInputs(I1, I2, matchedPoints1, matchedPoints2, varargin{:}); % pad the smaller image paddedSize = [max(size(I1,1), size(I2,1)), max(size(I1,2), size(I2,2))]; I1pad = [paddedSize(1) - size(I1,1), paddedSize(2) - size(I1,2)]; I2pad = [paddedSize(1) - size(I2,1), paddedSize(2) - size(I2,2)]; I1pre = round(I1pad/2); I2pre = round(I2pad/2); I1 = padarray(I1, I1pre, 0, 'pre'); I2 = padarray(I2, I2pre, 0, 'pre'); I1 = padarray(I1, I1pad-I1pre, 0, 'post'); I2 = padarray(I2, I2pad-I2pre, 0, 'post'); switch lower(method) case {'falsecolor'} imgOverlay = imfuse(I1, I2); % create red-cyan image instead of the imfuse default imgOverlay(:,:,1) = imgOverlay(:,:,2); imgOverlay(:,:,2) = imgOverlay(:,:,3); case {'blend'} imgOverlay = imfuse(I1,I2,'blend'); case {'montage'} imgOverlay = imfuse(I1,I2,'montage'); end % Display the composite image if nargout > 0 hImage = imshow(imgOverlay, 'Parent', hAxes); else imshow(imgOverlay, 'Parent', hAxes); end holdState = get(hAxes,'NextPlot'); % store the state for 'hold' before changing it set(hAxes, 'NextPlot', 'add'); %============ % Plot points %============ % Calculate the offsets needed to adjust plot after images were fused offset1 = fliplr(I1pre); offset2 = fliplr(I2pre); if strcmp(method, 'montage') offset2 = offset2 + fliplr([0 size(I1,2)]); end matchedPoints1 = bsxfun(@plus, matchedPoints1, offset1); matchedPoints2 = bsxfun(@plus, matchedPoints2, offset2); if ~isempty(lineSpec{1}) plot(hAxes, matchedPoints1(:,1), matchedPoints1(:,2), lineSpec{1}); % marker 1 end if ~isempty(lineSpec{2}) plot(hAxes, matchedPoints2(:,1), matchedPoints2(:,2), lineSpec{2}); % marker 2 end % Plot by using a single line object with line segments broken by using % NaNs. This is more efficient and makes it easier to customize the lines. lineX = [matchedPoints1(:,1)'; matchedPoints2(:,1)']; numPts = numel(lineX); lineX = [lineX; NaN(1,numPts/2)]; lineY = [matchedPoints1(:,2)'; matchedPoints2(:,2)']; lineY = [lineY; NaN(1,numPts/2)]; plot(hAxes, lineX(:), lineY(:), lineSpec{3}); % line set(hAxes, 'NextPlot', holdState); % restore the hold state drawnow(); %========================================================================== % Input parser %========================================================================== function [matchedPoints1, matchedPoints2, method, lineSpec, hAxes] = ... parseInputs(I1, I2, matchedPoints1, matchedPoints2, varargin) % do only basic image validation; let padarray and imfuse take care of % the rest validateattributes(I1,{'numeric','logical'},{'real','nonsparse',... 'nonempty'},mfilename,'I1',1) validateattributes(I2,{'numeric','logical'},{'real','nonsparse',... 'nonempty'},mfilename,'I2',2) matchedPoints1 = parsePoints(matchedPoints1, 1); matchedPoints2 = parsePoints(matchedPoints2, 2); if size(matchedPoints1,1) ~= size(matchedPoints2,1) error(message('vision:showMatchedFeatures:numPtsMustMatch')); end % Process the rest of inputs parser = inputParser; parser.FunctionName = mfilename; parser.addOptional('Method', 'falsecolor', @checkMethod); parser.addParameter('PlotOptions', {'ro','g+','y-'}, @checkPlotOptions); parser.addParameter('Parent', [], ... @vision.internal.inputValidation.validateAxesHandle); % Parse inputs parser.parse(varargin{:}); % Calling validatestring again permits easy handling of partial string matches method = validatestring(parser.Results.Method,... {'falsecolor','blend','montage'},mfilename,'Method'); lineSpec = parser.Results.PlotOptions; hAxes = newplot(parser.Results.Parent); %========================================================================== function points=parsePoints(points, ptsInputNumber) fcnInputVarNumber = 2 + ptsInputNumber; varName = ['matchedPoints', num2str(ptsInputNumber)]; if ~isa(points, 'vision.internal.FeaturePoints') && ~isa(points, 'MSERRegions') validateattributes(points,{'int16', 'uint16', 'int32', 'uint32', ... 'single', 'double'}, {'2d', 'nonsparse', 'real', 'size', [NaN 2]},... mfilename, varName, fcnInputVarNumber); else points = points.Location; end points = double(points); %========================================================================== function tf = checkMethod(method) validatestring(method,{'falsecolor','blend','montage'},mfilename,'Method'); tf = true; %========================================================================== function tf = checkPlotOptions(options) validateattributes(options,{'cell'}, {'size', [1 3]},... mfilename, 'PlotOptions'); validateattributes(options{1},{'char'},{},mfilename,'MarkerStyle1'); validateattributes(options{2},{'char'},{},mfilename,'MarkerStyle2'); validateattributes(options{3},{'char'},{},mfilename,'LineStyle'); % Now check valid strings checkMarkerStyle(options{1}, 1); checkMarkerStyle(options{2}, 2); checkLineStyle(options{3}); tf = true; %========================================================================== function style=eliminateColorSpec(style) colorSpec = cell2mat({'r','g','b','c','m','y','k','w'}); % Color can be specified only at the beginning or end of the style string. % Look for only one specifier. If color was specified twice, it will cause % a failure in later stages of parsing if ~isempty(style) if isempty(strfind(colorSpec, style(1))) % try the other end if ~isempty(strfind(colorSpec, style(end))) style(end) = []; end else style(1) = []; end end %========================================================================== function checkMarkerStyle(style, id) style = strtrim(style); % remove blanks from either end of the string style = strtrim(eliminateColorSpec(style)); % pull out valid color spec if isempty(style) % permit empty marker style, which amounts to marker not being displayed else markerSpec = {'+','o','*','.','x','square','s','diamond','d','^',... 'v','>','<','pentagram','p','hexagram','hImage'}; try validatestring(style,markerSpec); catch %#ok<CTCH> error(message('vision:showMatchedFeatures:invalidMarkerStyle',id)); end end %========================================================================== function checkLineStyle(style) style = strtrim(style); % remove blanks from either end of the string style = strtrim(eliminateColorSpec(style)); % pull out valid color spec if isempty(style) % permit empty line style thus letting plot use its default settings else lineSpec = {'-','--',':','-.'}; try validatestring(style,lineSpec); catch %#ok<CTCH> error(message('vision:showMatchedFeatures:invalidLineStyle')); end end