diff --git a/ext/opencv/cvmat.cpp b/ext/opencv/cvmat.cpp index d419721..953cdbc 100644 --- a/ext/opencv/cvmat.cpp +++ b/ext/opencv/cvmat.cpp @@ -383,6 +383,9 @@ void define_ruby_class() rb_define_method(rb_klass, "save_image", RUBY_METHOD_FUNC(rb_save_image), 1); rb_define_alias(rb_klass, "save", "save_image"); + + rb_define_method(rb_klass, "encode_image", RUBY_METHOD_FUNC(rb_encode_imageM), -1); + rb_define_alias(rb_klass, "encode", "encode_image"); } @@ -463,6 +466,75 @@ rb_load_imageM(int argc, VALUE *argv, VALUE self) return OPENCV_OBJECT(rb_klass, mat); } +/* + * call-seq: + * encode_image(ext [,params]) -> Array + * + * Encodes an image into a memory buffer. + * + * Parameters: + * ext - File extension that defines the output format ('.jpg', '.png', ...) + * params - Format-specific parameters. + */ +VALUE +rb_encode_imageM(int argc, VALUE *argv, VALUE self) +{ + VALUE _ext, _params; + rb_scan_args(argc, argv, "11", &_ext, &_params); + Check_Type(_ext, T_STRING); + const char* ext = RSTRING_PTR(_ext); + CvMat* buff = NULL; + int* params = NULL; + + if (!NIL_P(_params)) { + Check_Type(_params, T_HASH); + const int flags[] = { + CV_IMWRITE_JPEG_QUALITY, + CV_IMWRITE_PNG_COMPRESSION, + CV_IMWRITE_PNG_STRATEGY, + CV_IMWRITE_PNG_STRATEGY_DEFAULT, + CV_IMWRITE_PNG_STRATEGY_FILTERED, + CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY, + CV_IMWRITE_PNG_STRATEGY_RLE, + CV_IMWRITE_PNG_STRATEGY_FIXED, + CV_IMWRITE_PXM_BINARY + }; + const int flag_size = sizeof(flags) / sizeof(int); + + params = ALLOCA_N(int, RHASH_SIZE(_params) * 2); + for (int i = 0, n = 0; i < flag_size; i++) { + VALUE val = rb_hash_lookup(_params, INT2FIX(flags[i])); + if (!NIL_P(val)) { + params[n] = flags[i]; + params[n + 1] = NUM2INT(val); + n += 2; + } + } + } + + try { + buff = cvEncodeImage(ext, CVMAT(self), params); + } + catch (cv::Exception& e) { + raise_cverror(e); + } + + const int size = buff->rows * buff->cols; + VALUE array = rb_ary_new2(size); + for (int i = 0; i < size; i++) { + rb_ary_store(array, i, CHR2FIX(CV_MAT_ELEM(*buff, char, 0, i))); + } + + try { + cvReleaseMat(&buff); + } + catch (cv::Exception& e) { + raise_cverror(e); + } + + return array; +} + /* * nodoc */ diff --git a/ext/opencv/cvmat.h b/ext/opencv/cvmat.h index 2b1ba31..5e82442 100644 --- a/ext/opencv/cvmat.h +++ b/ext/opencv/cvmat.h @@ -26,6 +26,7 @@ void define_ruby_class(); VALUE rb_allocate(VALUE klass); VALUE rb_initialize(int argc, VALUE *argv, VALUE self); VALUE rb_load_imageM(int argc, VALUE *argv, VALUE self); +VALUE rb_encode_imageM(int argc, VALUE *argv, VALUE self); VALUE rb_method_missing(int argc, VALUE *argv, VALUE self); VALUE rb_to_s(VALUE self); diff --git a/ext/opencv/opencv.cpp b/ext/opencv/opencv.cpp index 0cc616e..30d4958 100644 --- a/ext/opencv/opencv.cpp +++ b/ext/opencv/opencv.cpp @@ -188,6 +188,17 @@ define_ruby_module() rb_define_const(rb_module, "CV_LOAD_IMAGE_ANYDEPTH", INT2FIX(CV_LOAD_IMAGE_ANYDEPTH)); rb_define_const(rb_module, "CV_LOAD_IMAGE_ANYCOLOR", INT2FIX(CV_LOAD_IMAGE_ANYCOLOR)); + /* Format-specific save parameters */ + rb_define_const(rb_module, "CV_IMWRITE_JPEG_QUALITY", INT2FIX(CV_IMWRITE_JPEG_QUALITY)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_COMPRESSION", INT2FIX(CV_IMWRITE_PNG_COMPRESSION)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_STRATEGY", INT2FIX(CV_IMWRITE_PNG_STRATEGY)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_STRATEGY_DEFAULT", INT2FIX(CV_IMWRITE_PNG_STRATEGY_DEFAULT)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_STRATEGY_FILTERED", INT2FIX(CV_IMWRITE_PNG_STRATEGY_FILTERED)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY", INT2FIX(CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_STRATEGY_RLE", INT2FIX(CV_IMWRITE_PNG_STRATEGY_RLE)); + rb_define_const(rb_module, "CV_IMWRITE_PNG_STRATEGY_FIXED", INT2FIX(CV_IMWRITE_PNG_STRATEGY_FIXED)); + rb_define_const(rb_module, "CV_IMWRITE_PXM_BINARY", INT2FIX(CV_IMWRITE_PXM_BINARY)); + /* Types of morphological operations */ rb_define_const(rb_module, "CV_MOP_OPEN", INT2FIX(CV_MOP_OPEN)); rb_define_const(rb_module, "CV_MOP_CLOSE", INT2FIX(CV_MOP_CLOSE)); diff --git a/test/test_cvmat.rb b/test/test_cvmat.rb index 56ee0d4..403e3f9 100755 --- a/test/test_cvmat.rb +++ b/test/test_cvmat.rb @@ -103,6 +103,38 @@ class TestCvMat < OpenCVTestCase File.delete filename end + def test_encode + mat = CvMat.load(FILENAME_CAT); + + jpg = mat.encode('.jpg') + assert_equal('JFIF', jpg[6, 4].map(&:chr).join) # Is jpeg format? + + jpg = mat.encode('.jpg', CV_IMWRITE_JPEG_QUALITY => 10) + assert_equal('JFIF', jpg[6, 4].map(&:chr).join) + + png = mat.encode('.png') + assert_equal('PNG', png[1, 3].map(&:chr).join) # Is png format? + + png = mat.encode('.png', CV_IMWRITE_PNG_COMPRESSION => 9) + assert_equal('PNG', png[1, 3].map(&:chr).join) + + assert_raise(TypeError) { + mat.encode(DUMMY_OBJ) + } + assert_raise(TypeError) { + mat.encode('.jpg', DUMMY_OBJ) + } + + # Uncomment the following lines to see the result images + # + # open('test-jpeg.jpg', 'wb') { |f| + # f.write jpg.pack("c*") + # } + # open('test-png.png', 'wb') { |f| + # f.write png.pack("c*") + # } + end + def test_GOOD_FEATURES_TO_TRACK_OPTION assert_equal(0xff, CvMat::GOOD_FEATURES_TO_TRACK_OPTION[:max]) assert_nil(CvMat::GOOD_FEATURES_TO_TRACK_OPTION[:mask])