From e4e0862c2ebe205f8c50897f15bfe256089d6ac9 Mon Sep 17 00:00:00 2001 From: "andrey.morozov" Date: Sat, 29 Jun 2013 22:00:26 +0400 Subject: [PATCH] added support image with alpha channel --- modules/highgui/src/grfmt_webp.cpp | 115 +++++++++++++++++++--------- modules/highgui/src/grfmt_webp.hpp | 7 +- modules/highgui/test/test_grfmt.cpp | 10 ++- 3 files changed, 94 insertions(+), 38 deletions(-) diff --git a/modules/highgui/src/grfmt_webp.cpp b/modules/highgui/src/grfmt_webp.cpp index 2702620950..fd9682a79f 100644 --- a/modules/highgui/src/grfmt_webp.cpp +++ b/modules/highgui/src/grfmt_webp.cpp @@ -46,6 +46,7 @@ #include #include + #include #include @@ -53,17 +54,38 @@ #include "opencv2/imgproc.hpp" +const size_t WEBP_HEADER_SIZE = 32; + namespace cv { WebPDecoder::WebPDecoder() { - m_signature = "RIFF....WEBPVP8 "; m_buf_supported = true; } -WebPDecoder::~WebPDecoder() +WebPDecoder::~WebPDecoder() {} + +size_t WebPDecoder::signatureLength() const { + return WEBP_HEADER_SIZE; +} + +bool WebPDecoder::checkSignature(const String & signature) const +{ + bool ret = false; + + if(signature.size() >= WEBP_HEADER_SIZE) + { + WebPBitstreamFeatures features; + if(VP8_STATUS_OK == WebPGetFeatures((uint8_t *)signature.c_str(), + WEBP_HEADER_SIZE, &features)) + { + ret = true; + } + } + + return ret; } ImageDecoder WebPDecoder::newDecoder() const @@ -71,20 +93,6 @@ ImageDecoder WebPDecoder::newDecoder() const return new WebPDecoder; } -bool WebPDecoder::checkSignature( const String& signature ) const -{ - size_t len = signatureLength(); - bool ret = false; - - if(signature.size() >= len) - { - ret = ( (memcmp(signature.c_str(), m_signature.c_str(), 4) == 0) && - (memcmp(signature.c_str() + 8, m_signature.c_str() + 8, 4) == 0) ); - } - - return ret; -} - bool WebPDecoder::readHeader() { if (m_buf.empty()) @@ -99,16 +107,16 @@ bool WebPDecoder::readHeader() } fseek(wfile, 0, SEEK_END); - size_t wfile_size = ftell(wfile); + long int wfile_size = ftell(wfile); fseek(wfile, 0, SEEK_SET); - if(wfile_size > (size_t)INT_MAX) + if(wfile_size > static_cast(INT_MAX)) { fclose(wfile); return false; } - data.create(1, (int)wfile_size, CV_8U); + data.create(1, wfile_size, CV_8U); size_t data_size = fread(data.data, 1, wfile_size, wfile); @@ -117,7 +125,7 @@ bool WebPDecoder::readHeader() fclose(wfile); } - if( data_size < wfile_size ) + if(static_cast(data_size) != wfile_size) { return false; } @@ -127,9 +135,23 @@ bool WebPDecoder::readHeader() data = m_buf; } - if(WebPGetInfo(data.data, data.total(), &m_width, &m_height) == 1) + WebPBitstreamFeatures features; + if(VP8_STATUS_OK == WebPGetFeatures(data.data, WEBP_HEADER_SIZE, &features)) { - m_type = CV_8UC3; + m_width = features.width; + m_height = features.height; + + if (features.has_alpha) + { + m_type = CV_8UC4; + channels = 4; + } + else + { + m_type = CV_8UC3; + channels = 3; + } + return true; } @@ -140,17 +162,24 @@ bool WebPDecoder::readData(Mat &img) { if( m_width > 0 && m_height > 0 ) { + if (img.cols != m_width || img.rows != m_height || img.type() != m_type) + { + img.create(m_height, m_width, m_type); + } + uchar* out_data = img.data; - unsigned int out_data_size = m_width * m_height * 3 * sizeof(uchar); + size_t out_data_size = img.cols * img.rows * img.elemSize(); uchar *res_ptr = 0; if (channels == 3) { - res_ptr = WebPDecodeBGRInto(data.data, data.total(), out_data, out_data_size, img.step); + res_ptr = WebPDecodeBGRInto(data.data, data.total(), out_data, + out_data_size, img.step); } else if (channels == 4) { - res_ptr = WebPDecodeBGRAInto(data.data, data.total(), out_data, out_data_size, img.step); + res_ptr = WebPDecodeBGRAInto(data.data, data.total(), out_data, + out_data_size, img.step); } if(res_ptr == out_data) @@ -168,9 +197,7 @@ WebPEncoder::WebPEncoder() m_buf_supported = true; } -WebPEncoder::~WebPEncoder() -{ -} +WebPEncoder::~WebPEncoder() { } ImageEncoder WebPEncoder::newEncoder() const { @@ -187,19 +214,19 @@ bool WebPEncoder::write(const Mat& img, const std::vector& params) size_t size = 0; bool comp_lossless = true; - int quality = 100; + float quality = 100.0f; if (params.size() > 1) { if (params[0] == CV_IMWRITE_WEBP_QUALITY) { comp_lossless = false; - quality = params[1]; - if (quality < 1) + quality = static_cast(params[1]); + if (quality < 1.0f) { - quality = 1; + quality = 1.0f; } - if (quality > 100) + if (quality > 100.0f) { comp_lossless = true; } @@ -219,14 +246,32 @@ bool WebPEncoder::write(const Mat& img, const std::vector& params) image = &temp; channels = 3; } + else if (channels == 2) + { + return false; + } if (comp_lossless) { - size = WebPEncodeLosslessBGR(image->data, width, height, ((width * 3 + 3) & ~3), &out); + if(channels == 3) + { + size = WebPEncodeLosslessBGR(image->data, width, height, image->step, &out); + } + else if(channels == 4) + { + size = WebPEncodeLosslessBGRA(image->data, width, height, image->step, &out); + } } else { - size = WebPEncodeBGR(image->data, width, height, ((width * 3 + 3) & ~3), (float)quality, &out); + if(channels == 3) + { + size = WebPEncodeBGR(image->data, width, height, image->step, quality, &out); + } + else if(channels == 4) + { + size = WebPEncodeBGRA(image->data, width, height, image->step, quality, &out); + } } if(size > 0) diff --git a/modules/highgui/src/grfmt_webp.hpp b/modules/highgui/src/grfmt_webp.hpp index f37e6e9f4a..ea692bf8d2 100644 --- a/modules/highgui/src/grfmt_webp.hpp +++ b/modules/highgui/src/grfmt_webp.hpp @@ -47,6 +47,8 @@ #ifdef HAVE_WEBP + + namespace cv { @@ -60,12 +62,15 @@ public: bool readData( Mat& img ); bool readHeader(); void close(); - bool checkSignature( const String& signature ) const; + + size_t signatureLength() const; + bool checkSignature( const String& signature) const; ImageDecoder newDecoder() const; protected: Mat data; + int channels; }; class WebPEncoder : public BaseImageEncoder diff --git a/modules/highgui/test/test_grfmt.cpp b/modules/highgui/test/test_grfmt.cpp index d4e18dd2dd..28af633daf 100644 --- a/modules/highgui/test/test_grfmt.cpp +++ b/modules/highgui/test/test_grfmt.cpp @@ -387,7 +387,7 @@ TEST(Highgui_WebP, encode_decode_lossless_webp) TEST(Highgui_WebP, encode_decode_lossy_webp) { cvtest::TS& ts = *cvtest::TS::ptr(); - std::string input = std::string(ts.get_data_path()) + "/../cv/shared/lena.png"; + std::string input = std::string(ts.get_data_path()) + "../cv/shared/lena.png"; cv::Mat img = cv::imread(input); ASSERT_FALSE(img.empty()); @@ -402,13 +402,16 @@ TEST(Highgui_WebP, encode_decode_lossy_webp) cv::Mat img_webp = cv::imread(output); remove(output.c_str()); EXPECT_FALSE(img_webp.empty()); + EXPECT_EQ(3, img_webp.channels()); + EXPECT_EQ(512, img_webp.cols); + EXPECT_EQ(512, img_webp.rows); } } TEST(Highgui_WebP, encode_decode_with_alpha_webp) { cvtest::TS& ts = *cvtest::TS::ptr(); - std::string input = std::string(ts.get_data_path()) + "/../cv/shared/lena.png"; + std::string input = std::string(ts.get_data_path()) + "../cv/shared/lena.png"; cv::Mat img = cv::imread(input); ASSERT_FALSE(img.empty()); @@ -424,6 +427,9 @@ TEST(Highgui_WebP, encode_decode_with_alpha_webp) cv::Mat img_webp = cv::imread(output); remove(output.c_str()); EXPECT_FALSE(img_webp.empty()); + EXPECT_EQ(4, img_webp.channels()); + EXPECT_EQ(512, img_webp.cols); + EXPECT_EQ(512, img_webp.rows); } #endif