のどあめ

ググってもなかなか出てこなかった情報を垂れ流すブログ。

VisualStudio 2012のデバッグ中にOpenCVのcv::Matの中身を確認する方法

私はVisualStudioの拡張機能であるImageWatchを使っています。
ImageWatchはOpenCVで読み込んだ画像などをデバッグ中に可視化する事ができます。
ImageWatchはとても便利なのですが、大きなCV_64Fの二次元のcv::Mat型などの中身を見るのには不便です。

以下のようにコマンドウィンドウを用いる方法もありますが、

>? ((double*)mat.data)[mat.rows*4+2]

ある要素(上の場合は(4,2))を見たいだけならいいのですが、
内容をずらっと見たい時に不便ですし、何より入力するのが面倒です。

今回はImageWatchのnatvisを改造して、この問題に対処したいと思います。

natvisとは

公式ページによると、

  • VisualStudioデバッガの表示をカスタマイズするフレームワーク
  • 昔はautoexp.datがやっていた。
  • xml形式でかけるのでわかりやすい

ということみたいです。
ImageWatchを入れると、cv::Matのデバッグ表示が変わるのはこのためです。
今回はImageWatchのnatvisを改造してcv::Matの中身を一緒に表示させるようにします。

natvisの改造

ImageWatchのOpenCV関連のnatvisファイルはデフォルトで、

C:\Users\username\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\謎文字列?\ImageWatchOpenCV.natvis

に保存されています。

この中の以下のように改造します。
※念のためバックアップは取ってください。

・・・
  <Type Name="cv::Mat">
    <AlternativeType Name="cv::Mat_&lt;*&gt;"/>
    <DisplayString Condition="(flags&amp;7)==0">{{UINT8, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==1">{{INT8, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==2">{{UINT16, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==3">{{INT16, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==4">{{INT32, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==5">{{FLOAT32, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==6">{{FLOAT64, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <DisplayString Condition="(flags&amp;7)==7">{{USER, {((flags&amp;0xfff)&gt;&gt;3)+1} x {cols} x {rows}}}</DisplayString>
    <Expand>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==0">
        <DisplayString>UINT8</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==1">
        <DisplayString>INT8</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==2">
        <DisplayString>UINT16</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==3">
        <DisplayString>INT16</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==4">
        <DisplayString>INT32</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==5">
        <DisplayString>FLOAT32</DisplayString>
      </Synthetic>
      <Synthetic Name="[type]" Condition="(flags&amp;7)==6">
        <DisplayString>FLOAT64</DisplayString>
      </Synthetic>
      <Item Name="[channels]">((flags&amp;0xfff)&gt;&gt;3)+1</Item>
      <Item Name="[width]">cols</Item>
      <Item Name="[height]">rows</Item>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 0 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 8U -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned char*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 1 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 8S -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((char*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 2 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 16U -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((unsigned short*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 3 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 16S -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((short*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 4 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 32S -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((int*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 5 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 32F -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((float*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
		<Synthetic Name="[detail]" Condition="dims == 2 &amp;&amp; (flags &amp; 7) == 6 &amp;&amp; (flags &amp; 16384) == 16384"><!-- 64F -->
			<Expand>
				<Synthetic Name="row[0]" Condition="rows &gt; 0">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+0*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[1]" Condition="rows &gt; 1">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+1*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[2]" Condition="rows &gt; 2">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+2*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[3]" Condition="rows &gt; 3 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+3*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[4]" Condition="rows &gt; 4 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+4*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[5]" Condition="rows &gt; 5 &amp;&amp; rows &lt; 7">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+5*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="..." Condition="rows &gt; 6"><DisplayString> </DisplayString></Synthetic>  
				<Synthetic Name="row[-3]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+(rows-3)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-2]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+(rows-2)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
				<Synthetic Name="row[-1]" Condition="rows &gt; 6">
					<Expand><IndexListItems><Size>cols</Size><ValueNode>(&amp;((double*)data)[$i+(rows-1)*cols])</ValueNode></IndexListItems></Expand></Synthetic>
			</Expand>
		</Synthetic>
      <Item Name="[stride]">step.p[0]</Item>
      <Item Name="[continous]">(flags &amp; 16384) == 16384</Item>
      <Item Name="[submatrix]">(flags &amp; 32678) == 32678</Item>
      <Item Name="[refcount]">refcount</Item>
	  <Item Name="[data]">data</Item>
    </Expand>
  </Type>
・・・

natvisファイルではループ等は使えないため、ゴリゴリ書いています。
今回はcv::Matの中身を6行(上3行、下3行)を見るためのnatvisを(ゴリゴリ)書きました。
他にも色々と可視化したほうがいいような気もしますが、
私個人としてはcv::Matさえ確認できればそれで良いのでこのままです。

必要なら自分で足してください。


これを適用すると、こんな感じになります。
f:id:ykicisk:20131106140258p:plain

大きな行列の中身を見るときに便利になりました!
めでたしめでたし。