imgcodecs: Add IMDecodeIntoMat to reduce heap allocations (#1035)

* imgcodecs: add IMDecodeIntoMat which allows to imdecode into existing Mat for performance
This commit is contained in:
Niklas Hansson
2022-12-01 10:14:30 +01:00
committed by deadprogram
parent 8f2aab1c67
commit cd9897f55d
4 changed files with 43 additions and 7 deletions

View File

@@ -42,3 +42,8 @@ Mat Image_IMDecode(ByteArray buf, int flags) {
cv::Mat img = cv::imdecode(data, flags);
return new cv::Mat(img);
}
void Image_IMDecodeIntoMat(ByteArray buf, int flags, Mat dest) {
std::vector<uchar> data(buf.data, buf.data + buf.length);
cv::imdecode(data, flags, dest);
}

View File

@@ -135,7 +135,6 @@ const (
//
// For further details, please see:
// http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56
//
func IMRead(name string, flags IMReadFlag) Mat {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
@@ -147,7 +146,6 @@ func IMRead(name string, flags IMReadFlag) Mat {
//
// For further details, please see:
// http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce
//
func IMWrite(name string, img Mat) bool {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
@@ -160,7 +158,6 @@ func IMWrite(name string, img Mat) bool {
//
// For further details, please see:
// http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce
//
func IMWriteWithParams(name string, img Mat, params []int) bool {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
@@ -196,7 +193,6 @@ const (
//
// For further details, please see:
// http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga461f9ac09887e47797a54567df3b8b63
//
func IMEncode(fileExt FileExt, img Mat) (buf *NativeByteBuffer, err error) {
cfileExt := C.CString(string(fileExt))
defer C.free(unsafe.Pointer(cfileExt))
@@ -211,11 +207,11 @@ func IMEncode(fileExt FileExt, img Mat) (buf *NativeByteBuffer, err error) {
// using the image format passed in in the form of a file extension string.
//
// Usage example:
//
// buffer, err := gocv.IMEncodeWithParams(gocv.JPEGFileExt, img, []int{gocv.IMWriteJpegQuality, quality})
//
// For further details, please see:
// http://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga461f9ac09887e47797a54567df3b8b63
//
func IMEncodeWithParams(fileExt FileExt, img Mat, params []int) (buf *NativeByteBuffer, err error) {
cfileExt := C.CString(string(fileExt))
defer C.free(unsafe.Pointer(cfileExt))
@@ -242,7 +238,6 @@ func IMEncodeWithParams(fileExt FileExt, img Mat, params []int) (buf *NativeByte
//
// For further details, please see:
// https://docs.opencv.org/master/d4/da8/group__imgcodecs.html#ga26a67788faa58ade337f8d28ba0eb19e
//
func IMDecode(buf []byte, flags IMReadFlag) (Mat, error) {
data, err := toByteArray(buf)
if err != nil {
@@ -250,3 +245,19 @@ func IMDecode(buf []byte, flags IMReadFlag) (Mat, error) {
}
return newMat(C.Image_IMDecode(*data, C.int(flags))), nil
}
// IMDecodeIntoMat reads an image from a buffer in memory into a matrix.
// The function IMDecodeIntoMat reads an image from the specified buffer in memory.
// If the buffer is too short or contains invalid data, the function
// returns an error
//
// For further details, please see:
// https://docs.opencv.org/4.x/d4/da8/group__imgcodecs.html#ga5a0acefe5cbe0a81e904e452ec7ca733
func IMDecodeIntoMat(buf []byte, flags IMReadFlag, dest *Mat) error {
data, err := toByteArray(buf)
if err != nil {
return err
}
C.Image_IMDecodeIntoMat(*data, C.int(flags), dest.p)
return nil
}

View File

@@ -17,6 +17,7 @@ void Image_IMEncode(const char* fileExt, Mat img, void* vector);
void Image_IMEncode_WithParams(const char* fileExt, Mat img, IntVector params, void* vector);
Mat Image_IMDecode(ByteArray buf, int flags);
void Image_IMDecodeIntoMat(ByteArray buf, int flag, Mat dest);
#ifdef __cplusplus
}

View File

@@ -149,6 +149,25 @@ func TestIMDecode(t *testing.T) {
t.Error("Should not decode empty array")
}
}
func TestIMDecodeIntoMat(t *testing.T) {
mat := NewMat()
defer mat.Close()
content, err := ioutil.ReadFile("images/face-detect.jpg")
if err != nil {
t.Error("Invalid ReadFile in IMDecode")
}
err = IMDecodeIntoMat(content, IMReadColor, &mat)
if err != nil {
t.Error(err.Error())
}
if mat.Empty() {
t.Error("Invalid Mat in IMDecode")
}
}
func TestIMDecodeWebp(t *testing.T) {
content, err := ioutil.ReadFile("images/sample.webp")
if err != nil {