Skip to content

Commit

Permalink
add imgcodecs
Browse files Browse the repository at this point in the history
  • Loading branch information
rainyl committed Jun 24, 2024
1 parent aaf29a3 commit 2f15396
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 7 deletions.
2 changes: 2 additions & 0 deletions ffigen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ headers:
- src/gapi/gapi.h
- src/highgui/highgui.h
- src/imgcodecs/imgcodecs.h
- src/imgcodecs/imgcodecs_async.h
- src/imgproc/imgproc.h
- src/imgproc/imgproc_async.h
- src/objdetect/objdetect.h
Expand All @@ -55,6 +56,7 @@ headers:
- src/gapi/gapi.h
- src/highgui/highgui.h
- src/imgcodecs/imgcodecs.h
- src/imgcodecs/imgcodecs_async.h
- src/imgproc/imgproc.h
- src/imgproc/imgproc_async.h
- src/objdetect/objdetect.h
Expand Down
52 changes: 52 additions & 0 deletions lib/src/imgcodecs/imgcodecs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ Mat imread(String filename, {int flags = IMREAD_COLOR}) {
});
}

Future<Mat> imreadAsync(String filename, {int flags = IMREAD_COLOR}) async {
final cname = filename.toNativeUtf8().cast<ffi.Char>();
final rval = cvRunAsync((callback) => CFFI.Image_IMRead_Async(cname, flags, callback), matCompleter);
calloc.free(cname);
return rval;
}

/// IMWrite writes a Mat to an image file.
///
/// For further details, please see:
Expand All @@ -52,6 +59,22 @@ bool imwrite(String filename, InputArray img, {VecInt? params}) {
});
}

Future<bool> imwriteAsync(String filename, InputArray img, {VecInt? params}) async {
final cname = filename.toNativeUtf8().cast<ffi.Char>();
final rval = cvRunAsync<bool>(
(callback) => params == null
? CFFI.Image_IMWrite_Async(cname, img.ref, callback)
: CFFI.Image_IMWrite_WithParams_Async(cname, img.ref, params.ref, callback),
(c, p) {
final rval = p.cast<ffi.Bool>().value;
calloc.free(p);
return c.complete(rval);
},
);
calloc.free(cname);
return rval;
}

/// IMEncode encodes an image Mat into a memory buffer.
/// This function compresses the image and stores it in the returned memory buffer,
/// using the image format passed in in the form of a file extension string.
Expand All @@ -77,6 +100,28 @@ Uint8List imencode(
return VecUChar.fromPointer(buffer).toU8List();
}

Future<(bool, Uint8List)> imencodeAsync(
String ext,
InputArray img, {
VecInt? params,
}) async {
final cExt = ext.toNativeUtf8().cast<ffi.Char>();
final rval = cvRunAsync2<(bool, Uint8List)>(
(callback) => params == null
? CFFI.Image_IMEncode_Async(cExt, img.ref, callback)
: CFFI.Image_IMEncode_WithParams_Async(cExt, img.ref, params.ref, callback),
(c, p, p1) {
final v = p.cast<ffi.Bool>().value;
calloc.free(p);
final vec = VecUChar.fromPointer(p1.cast());
final data = vec.toU8List();
vec.dispose();
return c.complete((v, data));
},
);
return rval;
}

/// imdecode reads an image from a buffer in memory.
/// The function imdecode reads an image from the specified buffer in memory.
/// If the buffer is too short or contains invalid data, the function
Expand All @@ -91,3 +136,10 @@ Mat imdecode(Uint8List buf, int flags, {Mat? dst}) {
cvRun(() => CFFI.Image_IMDecode(vec.ref, flags, dst!.ptr));
return dst;
}

Future<Mat> imdecodeAsync(Uint8List buf, int flags) async {
final vec = VecUChar.fromList(buf);
final rval = cvRunAsync((callback) => CFFI.Image_IMDecode_Async(vec.ref, flags, callback), matCompleter);
vec.dispose();
return rval;
}
125 changes: 125 additions & 0 deletions lib/src/opencv.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6122,6 +6122,25 @@ class CvNative {
late final _Image_IMDecode = _Image_IMDecodePtr.asFunction<
ffi.Pointer<CvStatus> Function(VecUChar, int, ffi.Pointer<Mat>)>();

ffi.Pointer<CvStatus> Image_IMDecode_Async(
VecUChar buf,
int flags,
CvCallback_1 callback,
) {
return _Image_IMDecode_Async(
buf,
flags,
callback,
);
}

late final _Image_IMDecode_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(
VecUChar, ffi.Int, CvCallback_1)>>('Image_IMDecode_Async');
late final _Image_IMDecode_Async = _Image_IMDecode_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(VecUChar, int, CvCallback_1)>();

ffi.Pointer<CvStatus> Image_IMEncode(
ffi.Pointer<ffi.Char> fileExt,
Mat img,
Expand All @@ -6144,6 +6163,26 @@ class CvNative {
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, Mat,
ffi.Pointer<ffi.Bool>, ffi.Pointer<VecUChar>)>();

ffi.Pointer<CvStatus> Image_IMEncode_Async(
ffi.Pointer<ffi.Char> fileExt,
Mat img,
CvCallback_2 callback,
) {
return _Image_IMEncode_Async(
fileExt,
img,
callback,
);
}

late final _Image_IMEncode_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, Mat,
CvCallback_2)>>('Image_IMEncode_Async');
late final _Image_IMEncode_Async = _Image_IMEncode_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, Mat, CvCallback_2)>();

