From 87d5cb500970e3c160f28b6738fed3c59a3039bd Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Thu, 9 Jul 2015 23:06:06 +0200 Subject: [PATCH] Bugfix: Avoid nasty memory leaks by adding a wrapper class for converting a bitmap to cv::Mat. --- .../csharp/openalpr-net/openalpr-net.cpp | 187 ++++++++++++------ 1 file changed, 124 insertions(+), 63 deletions(-) diff --git a/src/bindings/csharp/openalpr-net/openalpr-net.cpp b/src/bindings/csharp/openalpr-net/openalpr-net.cpp index 9c0c844..df279c3 100644 --- a/src/bindings/csharp/openalpr-net/openalpr-net.cpp +++ b/src/bindings/csharp/openalpr-net/openalpr-net.cpp @@ -43,29 +43,62 @@ using namespace alpr; namespace openalprnet { private ref class AlprHelper sealed + private ref class BitmapMat : IDisposable { + private: + cv::Mat* m_bitmap; + bool m_disposed; public: - static std::vector ToVector(array^ src) + BitmapMat(array^ byteArray) { - std::vector result(src->Length); - pin_ptr pin(&src[0]); - char *first(pin), *last(pin + src->Length); - std::copy(first, last, result.begin()); - return result; + this->m_bitmap = ByteArrayToMat(byteArray); } - static std::vector ToVector(array^ src) + BitmapMat(Bitmap^ bitmap) { - std::vector result(src->Length); - pin_ptr pin(&src[0]); - char* pch = reinterpret_cast(pin); - char *first(pch), *last(pch + src->Length); - std::copy(first, last, result.begin()); - return result; + this->m_bitmap = BitmapToMat(bitmap); } - static cv::Mat BitmapToMat(Bitmap^ bitmap) + BitmapMat(MemoryStream^ memoryStream) + { + this->m_bitmap = MemoryStreamBitmapToMat(memoryStream); + } + + BitmapMat(String^ filename) + { + Bitmap^ bitmap = gcnew Bitmap(filename); + this->m_bitmap = BitmapToMat(bitmap); + delete bitmap; + } + + property cv::Mat Value { + cv::Mat get() + { + cv::Mat value = this->m_bitmap->clone(); + return value; + } + } + + ~BitmapMat() + { + if (this->m_disposed) + { + return; + } + + this->!BitmapMat(); + this->m_disposed = true; + } + + !BitmapMat() + { + delete[] m_bitmap->data; + } + + private: + + static cv::Mat* BitmapToMat(Bitmap^ bitmap) { int channels = 0; @@ -93,31 +126,59 @@ namespace openalprnet { bitmap->PixelFormat ); - char *src = reinterpret_cast(bitmapData->Scan0.ToPointer()); - pin_ptr pin(&src[0]); + const int totalBytes = bitmap->Height * bitmapData->Stride; - cv::Mat dstMat(cv::Size(bitmap->Width, bitmap->Height), CV_8UC(channels), pin); + char *dst = new char[totalBytes]; + ::memcpy(dst, bitmapData->Scan0.ToPointer(), totalBytes); + + cv::Mat* dstMat = new cv::Mat(cv::Size(bitmap->Width, bitmap->Height), CV_8UC(channels), dst); bitmap->UnlockBits(bitmapData); return dstMat; } - static cv::Mat MemoryStreamBitmapToMat(MemoryStream^ memoryStream) + static cv::Mat* MemoryStreamBitmapToMat(MemoryStream^ memoryStream) { Bitmap^ bitmap = gcnew Bitmap(memoryStream); - cv::Mat mat = BitmapToMat(bitmap); + cv::Mat* mat = BitmapToMat(bitmap); + delete bitmap; return mat; } - static cv::Mat ByteArrayToMat(array^ byteArray) + static cv::Mat* ByteArrayToMat(array^ byteArray) { MemoryStream^ ms = gcnew MemoryStream(byteArray); - cv::Mat mat(MemoryStreamBitmapToMat(ms)); + cv::Mat* mat = MemoryStreamBitmapToMat(ms); delete ms; return mat; } + }; + + private ref class AlprHelper sealed + { + public: + + static std::vector ToVector(array^ src) + { + std::vector result(src->Length); + pin_ptr pin(&src[0]); + char *first(pin), *last(pin + src->Length); + std::copy(first, last, result.begin()); + return result; + } + + static std::vector ToVector(array^ src) + { + std::vector result(src->Length); + pin_ptr pin(&src[0]); + char* pch = reinterpret_cast(pin); + char *first(pch), *last(pch + src->Length); + std::copy(first, last, result.begin()); + return result; + } + static Bitmap^ MatToBitmap(cv::Mat mat) { const int width = mat.size().width; @@ -217,14 +278,16 @@ namespace openalprnet { return System::Drawing::Rectangle(rect.x, rect.y, rect.width, rect.height); } - }; + static List^ ToRectangleList(std::vector srcRects) + { + List^ rects = gcnew List(); + for each(cv::Rect rect in srcRects) + { + rects->Add(ToRectangle(rect)); + } + return rects; + } - public enum class OpenCVMatType { - Unchanged = CV_LOAD_IMAGE_UNCHANGED, - Grayscale = CV_LOAD_IMAGE_GRAYSCALE, - Color = CV_LOAD_IMAGE_COLOR, - AnyDepth = CV_LOAD_IMAGE_ANYDEPTH, - AnyColor = CV_LOAD_IMAGE_ANYCOLOR }; public ref class AlprMotionDetectionNet : IDisposable { @@ -236,42 +299,62 @@ namespace openalprnet { void ResetMotionDetection(Bitmap^ bitmap) { - ResetMotionDetection(Mat(bitmap)); + BitmapMat^ wrapper = gcnew BitmapMat(bitmap); + ResetMotionDetection(wrapper->Value); + delete wrapper; } - void ResetMotionDetection(String^ filename, OpenCVMatType matType) + void ResetMotionDetection(String^ filename) { - return ResetMotionDetection(Mat(filename, matType)); + BitmapMat^ wrapper = gcnew BitmapMat(filename); + ResetMotionDetection(wrapper->Value); + delete wrapper; } void ResetMotionDetection(MemoryStream^ memoryStream) { - return ResetMotionDetection(Mat(memoryStream)); + BitmapMat^ wrapper = gcnew BitmapMat(memoryStream); + ResetMotionDetection(wrapper->Value); + delete wrapper; } void ResetMotionDetection(array^ byteArray) { - return ResetMotionDetection(Mat(byteArray)); + BitmapMat^ wrapper = gcnew BitmapMat(byteArray); + ResetMotionDetection(wrapper->Value); + delete wrapper; } System::Drawing::Rectangle MotionDetect(Bitmap^ bitmap) { - return MotionDetect(Mat(bitmap)); + BitmapMat^ wrapper = gcnew BitmapMat(bitmap); + System::Drawing::Rectangle motion = MotionDetect(wrapper->Value); + delete wrapper; + return motion; } - System::Drawing::Rectangle MotionDetect(String^ filename, OpenCVMatType matType) + System::Drawing::Rectangle MotionDetect(String^ filename) { - return MotionDetect(Mat(filename, matType)); + BitmapMat^ wrapper = gcnew BitmapMat(filename); + System::Drawing::Rectangle motion = MotionDetect(wrapper->Value); + delete wrapper; + return motion; } System::Drawing::Rectangle MotionDetect(MemoryStream^ memoryStream) { - return MotionDetect(Mat(memoryStream)); + BitmapMat^ wrapper = gcnew BitmapMat(memoryStream); + System::Drawing::Rectangle motion = MotionDetect(wrapper->Value); + delete wrapper; + return motion; } System::Drawing::Rectangle MotionDetect(array^ byteArray) { - return MotionDetect(Mat(byteArray)); + BitmapMat^ wrapper = gcnew BitmapMat(byteArray); + System::Drawing::Rectangle motion = MotionDetect(wrapper->Value); + delete wrapper; + return motion; } private: @@ -286,30 +369,6 @@ namespace openalprnet { return AlprHelper::ToRectangle(rect); } - cv::Mat Mat(String^ filename, OpenCVMatType matType) - { - cv::Mat mat = cv::imread(AlprHelper::ToStlString(filename), static_cast(matType)); - return mat; - } - - cv::Mat Mat(Bitmap^ bitmap) - { - cv::Mat mat = AlprHelper::BitmapToMat(bitmap); - return mat; - } - - cv::Mat Mat(MemoryStream^ memoryStream) - { - cv::Mat mat = AlprHelper::MemoryStreamBitmapToMat(memoryStream); - return mat; - } - - cv::Mat Mat(array^ byteArray) - { - cv::Mat mat = AlprHelper::ByteArrayToMat(byteArray); - return mat; - } - private: ~AlprMotionDetectionNet() @@ -1349,9 +1408,11 @@ namespace openalprnet { /// AlprResultsNet^ Recognize(Bitmap^ bitmap, List^ regionsOfInterest) { - cv::Mat frame = AlprHelper::BitmapToMat(bitmap); + BitmapMat^ wrapper = gcnew BitmapMat(bitmap); + cv::Mat frame = wrapper->Value; std::vector rois = AlprHelper::ToVector(regionsOfInterest); AlprResults results = m_Impl->recognize(frame.data, frame.elemSize(), frame.cols, frame.rows, rois); + delete wrapper; return gcnew AlprResultsNet(results); }