Ask Your Question

Revision history [back]

Strange memory leak using CvMat structure

Dear all,

I've tried to modify the cvShowImageHWND in opencv/modules/highgui/src/window_w32.cpp in order to show image by a HWND window specified instead of using window name. My modified one worked well until I relized it's memory leak. I found that the line cvConvertImage() causes the leak and try to prevent it from leaking memory. Can anyone help me? Actually I tried to use smart pointer cv::Ptr<cvmat> to wrap it but it raises error whenever program goes out of cvShowImageHWND scope, I guess that the data is retained for displaying after the function cvShowImageHWND done, but if I didn't free the memory, my program memory keeps increase roughly 4MB each loop. Please show me a hint or tell me what should I do

void OpenCV::cvShowImageHWND(HWND w_hWnd, const cv::Mat arr0){
        CV_FUNCNAME("cvShowImage");
        __BEGIN__;
        IplImage* arr=cvCloneImage(&(IplImage)arr0);
        SIZE size = { 0, 0 };
        int channels = 0;
        void* dst_ptr = 0;
        const int channels0 = 3;
        int origin = 0;
        CvMat stub, dst;
        cv::Ptr<CvMat> image;
        bool changed_size = false;
        BITMAPINFO* binfo;
        HDC hdc = NULL;

        if( !arr ) EXIT;
        if( !w_hWnd )
            EXIT;

        hdc = ::GetDC(w_hWnd);


        if( CV_IS_IMAGE_HDR( arr ) )
            origin = ((IplImage*)arr)->origin;

        CV_CALL( image = cv::Ptr<CvMat>(cvGetMat( arr, &stub )) );

        //image = cvGetMat( arr, &stub );
        if ( hdc )
        {

                //GetBitmapData
                BITMAP bmp;
                GdiFlush();
                HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );

                if (h == NULL) EXIT;
                if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
                EXIT;

                channels = bmp.bmBitsPixel/8;
                dst_ptr = bmp.bmBits;
         }


        if( size.cx != image->width || size.cy != image->height || channels != channels0 )
        {

            changed_size = true;

            uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
            binfo = (BITMAPINFO*)buffer;

            BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
                    CV_Assert( FALSE != bDeleteObj );

            size.cx = image->width;
            size.cy = image->height;
            channels = channels0;

            OpenCV::FillBitmapInfo( binfo, size.cx, size.cy, channels*8, channels );

            SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
        }


        cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 );
        //TODO QUYETNM This line causes memory leak!!!
        cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );

        // Image stretching to fit the window
        RECT rect;
        ::GetClientRect(w_hWnd, &rect);
        StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, binfo, DIB_RGB_COLORS, SRCCOPY );
        system("pause");
        // only resize window if needed
        ::InvalidateRect(w_hWnd, 0, 0);
        //Release resource
        cvReleaseImage(&arr);

        __END__;
    }

    void OpenCV::FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
    {
        assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));

        BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);

        memset( bmih, 0, sizeof(*bmih));
        bmih->biSize = sizeof(BITMAPINFOHEADER);
        bmih->biWidth = width;
        bmih->biHeight = origin ? abs(height) : -abs(height);
        bmih->biPlanes = 1;
        bmih->biBitCount = (unsigned short)bpp;
        bmih->biCompression = BI_RGB;

        if( bpp == 8 )
        {
            RGBQUAD* palette = bmi->bmiColors;
            int i;
            for( i = 0; i < 256; i++ )
            {
                palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
                palette[i].rgbReserved = 0;
            }
        }
    }

Strange memory leak using CvMat structure

Dear all,

I've tried to modify the cvShowImageHWND in opencv/modules/highgui/src/window_w32.cpp in order to show image by a HWND window specified instead of using window name. My modified one worked well until I relized it's memory leak. I found that the line cvConvertImage() causes the leak and try to prevent it from leaking memory. Can anyone help me? Actually I tried to use smart pointer cv::Ptr<cvmat> to wrap it but it raises error whenever program goes out of cvShowImageHWND scope, I guess that the data is retained for displaying after the function cvShowImageHWND done, but if I didn't free the memory, my program memory keeps increase increasing roughly 4MB each loop. Please show me a hint or tell me what should I do