ffi.Pointer<CvStatus> Image_IMEncode_WithParams(
ffi.Pointer<ffi.Char> fileExt,
Mat img,
Expand Down Expand Up @@ -6173,6 +6212,29 @@ class CvNative {
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, Mat, VecInt,
ffi.Pointer<ffi.Bool>, ffi.Pointer<VecUChar>)>();

ffi.Pointer<CvStatus> Image_IMEncode_WithParams_Async(
ffi.Pointer<ffi.Char> fileExt,
Mat img,
VecInt params,
CvCallback_2 callback,
) {
return _Image_IMEncode_WithParams_Async(
fileExt,
img,
params,
callback,
);
}

late final _Image_IMEncode_WithParams_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, Mat, VecInt,
CvCallback_2)>>('Image_IMEncode_WithParams_Async');
late final _Image_IMEncode_WithParams_Async =
_Image_IMEncode_WithParams_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, Mat, VecInt, CvCallback_2)>();

ffi.Pointer<CvStatus> Image_IMRead(
ffi.Pointer<ffi.Char> filename,
int flags,
Expand All @@ -6193,6 +6255,26 @@ class CvNative {
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, int, ffi.Pointer<Mat>)>();

ffi.Pointer<CvStatus> Image_IMRead_Async(
ffi.Pointer<ffi.Char> filename,
int flags,
CvCallback_1 callback,
) {
return _Image_IMRead_Async(
filename,
flags,
callback,
);
}

late final _Image_IMRead_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, ffi.Int,
CvCallback_1)>>('Image_IMRead_Async');
late final _Image_IMRead_Async = _Image_IMRead_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, int, CvCallback_1)>();

ffi.Pointer<CvStatus> Image_IMWrite(
ffi.Pointer<ffi.Char> filename,
Mat img,
Expand All @@ -6213,6 +6295,26 @@ class CvNative {
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, Mat, ffi.Pointer<ffi.Bool>)>();

ffi.Pointer<CvStatus> Image_IMWrite_Async(
ffi.Pointer<ffi.Char> filename,
Mat img,
CvCallback_1 callback,
) {
return _Image_IMWrite_Async(
filename,
img,
callback,
);
}

late final _Image_IMWrite_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, Mat,
CvCallback_1)>>('Image_IMWrite_Async');
late final _Image_IMWrite_Async = _Image_IMWrite_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, Mat, CvCallback_1)>();

