Ask Your Question
0

How to use Mat as a C++ member correctly?

asked 2015-03-02 02:21:29 -0500

Richard Y. Hayashi gravatar image

updated 2015-03-02 18:40:20 -0500

Using VS 2012 with OpenCV 2.4.10

I am grabbing an image from a Basler camera in a thread class in my DLL and and converting it to an OpenCV Mat. I then pass it to an CameraImage class that is created using new and add it to a queue where another thread writes it out to disk and deletes the instance.

I find that whether I assign, clone(), copyTo(), or create/memcpy image to CameraImage.mImage when I delete the instance of CameraImage, mImage does not delete the image data and around the 86th image the create Mat throws an exception which means that it cannot allocate the memory for the new image. I thought the smart pointer takes care of the data memory allocation/deallocation automatically as well as refcount. I even call mImage.release() in the CameraImage destructor. I have used assert() to check on the refcount(s) (not shown).

Image Grab function called by thread

void CImageWriter::Grab()
{
   ...
   mCamera.GrabImage(result);

   cv::Mat image;

   ConvertToMat(image, result.GetImage());
   CameraImage *cameraImage = new CameraImage(image);

   // Send it to the write queue thread.
   mWriteQueueThread.QueueToWrite(cameraImage);
   ...
}

Converting to Mat

void CImageWriter::ConvertToMat(cv::Mat &image, Pylon::IImage &pylonImage, ImageRotation rotateDegrees)
{
   Pylon::CImageFormatConverter converter;
   Pylon::CPylonImage target;

   converter.OutputPixelFormat = Pylon::PixelType::PixelType_BGR8packed;
   converter.OutputBitAlignment = Pylon::OutputBitAlignmentEnums::OutputBitAlignment_MsbAligned;
   converter.Convert(target, pylonImage);

   image.create(target.GetHeight(), target.GetWidth(), CV_8UC3);
   // copies from Result.Buffer into img 
   memcpy(image.ptr(), target.GetBuffer(), 3*target.GetWidth()*target.GetHeight());

   Rotate(image, image, rotateDegrees);
}

The Image Class

class CameraImage
{
public:
    CameraImage(cv::Mat &image);
    ~CameraImage();

    void WriteToDisk(void);

protected:
    cv::Mat mImage;
};


 CameraImage::CameraImage(cv::Mat &image)
 {
    mImage = image; or mImage = image.clone();  or  image.copyTo(mImage); 
    or
    mImage.create(image.rows, image.cols, CV_8UC3);
    memcpy(mImage.ptr(), image.ptr(), 3 * image.rows * image.cols);
 }

 CameraImage::~CameraImage()
 {
    mImage.release();
 }

Is this the proper way to use Mat as a C++ member? What am I doing wrong?

edit retag flag offensive close merge delete

Comments

Hello I have a similar problem with opencv. I try to keep in Memory some pointer to Mat object in a buffer. For freed my Mat object, i use mat->release then à delete on this ptr. When I let the delete the program crash. When I suppress the delete it creates a Memory leak. Could you please propose a solution?

Benlag06 gravatar imageBenlag06 ( 2015-09-21 13:27:48 -0500 )edit

1 answer

Sort by » oldest newest most voted
2

answered 2015-03-02 05:02:12 -0500

thdrksdfthmn gravatar image

I would suggest you to do

CameraImage::CameraImage(const cv::Mat &image) : mImage(image) {}

The idea of using clone or copyTo is when you are having a Mat parameter (not const) that you want not to change, and you do some modifications on it (like conversions, or drawings, or stuffs like that).

Please review the docs about Mat, especially = operator

edit flag offensive delete link more

Comments

Yes.. the clone creates a hard copy of Mat. You probably want to use the = operator, that will just assign pointers to the same object.

Pedro Batista gravatar imagePedro Batista ( 2015-03-02 05:24:00 -0500 )edit

I gave your suggestion a try, but it is still giving me an "Unknown Exception" when I go to create a new Mat for the around 75th image grabbed now. I first tried just creating the CameraImage then deleting it without putting it in the queue. Then when I put it in the queue it gives an "Unhandled Exception" with "Access violation reading location xxx" when it comes to writing it to disk. Either way it give me Unknow Exception on create.

Richard Y. Hayashi gravatar imageRichard Y. Hayashi ( 2015-03-02 05:35:52 -0500 )edit

By the way, I was able to write the Mat image out to disk in the grab thread without any problems, but it dies after a certain number of images, and depending of course on the size of the image, when it comes to adding it to an object and putting it in the queue to be written later.

Richard Y. Hayashi gravatar imageRichard Y. Hayashi ( 2015-03-02 05:43:11 -0500 )edit

Ok, I don't get it anymore, what are you trying to do? storing Mats into a queue? How many do you need? What resolution do they have? What are you trying to do? Maybe it is because you have no more RAM?

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-03-02 06:15:38 -0500 )edit

I am trying to store the Mat in an object placed in a queue to be written out to disk by another thread. The Write thread's job is to just write the image to disk, and delete the object with the Mat, since writing to disk may take longer than getting the next image/frame depending on fps, size, and image file type. Right now I am writing the the colour image, 4608 x 1400 at 2 fps, as a BMP which is written to disk at about 200 ms so the queue does not fill up.

It would seem that the Mat does not deallocate the data memory when the container object is deleted, since I keep running into an Unknown Exception on creating the 80th or so grabbed image. What I meant to say was, I do not get this problem when I write the image immediately ...(more)

Richard Y. Hayashi gravatar imageRichard Y. Hayashi ( 2015-03-02 18:09:04 -0500 )edit

UPDATE

I got more detail of the "Unknown Exception" by using cv::Exception at Mat creation and it confirmed what I thought: Failed to allocate 45453316 bytes in function cv::OutOfMemoryError. This is using just the creating and deleting of CameraImage in the Grab function and not placing it in the queue.

Richard Y. Hayashi gravatar imageRichard Y. Hayashi ( 2015-03-02 21:27:02 -0500 )edit

Then I think your problem is at writing the image on disk... How do you delete the element in the queue?

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-03-03 02:18:56 -0500 )edit
1

How I would do it:

View the CameraImage class as the owner of the cv::Mat object.

In the Grab-method use CameraImage *cameraImage = new CameraImage(image.clone()); to make an independent copy.

The CameraImage constructor can simply be (what @thdrksdfthmn suggests) CameraImage::CameraImage(const cv::Mat &image) : mImage(image) {}, nothing more, no need to memcpy or release() it in the destructor.

The only thing is that your CameraImage class must be deleted (with delete), but you probably already did that where it writes to disk.

boaz001 gravatar imageboaz001 ( 2015-03-03 08:10:24 -0500 )edit

Thank you everyone for your help and suggestions. Merci @thdrksdfthmn. I found where the problem was just like @thdrksdfthmn had posted. I made the mistake of not making the destructor of the base class of CameraImage, which I forgot to add in my post, a virtual destructor; I'm using a pointer to the base class when I delete the object. It is now working fine. I hope the code I have posted can be of help to others.

Richard Y. Hayashi gravatar imageRichard Y. Hayashi ( 2015-03-04 01:58:38 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2015-03-02 02:21:29 -0500

Seen: 2,219 times

Last updated: Mar 02 '15