void OpenCV::cvShowImageHWND(HWND w_hWnd, const cv::Mat arr0){
        CV_FUNCNAME("cvShowImage");
        __BEGIN__;
        IplImage* arr=cvCloneImage(&(IplImage)arr0);
        SIZE size = { 0, 0 };
        int channels = 0;
        void* dst_ptr = 0;
        const int channels0 = 3;
        int origin = 0;
        CvMat stub, dst;
        cv::Ptr<CvMat> image;
        bool changed_size = false;
        BITMAPINFO* binfo;
        HDC hdc = NULL;

        if( !arr ) EXIT;
        if( !w_hWnd )
            EXIT;

        hdc = ::GetDC(w_hWnd);


        if( CV_IS_IMAGE_HDR( arr ) )
            origin = ((IplImage*)arr)->origin;

        CV_CALL( image = cv::Ptr<CvMat>(cvGetMat( arr, &stub )) );

        //image = cvGetMat( arr, &stub );
        if ( hdc )
        {

                //GetBitmapData
                BITMAP bmp;
                GdiFlush();
                HGDIOBJ h = GetCurrentObject( hdc, OBJ_BITMAP );

                if (h == NULL) EXIT;
                if (GetObject(h, sizeof(bmp), &bmp) == 0) //GetObject(): returns size of object, 0 if error
                EXIT;

                channels = bmp.bmBitsPixel/8;
                dst_ptr = bmp.bmBits;
         }


        if( size.cx != image->width || size.cy != image->height || channels != channels0 )
        {

            changed_size = true;

            uchar buffer[sizeof(BITMAPINFO) + 255*sizeof(RGBQUAD)];
            binfo = (BITMAPINFO*)buffer;

            BOOL bDeleteObj = DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
                    CV_Assert( FALSE != bDeleteObj );

            size.cx = image->width;
            size.cy = image->height;
            channels = channels0;

            OpenCV::FillBitmapInfo( binfo, size.cx, size.cy, channels*8, channels );

            SelectObject( hdc, CreateDIBSection( hdc, binfo, DIB_RGB_COLORS, &dst_ptr, 0, 0));
        }


        cvInitMatHeader( &dst, size.cy, size.cx, CV_8UC3, dst_ptr, (size.cx * channels + 3) & -4 );
        //TODO QUYETNM This line causes memory leak!!!
        cvConvertImage( image, &dst, origin == 0 ? CV_CVTIMG_FLIP : 0 );

        // Image stretching to fit the window
        RECT rect;
        ::GetClientRect(w_hWnd, &rect);
        StretchDIBits( hdc, 0, 0, rect.right, rect.bottom, 0, 0, image->width, image->height, dst_ptr, binfo, DIB_RGB_COLORS, SRCCOPY );
        system("pause");
        // only resize window if needed
        ::InvalidateRect(w_hWnd, 0, 0);
        //Release resource
        cvReleaseImage(&arr);

        __END__;
    }

    void OpenCV::FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp, int origin )
    {
        assert( bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));

        BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);

        memset( bmih, 0, sizeof(*bmih));
        bmih->biSize = sizeof(BITMAPINFOHEADER);
        bmih->biWidth = width;
        bmih->biHeight = origin ? abs(height) : -abs(height);
        bmih->biPlanes = 1;
        bmih->biBitCount = (unsigned short)bpp;
        bmih->biCompression = BI_RGB;

        if( bpp == 8 )
        {
            RGBQUAD* palette = bmi->bmiColors;
            int i;
            for( i = 0; i < 256; i++ )
            {
                palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
                palette[i].rgbReserved = 0;
            }
        }
    }