ffi.Pointer<CvStatus> Image_IMWrite_WithParams(
ffi.Pointer<ffi.Char> filename,
Mat img,
Expand All @@ -6236,6 +6338,29 @@ class CvNative {
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, Mat, VecInt, ffi.Pointer<ffi.Bool>)>();

ffi.Pointer<CvStatus> Image_IMWrite_WithParams_Async(
ffi.Pointer<ffi.Char> filename,
Mat img,
VecInt params,
CvCallback_1 callback,
) {
return _Image_IMWrite_WithParams_Async(
filename,
img,
params,
callback,
);
}

late final _Image_IMWrite_WithParams_AsyncPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<CvStatus> Function(ffi.Pointer<ffi.Char>, Mat, VecInt,
CvCallback_1)>>('Image_IMWrite_WithParams_Async');
late final _Image_IMWrite_WithParams_Async =
_Image_IMWrite_WithParams_AsyncPtr.asFunction<
ffi.Pointer<CvStatus> Function(
ffi.Pointer<ffi.Char>, Mat, VecInt, CvCallback_1)>();

ffi.Pointer<CvStatus> InitUndistortRectifyMap(
Mat cameraMatrix,
Mat distCoeffs,
Expand Down
47 changes: 47 additions & 0 deletions src/imgcodecs/imgcodecs_async.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "imgcodecs_async.h"
#include "core/types.h"

CvStatus *Image_IMRead_Async(const char *filename, int flags, CvCallback_1 callback) {
BEGIN_WRAP
callback(new Mat{new cv::Mat(cv::imread(filename, flags))});
END_WRAP
}

CvStatus *Image_IMWrite_Async(const char *filename, Mat img, CvCallback_1 callback) {
BEGIN_WRAP
callback(new bool(cv::imwrite(filename, *img.ptr)));
END_WRAP
}

CvStatus *Image_IMWrite_WithParams_Async(
const char *filename, Mat img, VecInt params, CvCallback_1 callback
) {
BEGIN_WRAP
callback(new bool(cv::imwrite(filename, *img.ptr, *params.ptr)));
END_WRAP
}

CvStatus *Image_IMEncode_Async(const char *fileExt, Mat img, CvCallback_2 callback) {
BEGIN_WRAP
std::vector<uchar> buf;
bool success = cv::imencode(fileExt, *img.ptr, buf);
callback(new bool(success), new VecUChar{new std::vector<uchar>(buf)});
END_WRAP
}

CvStatus *Image_IMEncode_WithParams_Async(
const char *fileExt, Mat img, VecInt params, CvCallback_2 callback
) {
BEGIN_WRAP
std::vector<uchar> buf;
bool success = cv::imencode(fileExt, *img.ptr, buf, *params.ptr);
callback(new bool(success), new VecUChar{new std::vector<uchar>(buf)});
END_WRAP
}

CvStatus *Image_IMDecode_Async(VecUChar buf, int flags, CvCallback_1 callback) {
BEGIN_WRAP
auto m = cv::imdecode(*buf.ptr, flags);
callback(new Mat{new cv::Mat(m)});
END_WRAP
}
30 changes: 30 additions & 0 deletions src/imgcodecs/imgcodecs_async.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Created by Rainyl.
Licensed: Apache 2.0 license. Copyright (c) 2024 Rainyl.
*/

#ifndef CVD_IMGCODECS_ASYNC_H_
#define CVD_IMGCODECS_ASYNC_H_

#include "core/types.h"
#include <stdbool.h>

#ifdef __cplusplus
#include <opencv2/opencv.hpp>
extern "C" {
#endif

CvStatus *Image_IMRead_Async(const char *filename, int flags, CvCallback_1 callback);
CvStatus *Image_IMWrite_Async(const char *filename, Mat img, CvCallback_1 callback);
CvStatus *
Image_IMWrite_WithParams_Async(const char *filename, Mat img, VecInt params, CvCallback_1 callback);
CvStatus *Image_IMEncode_Async(const char *fileExt, Mat img, CvCallback_2 callback);
CvStatus *
Image_IMEncode_WithParams_Async(const char *fileExt, Mat img, VecInt params, CvCallback_2 callback);
CvStatus *Image_IMDecode_Async(VecUChar buf, int flags, CvCallback_1 callback);

#ifdef __cplusplus
}
#endif

#endif // CVD_IMGCODECS_ASYNC_H_
42 changes: 35 additions & 7 deletions test/imgcodecs_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,23 @@ import 'package:opencv_dart/opencv_dart.dart' as cv;
import 'package:test/test.dart';

void main() async {
test("cv2.imread, cv2.imwrite", () {
final cvImage = cv.imread("test/images/circles.jpg", flags: cv.IMREAD_COLOR);
expect((cvImage.width, cvImage.height), (512, 512));
expect(cv.imwrite("test/images_out/test_imwrite.png", cvImage), true);
final params = [cv.IMWRITE_PNG_COMPRESSION, 9].i32;
final res = cv.imwrite("test/images_out/test_imwrite.png", cvImage, params: params);
expect(res, true);
test("cv2.imread, cv2.imwrite", () async {
{
final cvImage = cv.imread("test/images/circles.jpg", flags: cv.IMREAD_COLOR);
expect((cvImage.width, cvImage.height), (512, 512));
expect(cv.imwrite("test/images_out/test_imwrite.png", cvImage), true);
final params = [cv.IMWRITE_PNG_COMPRESSION, 9].i32;
final res = cv.imwrite("test/images_out/test_imwrite.png", cvImage, params: params);
expect(res, true);
}
{
final cvImage = await cv.imreadAsync("test/images/circles.jpg", flags: cv.IMREAD_COLOR);
expect((cvImage.width, cvImage.height), (512, 512));
expect(await cv.imwriteAsync("test/images_out/test_imwrite.png", cvImage), true);
final params = [cv.IMWRITE_PNG_COMPRESSION, 9].i32;
final res = await cv.imwriteAsync("test/images_out/test_imwrite.png", cvImage, params: params);
expect(res, true);
}
});

test("cv2.imencode, cv2.imdecode", () async {
Expand All @@ -33,4 +43,22 @@ void main() async {
expect(dst.isEmpty, false);
expect((dst.rows, dst.cols, dst.channels), (cvImage.rows, cvImage.cols, cvImage.channels));
});
test("cv2.imencodeAsync, cv2.imdecodeAsync", () async {
final cvImage = await cv.imreadAsync("test/images/circles.jpg", flags: cv.IMREAD_COLOR);
expect((cvImage.width, cvImage.height), (512, 512));
final (success, buf) = await cv.imencodeAsync(".png", cvImage);
expect(success, true);
expect(buf.length, greaterThan(0));

await File("test/images_out/test_imencode.png").writeAsBytes(buf);
final params = [cv.IMWRITE_PNG_COMPRESSION, 9].i32;
final (success1, buf1) = await cv.imencodeAsync(".png", cvImage, params: params);
expect(success1, true);
expect(buf1.length, greaterThan(0));

final cvimgDecode = await cv.imdecodeAsync(buf, cv.IMREAD_COLOR);
expect(cvimgDecode.height, equals(cvImage.height));
expect(cvimgDecode.width, equals(cvImage.width));
expect(cvimgDecode.channels, equals(cvImage.channels));
});
}

0 comments on commit 2f15396

Please sign in to comment.