function frames = retriangulate(ipr)
	% frames = retriangulate(ipr)
	% identify particles and retriangulate their position from residual
	% RGB images
	%
	%
	% Output:
    %   frames, a 1 x 3 structure containing the following fields:
    %
    %   n_part      1 x 1       number of particles reconstructed
    %   re_part     3 x N       positions of particles reconstructed at time t
    %   im_matched  2 x N x 3   image space coordinates of reconstructed particles
    %   im_res      3 x N       image space residual of reconstructed particles
    %   im_idx      3 x N       index of particle in im_part_ary
    %   c_idx       3 x N       indices of cameras particle was matched in
    %

	%% options
    mopts           = ipr.opts.matching;
	mopts.adjacency = ipr.setup.adjacency;
	mopts.re_lim	= ipr.setup.re_bb_lim;
	%b_verbose		= ipr.opts.b_verbose;
	%indent			= ipr.opts.indent;
	n_cameras		= ipr.n_cameras;
	camera			= ipr.setup.camera;
    
    %% search particles in image
	im_part_ary			= cell(3, n_cameras);
	im_bright_ary		= cell(3, n_cameras);
	n_2D_part			= zeros(3, n_cameras);
	for ic = 1 : n_cameras
		%% identify particle images
		[im_part, im_bright]= rgb_find_particles(camera(ic), ipr.img_res{ic}, mopts.img_threshold);
		im_part_ary(:,ic)	= im_part;
		im_bright_ary(:,ic) = im_bright;
		n_2D_part(:,ic)		= cellfun(@(x) size(x, 2), im_part);
		fprintf('[C%3d] %d R, %d G, %d B\n', ic, n_2D_part(:,ic));
	end
	
	%% triangulate particles
	frames				= cell(1, 3);
	for rgb	= 1 : 3
		fprintf('triangulating at time step %d ...\n', rgb);
		R				= struct();
		[R.re_part, R.im_matched, R.im_res, R.im_idx, R.c_idx]	= ...
			match3d3c(camera, im_part_ary(rgb,:), mopts);
		R.n_part		= size(R.re_part,2);
		frames{rgb}		= R;
    end
    frames              = cell2mat(frames);
end