VHS filter matlab script

April 23rd, 2014

A while ago I found this killer tutorial for apply a VHS look to an image. I was able to whip up a little matlab filter to do it procedurally. Here’s the vhs function:


function V = vhs(im,varargin)
  % VHS Apply a VHS filter to an image
  %
  % V = vhs(im)
  % V = vhs(im,'ParameterName',ParameterValue,...)
  %
  % Inputs:
  %   im  h by w by c image
  %   Optional:
  %     'VerticalLoop' followed by whether to loop the bent strip vertically
  %     over time and output a sequence of images.
  % Output:
  %   V  h by w by c by f image of (f long sequence of images)
  %

  looping = false;
  % Map of parameter names to variable names
  params_to_variables = containers.Map( {'VerticalLoop'},{'looping'});
  v = 1;
  iter = 1;
  while v <= numel(varargin)
    param_name = varargin{v};
    if isKey(params_to_variables,param_name)
      assert(v+1<=numel(varargin));
      v = v+1;
      % Trick: use feval on anonymous function to use assignin to this workspace
      feval(@()assignin('caller',params_to_variables(param_name),varargin{v}));
    else
      error('Unsupported parameter: %s',varargin{v});
    end
    v=v+1;
  end

  if looping 
    strip_top = 1;
  else
    strip_top = ceil(0.4*size(im,1));
  end

  first = 1;
  while true

    % http://mikeyjam.buzznet.com/user/journal/12237761/tutorial-getting-vhs-tv-effect/
    A = im;
    B = im;
    C = im;
    D = im;
    % exclusion blend like photoshop
    % http://www.deepskycolors.com/archive/2010/04/21/formulas-for-Photoshop-blending-modes.html
    ex = @(T,B) 0.5 - 2.*(T-0.5).*(B-0.5);
    % kill color channels
    A(:,:,1) = 0;
    B(:,:,2) = 0;
    C(:,:,3) = 0;
    % Shift color layers
    nudge = @(f) ceil(f*rand(1)*size(im,2));
    A = A(:,mod(nudge(0.02)+(1:end)-1,end)+1,:);
    B = B(:,mod(nudge(0.02)+(1:end)-1,end)+1,:);
    C = C(:,mod(nudge(0.02)+(1:end)-1,end)+1,:);
    A = A(mod(nudge(0.005)+(1:end)-1,end)+1,:,:);
    B = B(mod(nudge(0.005)+(1:end)-1,end)+1,:,:);
    C = C(mod(nudge(0.005)+(1:end)-1,end)+1,:,:);
    % exclusion blend colored layers and alpha blend with original

    F = D+0.3*(ex(ex(C,B),A)-D);
    N = rand(size(im));

    % inverse mapping function
    bend_w = (2*rand(1)-1)*5;
    bend = @(x,u) [mod(x(:,1)+(1-x(:,2)/max(x(:,2))).^2*bend_w,max(x(:,1))) x(:,2)];
    % maketform arguments
    ndims_in = 2;
    ndims_out = 2;
    tdata = [];
    tform = maketform('custom', 2,2, [], bend, tdata);

    % Bend strip
    strip_h = ceil(1/4*size(im,1));
    strip = mod(strip_top+(1:strip_h)-1,size(im,1))+1;
    F(strip,:,:) = imtransform(F(strip,:,:), tform);

    % overlay gray line
    ol= @(T,B) (T>0.5).*(1-(1-2.*(T-0.5)).*(1-B))+(T<=0.5).*((2.*T).*B);
    G = repmat(0.75,[numel(-1:1) size(F,2) size(F,3)]);
    F(mod(strip_top+(-1:1)-1,size(F,1))+1,:,:) = ...
      ol( F(mod(strip_top+(-1:1)-1,size(F,1))+1,:,:),G);


    % overlay horizontal lines
    L = zeros(size(F));
    L(1:4:end,:,:) = 1;
    L(2:4:end,:,:) = 1;
    L = imfilter(L,fspecial('gaussian',[5 5],1.5),'replicate');
    F = ol(F,L);

    % Fade in random color gradient
    m = rand(1,2)*2-1;
    R = bsxfun(@plus,m(1)*(1:size(F,2)),m(2)*(1:size(F,1))');
    R = (R-min(R(:)))./(max(R(:))-min(R(:)));
    R = gray2rgb(R,colormap(jet(255)));
    F = F+0.05*(ol(F,R)-F);

    % soft light
    sl = @(T,B) (B>0.5).*(1-(1-T).*(1-(B-0.5))) + (B<=0.5).*(T.*(B+0.5));
    F = F + 0.15*(sl(F,N)-F);

    % sharpen
    V(:,:,:,iter) = imsharpen(F);

    %imshow(V(:,:,:,iter));
    %drawnow;

    strip_top = strip_top+round(0.057*size(im,1));
    iter = iter+1;
    if ~looping || strip_top > size(im,1)
      break;
    end

  end
end

Doing it procedurally is cool because you can generate a whole animation of them. Like this:

kavinsky vhs animation

or this

rioux vhs animation

or this

dylan vhs animation

“Bijective mappings with generalized barycentric coordinates: a counterexample” published in JGT

April 22nd, 2014

bijective barycentric coordinates counterexample

My little proof that any generalized barycentric coordinates can create a non-injective mapping (i.e. you give me a scheme for weights then I can give you a configuration that creates a deformation with flips) was published in the Journal of Graphics Tools. If you don’t have access, then why not just take a look at the tech report. The proofs are just slightly different, only amounting to satisfying different tastes.

Qt application launched in background, not stealing focus

April 22nd, 2014

We’re building a Qt executable (not an app bundle) with cmake. When running it feels like an application, dock icon, menu bar and all, but when it’s first launched from the command line with something like:

./my_app_exec

The application opens behind the terminal. The focus stays with the terminal. This was frustrating because then each time I launch the application I need to CMD+SHIFT+TAB to get to the application.

Here’s a dirty hack workaround. In my main function just after main_window.show() or whatever I add a bit of apple-specific applescript to do the alt tabbing for me:

mainWin->show();
#ifdef __APPLE__
    system("osascript -e 'tell application \"System Events\" "
      "to keystroke tab using {command down, shift down}'");
#endif

No `gdb` in OS X 10.9, Mavericks

April 21st, 2014

Use lldb, even works with binaries compiled with gcc.

Matlab’s mex can’t find std headers

April 18th, 2014

Trying to compile the ecos mex files I ran into the following errors:

In file included from /opt/local/lib/gcc47/gcc/x86_64-apple-darwin13/4.7.3/include-fixed/syslimits.h:7:0,
                 from /opt/local/lib/gcc47/gcc/x86_64-apple-darwin13/4.7.3/include-fixed/limits.h:34,
                 from ../external/SuiteSparse_config/SuiteSparse_config.h:45,
                 from ../external/ldl/include/ldl.h:11,
                 from ../external/ldl/src/ldl.c:157:
/opt/local/lib/gcc47/gcc/x86_64-apple-darwin13/4.7.3/include-fixed/limits.h:169:61: error: no include path in which to search for limits.h
In file included from ../external/ldl/include/ldl.h:11:0,
                 from ../external/ldl/src/ldl.c:157:
../external/SuiteSparse_config/SuiteSparse_config.h:46:20: fatal error: stdlib.h: No such file or directory
compilation terminated.

    mex: compile of ' "../external/ldl/src/ldl.c"' failed.

Turns out this has nothing to do with ecos, rather I had upgraded my OS since installing matlab. I need to replace 10.7 with 10.9 in my /Applications/MATLAB_R2013b.app/bin/mexopts.sh file. Then everything compiled fine.

The offending flags were:

-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/ -mmacosx-version-min=10.7

And the correct versions were:

-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/ -mmacosx-version-min=10.9

Interactive image comparison with sliding splitter in MATLAB

April 16th, 2014

Wojciech Jarosz has nice interactive comparisons on his website. I wanted to have a similar feature in matlab. Here’s a little function to do just that:

function [ph,ih] = sliding_comparison(A,B)
  % SLIDING_COMPARISON Create a figure which allows the user to mouse over and
  % move a sliding splitter to compare two images interactively.
  %
  % Inputs:
  %   A  h by w by c left image (should be double)
  %   B  h by w by c right image (should be double)
  % Outputs:
  %   ph  handle to plot of separator line
  %   ih  handle to image line
  %
  function C = split(A,B,x)
    x = max(min(x,size(A,2)),1);
    C = [A(:,1:round(x)-1,:) B(:,round(x):end,:)];
  end

  function onmove(src,ev)
    % get current mouse position, and remember old one
    pos=get(gca,'currentpoint');
    x = pos(1,1,1);
    if ishandle(ih) && ishandle(ph)
      set(ph,'XData',repmat(x,1,2));
      set(ih,'CData',split(A,B,x));
    else
      % Clean up
      set(gcf,'windowbuttonmotionfcn',old_onmove);
    end
    drawnow
  end

  w = size(A,2);
  h = size(A,1);
  % `imshow` will clamp but `set(...,'CData',...)` will not
  clamp = @(X) max(min(X,1),0);
  A = clamp(A);
  B = clamp(B);

  x = w/2;
  ih = imshow(split(A,B,x));
  hold on;
    ph = plot([x;x],[0;h],'LineWidth',2);
  hold off;

  old_onmove = get(gcf,'windowbuttonmotionfcn');
  set(gcf,'windowbuttonmotionfcn',@onmove);
end

So, say you have your image in im and your depth image in D then:

sliding_comparison(im,repmat(D,[1 1 3]))

Then you’ll see something like:

octopus-sliding-splitter-image-comparison.gif

Enlarge matlab axis by a specific factor

April 8th, 2014

Here’s the code I use to double or enlarge the axis of a plot window by any factor. Say 150%:

a = axis;
axis(a+1.5*[a(1:2)-(a(1)+a(2))*0.5 a(3:4)-(a(3)+a(4))*0.5]);

Matlab is stalling after every command

April 1st, 2014

I ran into a strange issue that MATLAB was stalling for a long while each time I issued a command and took a long time to execute scripts. Seems the issue was that the current directory I was working in had over 30000 files. My guess is that this was causing the parser to freak out when searching for available functions. Anyway, moving these files (some generated data) to a subfolder not in the working path fixed the issue.

Convert all .mkv files in a directory to .mp4 for ipad

March 30th, 2014

Here’s a bash “one-liner” to convert all movie files in the current directory to a format that works with the ipad. It renames the files from .mkv to .mp4.

for f in *.mkv; do ffmpeg -i $f -acodec aac -ac 2 -strict experimental -ab 160k -s 1920x1080 -vcodec copy -f mp4 -threads 0 ${f%.*}.mp4; done

Bounded biharmonic weights in Communications of the ACM

March 26th, 2014

bbw in cacm

Our 2011 SIGGRAPH paper, “Bounded Biharmonic Weights for Real-Time Deformation”, is featured in the Research Highlights section of the April 2014 edition of the computer science magazine Communications of the ACM. This version of the paper has some updates that would have been anachronistic in the original paper and a more accessible introduction (at least we think so). The paper is prefaced by a technical perspective letter by Joe Warren.