title: JavaCV/OpenCV cvDrawContours modifies original image
body: <p>I am experimenting with JavaCV (OpenCV) and I am confused with the following behavior.
  My programm simply:</p>
  
  <ol>
  <li>Grab an image</li>
  <li>Create a grayscale version of the image (leaving the original image untouched)</li>
  <li>Threshold the grayscale image</li>
  <li>Find contours in the grayscale image (cloning the image since cvFindContours modifies the image and we want to display it as is)</li>
  <li>Draw contours <strong>on the original color image</strong></li>
  </ol>
  
  <p>The problem is that unless I clone the <code>grabbedImage</code> (see commented line), the grayscale image is modified and contours are drawn on it. Also, it is as if multiple contours are drawn on the <code>grabbedImage</code>.</p>
  
  <p>I also tried to add a sleep to the loop and it fixes the problem. Could it be that I get the same (modified) <code>grabbedImage</code> multiple time? I checked the java reference and it's different but could it be the same buffer?</p>
  
  <p>Any idea?</p>
  
  <p>Thank you</p>
  
  <pre><code>package com.mdarveau.opencvtest;
  
  import static com.googlecode.javacv.cpp.opencv_core.*;
  import static com.googlecode.javacv.cpp.opencv_imgproc.*;
  
  import com.googlecode.javacpp.Loader;
  import com.googlecode.javacv.CanvasFrame;
  import com.googlecode.javacv.FrameGrabber;
  import com.googlecode.javacv.cpp.opencv_core.CvContour;
  import com.googlecode.javacv.cpp.opencv_core.CvMemStorage;
  import com.googlecode.javacv.cpp.opencv_core.CvScalar;
  import com.googlecode.javacv.cpp.opencv_core.CvSeq;
  import com.googlecode.javacv.cpp.opencv_core.IplImage;
  import com.googlecode.javacv.cpp.opencv_objdetect;
  
  public class Demo {
  
      public static void main( String[] args ) throws Exception {
          // Preload the opencv_objdetect module to work around a known bug.
          Loader.load( opencv_objdetect.class );
  
          FrameGrabber grabber = FrameGrabber.createDefault( 1 );
          grabber.start();
  
          IplImage grabbedImage = grabber.grab();
          int width = grabbedImage.width();
          int height = grabbedImage.height();
  
          IplImage grayImage = IplImage.create( width, height, IPL_DEPTH_8U, 1 );
  
          CvMemStorage storage = CvMemStorage.create();
  
          CanvasFrame filterProbe = new CanvasFrame( "Filtered", CanvasFrame.getDefaultGamma() / grabber.getGamma() );
          CanvasFrame enhancedProbe = new CanvasFrame( "Enhanced", CanvasFrame.getDefaultGamma() / grabber.getGamma() );
  
          while ( filterProbe.isVisible() &amp;&amp; enhancedProbe.isVisible() &amp;&amp; (grabbedImage = grabber.grab()) != null ) {
              cvClearMemStorage( storage );
  
              // Convert to grayscale image...
              cvCvtColor( grabbedImage, grayImage, CV_BGR2GRAY );
              // UNCOMMENT FIXES THE PROBLEM grabbedImage = grabbedImage.clone();
  
              // Let's find some contours! but first some thresholding...
              cvThreshold( grayImage, grayImage, 128, 255, CV_THRESH_BINARY );
  
              // To check if an output argument is null we may call either isNull() or equals(null).
              CvSeq contour = new CvSeq( null );
              // cvFindContours modifies the image so clone it first since we want to keep the grayscale version
              cvFindContours( grayImage.clone(), storage, contour, Loader.sizeof( CvContour.class ), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE );
              while ( contour != null &amp;&amp; !contour.isNull() ) {
                  if ( contour.elem_size() &gt; 0 ) {
                      CvSeq points = cvApproxPoly( contour, Loader.sizeof( CvContour.class ), storage, CV_POLY_APPROX_DP, cvContourPerimeter( contour ) * 0.02, 0 );
                      cvDrawContours( grabbedImage, points, CvScalar.BLUE, CvScalar.BLUE, -1, 1 /*CV_FILLED*/, CV_AA );
                  }
                  contour = contour.h_next();
              }
  
              filterProbe.showImage( grayImage );
              enhancedProbe.showImage( grabbedImage );
          }
          filterProbe.dispose();
          enhancedProbe.dispose();
          grabber.stop();
      }
  }
  </code></pre>