%% Copyright 2011-2012 The MathWorks, Inc.                                 
function ReplaceCard()
% This is a simple demo to show a match & replace of the video
% data. 
% 
% To try this, 
% 1. Get a deck of playing cards with "MATLAB & Simulink" logo or print
% the file "MWqueen_crop_small.bmp" on a color printer. 
% 2. Run this script in MATLAB
% 3. Show printed queen of diamond in front of the usb web camera.
% 4. Press either 1 or 2 of your keyboard to see the image changing
% 5. Press 0 of your keyboard to reset it back to queen of diamonds
% 
% Original version created by Takuya Otani
% Senior Application Engineer, MathWorks, Japan
%

clear all; close all; clc; imaqreset;
global process_flag;
process_flag = false;

%% Define Geometric Transformation Objects
gte = vision.GeometricTransformEstimator; 
gte.Method = 'Random Sample Consensus (RANSAC)';
gte.Transform = 'Nonreflective similarity';
gte.NumRandomSamplingsMethod = 'Desired confidence';
gte.MaximumRandomSamples = 500;
gte.DesiredConfidence = 99.8;

agt = vision.GeometricTransformer;
agt.OutputImagePositionSource = 'Property';
agt.OutputImagePosition = [1 1 480 640];

halphablender = vision.AlphaBlender( ...
    'Operation', 'Binary mask', 'MaskSource', 'Input port');

%% Setup Image Acquisition
hCamera = videoinput('winvideo', 1, 'RGB24_640x480');
hCamera.ReturnedColorspace = 'rgb';
hCamera.FramesPerTrigger =  1;

% Initialization of the camera
triggerconfig(hCamera, 'manual');
start(hCamera);

%% Load reference image data (queen of diamond) Pad the image data
%% to match 480x640 dimension
ref_img = imread('MWqueen_crop_small.bmp'); 
ref_img_pad = padarray(ref_img, [140 0], 'pre'); %340x240
ref_img_pad = padarray(ref_img_pad, [0 400], 'pre');
ref_img_gray = rgb2gray(ref_img_pad);
ref_keys = detectSURFFeatures(ref_img_gray, 'MetricThreshold', 1000);
% Extract SURF Features
[ref_features  ref_validPts] = extractFeatures(ref_img_gray,  ref_keys, 'SURFSize', 64);

% Open a Figure window which accepts keyboard inputs
figure('KeyPressFcn', @keycontrol);
himg = imshow(zeros(480, 640, 3, 'uint8'));

%% image data to replace 
global rep_img_pad;

while ishandle(himg) 
    
  %% Capture data from the camera, and extrace SURF features, and descriptors
  vid_img = getsnapshot(hCamera);
  vid_img = im2single(vid_img);  vid_img_gray = rgb2gray(vid_img);
  vid_keys = detectSURFFeatures(vid_img_gray, 'MetricThreshold', 1000);
  [vid_features vid_validPts] = extractFeatures(vid_img_gray, vid_keys, 'SURFSize', 64);

  %Here, I am using a MATLAB Coder compiled version of matchFeatures
  %To speed things up. 
  %index_pairs = matchFeatures(ref_features, vid_features, 'MatchThreshold', 2);
  index_pairs = matching_fcn_mex(ref_features, vid_features, 2);

  if process_flag == true & size(index_pairs,1) > 60

    ref_matched_points = ref_validPts(index_pairs(:,1));
    vid_matched_points = vid_validPts(index_pairs(:,2));

    
    % Estimate the transformation matrix
    [tform_matrix inlierIdx] = step(gte, ...
                                    ref_matched_points.Location, ...
                                    vid_matched_points.Location);

    % peform a geometric transformation
    rep_img_trans = step(agt, rep_img_pad, tform_matrix);
    
    % Replace the card
    mask = rep_img_trans(:,:,1) > 0;
    mosaic = step(halphablender, vid_img, rep_img_trans, mask);

    set(himg, 'CData', mosaic);
  else
    set(himg, 'CData', vid_img);
  end
  
  drawnow;
end



% When keyboard is pressed, replace rep_img data.
function keycontrol(src,evnt)
global rep_img_pad;
global process_flag;

if evnt.Character == '0'
    process_flag = false;
elseif evnt.Character == '1'
    process_flag = true;
    rep_img = imread('MWJoker_crop_small.bmp');
    rep_img = im2single(rep_img);
    rep_img_pad = padarray(rep_img, [140 0], 'pre');
    rep_img_pad = padarray(rep_img_pad, [0 400], 'pre');
elseif evnt.Character == '2'
    process_flag = true;
    rep_img = imread('MWspade_crop_small.bmp');
    rep_img = im2single(rep_img);
    rep_img_pad = padarray(rep_img, [140 0], 'pre');
    rep_img_pad = padarray(rep_img_pad, [0 400], 'pre');    
end
