New answer
We start from constructing a easy way to typeset multiple nodes at the same position:
\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{shapes.callouts}
\begin{document}
% The goal is to translate
% \overlaynode<red,blue>{hallo};
% into
% \node[red]{hallo};
% \node[blue]{hallo};
\makeatletter
\def\overlaynode<#1>#2;{
\gdef\stacknodecommonpart{#2}
\pgfkeys{/typeset node/.list={#1}}
% we are lazy
% pgfkeys will translate
% \pgfkeys{/typeset node/.list={red,blue}}
% into
% \pgfkeys{/typeset node=red}
% \pgfkeys{/typeset node=blue}
}
\pgfkeys{
/typeset node/.code={
\edef\pgf@marshal{\noexpand\node[#1]\stacknodecommonpart;}
\pgf@marshal
}
}
\tikz{
\overlaynode<red,{blue,xshift=1}>{{Hello}}; % notice the nested {{}}
% \overlaynode<red,{blue,xshift=1}>[]{Hello}; % workaround
\overlaynode<red,{blue,rotate=5}>at(1,0)[draw]{from};
\overlaynode<red,{blue,scale=1.1}>[circle]at(2,0)[draw]{the};
\overlaynode<red,{blue,opacity=.5}>[fill=yellow!50]at(3,0){other};
\overlaynode<{red,rectangle callout,fill},{blue,ellipse callout,draw}>at(4,0){side};
}

- Each item in
< > will lead to an individual node. In the example above, red gives you a red node and {blue,rotate=5} gives you a blue, rotated node.
- you can set global property in
[ ]. In the example above, [draw] will draw the borders of all nodes. Hence you can see both the red rectangle and the blue, rotated rectangle.
So one can do multiple callout without pain: since each callout is itself a node, there will be no problem combining absolute and relative and shorten.
\tikz{
\overlaynode<
{fill=red,callout absolute pointer=(45:2)},
{fill=yellow,callout absolute pointer=(135:2),callout pointer shorten=1cm},
{fill=green,callout relative pointer=(-135:2),callout pointer width=.5cm},
{fill=blue,callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout,text=white]
at(0,0){can you}
;
}

Now we come to the exciting part.
To depict the contour of all nodes, we need to call \overlaynode twice: once with draw and once with fill.
\def\overlaynodedrawfill{\pgfutil@ifnextchar[{\overlaynodedrawfill@opt}{\overlaynodedrawfill@opt[]}}
\def\overlaynodedrawfill@opt[#1]<#2>#3;{
\begin{scope}[transparency group,draw=black,fill=white,line cap=round,line join=round,#1]
\pgfmathsetmacro\pgflinewidthdouble{2\pgflinewidth}
\overlaynode<#2>[draw=pgfstrokecolor,line width=\pgflinewidthdouble]#3;
\overlaynode<#2>[fill=pgffillcolor]#3;
\end{scope}
}
\tikz{
\overlaynodedrawfill[draw=cyan,fill=magenta,opacity=.5]<
{callout absolute pointer=(45:2)},
{callout absolute pointer=(135:2),callout pointer shorten=1cm},
{callout relative pointer=(-135:2),callout pointer width=.5cm},
{callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout]
at(0,0){hear me}
;
}

Notice that there is opacity=.5, but it looks like just one node!
ALso notice that we put draw=cyan,fill=magenta,opacity=.5 at the beginning and put rectangle callout at the end.
If you put draw=cyan at the end, then all nodes will be drawn and the result will not be the contour. (However, you still can do so if you know what are you doing.)
Even more tricks
\tikz{
\overlaynodedrawfill<
{cloud callout,callout absolute pointer=(90:2),inner sep=-20},
{rectangle callout,callout absolute pointer=(210:2),minimum height=30},
{ellipse callout,callout absolute pointer=(-30:2)}
>
at(0,0){nice to meet you}
;
}

\tikz{
\overlaynodedrawfill<
{starburst},
{cloud,inner sep=-10}
>
at(0,0){where you been}
;
}

\usetikzlibrary{shapes.arrows}
\tikz{
\overlaynodedrawfill[arrow box,text opacity=0,minimum height=50,,minimum width=50,inner xsep=-10]<
{rotate=22.5},
{rotate=45},
{rotate=67.5},
{text opacity=1}
>
at(0,0){I can}
;
}

Full code
\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{shapes.callouts}
\begin{document}
% The goal is to translate
% \overlaynode<red,blue>{hallo};
% into
% \node[red]{hallo};
% \node[blue]{hallo};
\makeatletter
\def\overlaynode<#1>#2;{
\gdef\stacknodecommonpart{#2}
\pgfkeys{/typeset node/.list={#1}}
% we are lazy
% pgfkeys will translate
% \pgfkeys{/typeset node/.list={red,blue}}
% into
% \pgfkeys{/typeset node=red}
% \pgfkeys{/typeset node=blue}
}
\pgfkeys{
/typeset node/.code={
\edef\pgf@marshal{\noexpand\node[#1]\stacknodecommonpart;}
\pgf@marshal
}
}
\tikz{
\overlaynode<red,{blue,xshift=1}>{{Hello}}; % notice the nested {{}}
% \overlaynode<red,{blue,xshift=1}>[]{Hello}; % workaround
\overlaynode<red,{blue,rotate=5}>at(1,0)[draw]{from};
\overlaynode<red,{blue,scale=1.1}>[circle]at(2,0)[draw]{the};
\overlaynode<red,{blue,opacity=.5}>[fill=yellow!50]at(3,0){other};
\overlaynode<{red,rectangle callout,fill},{blue,ellipse callout,draw}>at(4,0){side};
}
\tikz{
\overlaynode<
{fill=red,callout absolute pointer=(45:2)},
{fill=yellow,callout absolute pointer=(135:2),callout pointer shorten=1cm},
{fill=green,callout relative pointer=(-135:2),callout pointer width=.5cm},
{fill=blue,callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout,text=white]
at(0,0){can you}
;
}
\def\overlaynodedrawfill{\pgfutil@ifnextchar[{\overlaynodedrawfill@opt}{\overlaynodedrawfill@opt[]}}
\def\overlaynodedrawfill@opt[#1]<#2>#3;{
\begin{scope}[transparency group,draw=black,fill=white,line cap=round,line join=round,#1]
\pgfmathsetmacro\pgflinewidthdouble{2\pgflinewidth}
\overlaynode<#2>[draw=pgfstrokecolor,line width=\pgflinewidthdouble]#3;
\overlaynode<#2>[fill=pgffillcolor]#3;
\end{scope}
}
\tikz{
\overlaynodedrawfill[draw=magenta,fill=cyan,opacity=.5]<
{callout absolute pointer=(45:2)},
{callout absolute pointer=(135:2),callout pointer shorten=1cm},
{callout relative pointer=(-135:2),callout pointer width=.5cm},
{callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout]
at(0,0){hear me}
;
}
\tikz{
\overlaynodedrawfill<
{cloud callout,callout absolute pointer=(90:2),inner sep=-20},
{rectangle callout,callout absolute pointer=(210:2),minimum height=30},
{ellipse callout,callout absolute pointer=(-30:2)}
>
at(0,0){nice to meet you}
;
}
\tikz{
\overlaynodedrawfill<
{starburst},
{cloud,inner sep=-10}
>
at(0,0){where you been}
;
}
\usetikzlibrary{shapes.arrows}
\tikz{
\overlaynodedrawfill[arrow box,text opacity=0,minimum height=50,minimum width=50,inner xsep=-10]<
{rotate=22.5},
{rotate=45},
{rotate=67.5},
{text opacity=1}
>
at(0,0){I can}
;
}
\end{document}
Old answer
THe idea is [draw,black,line width=.8pt,postaction={fill,white}].
\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{automata,shapes,arrows}
\makeatletter
\tikzset{
expand me/.style={#1},
multiple absolute pointers/.style args={#1[#2]#3#4}{
insert path={
\foreach \qrr@tikz@calloutabsolutepointer in {#3} {
\pgfextra
\expandafter\pgfutil@ifnextchar\expandafter[%
\expandafter\qrr@tikz@parse@calloutabsolutepointer\expandafter{%
\expandafter\qrr@tikz@parse@calloutabsolutepointer\expandafter[\expandafter]\expandafter}\qrr@tikz@calloutabsolutepointer\@qrr@tikz@parse@calloutabsolutepointer
\endpgfextra
node[#2, shape/.expanded=\tikz@shape\space callout, expand me/.expanded=\qrr@tikz@calloutabsolutepointer@options, callout absolute pointer={(\qrr@tikz@calloutabsolutepointer@)}] {#4}
}
\pgfextra
\def\pgf@tempa{#1}
\pgfutil@in@*{#1}
\ifpgfutil@in@\else
\pgfkeysalso{insert path={node[#2] {#4}}}
\fi
\endpgfextra}}}
\def\qrr@tikz@parse@calloutabsolutepointer[#1]#2\@qrr@tikz@parse@calloutabsolutepointer{%
\gdef\qrr@tikz@calloutabsolutepointer@options{#1}%
\gdef\qrr@tikz@calloutabsolutepointer@{#2}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[node distance=2cm, auto]
\node[state,initial] (s0) {$s_0$};
\node[state] (s1) [right of=s0] {$s_1$};
\node[state,accepting] (s2) [right of=s1] {$s_2$};
\path[->]
(s0) edge node {a} (s1)
(s1) edge node {c} (s2)
edge [loop above] node {b} ();
\path[multiple absolute pointers={
[fill=green!20, text width=2.1cm, below of=s0]
{
{[draw,line width=.8pt]s1.south},%
{[draw,line width=.8pt]s2.south},%
{[draw,line width=.8pt]s0.south},%
[fill=magenta]s1.south,%
[fill=yellow]s2.south,%
[fill=cyan]s0.south%
}
{Each circle is a \emph{state} of the automaton}
}];
\end{tikzpicture}
\end{document}

draw,black,linewidth=.8pt, postaction={fill,white}will work. – Symbol 1 Apr 01 '17 at 02:20