From 03ea24f298f90934d71fcbabe4d134286ff34d6e Mon Sep 17 00:00:00 2001 From: Ashod Nakashian Date: Wed, 11 Feb 2015 17:49:19 -0500 Subject: [PATCH 1/4] Fix for decoding large Jp2 images on Windows. On Windows, the tmpnam function returns a temp filename in the current directory, which has a prepended backslash '\\'. This subsequently fails the open function. This patch creates a proper temp filename in the temp folder and makes unlike work by opening the file as short-lived. --- 3rdparty/libjasper/jas_stream.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/3rdparty/libjasper/jas_stream.c b/3rdparty/libjasper/jas_stream.c index ca1239c7d9..4c5db5871b 100644 --- a/3rdparty/libjasper/jas_stream.c +++ b/3rdparty/libjasper/jas_stream.c @@ -365,10 +365,14 @@ jas_stream_t *jas_stream_tmpfile() #ifdef _WIN32 /* Choose a file name. */ - tmpnam(obj->pathname); + char lpTempPathBuffer[MAX_PATH]; + const DWORD dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); /* Open the underlying file. */ - if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY, + if (dwRetVal >= MAX_PATH || dwRetVal == 0 || + sprintf_s(obj->pathname, MAX_PATH, "%s\\tmp.XXXXXXXXXX", lpTempPathBuffer) <= 0 || + _mktemp_s(obj->pathname, MAX_PATH) || + (obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY | O_TEMPORARY | _O_SHORT_LIVED, JAS_STREAM_PERMS)) < 0) { jas_stream_destroy(stream); return 0; From 6fd2fdc2e6fe7670b39c2728e06b57db230a441d Mon Sep 17 00:00:00 2001 From: Ashod Nakashian Date: Wed, 11 Feb 2015 21:28:44 -0500 Subject: [PATCH 2/4] Jasper unit-tests and removed a superfluous assertion. --- 3rdparty/libjasper/jas_cm.c | 1 - modules/imgcodecs/test/test_grfmt.cpp | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/3rdparty/libjasper/jas_cm.c b/3rdparty/libjasper/jas_cm.c index dc23ead895..16d4a502df 100644 --- a/3rdparty/libjasper/jas_cm.c +++ b/3rdparty/libjasper/jas_cm.c @@ -842,7 +842,6 @@ static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in, *dst++ = a2; } } else { -assert(0); while (--cnt >= 0) { a0 = *src++; src++; diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp index 423d030a0c..5ef0164fec 100644 --- a/modules/imgcodecs/test/test_grfmt.cpp +++ b/modules/imgcodecs/test/test_grfmt.cpp @@ -87,6 +87,9 @@ TEST(Imgcodecs_imread, regression) { const char* const filenames[] = { +#ifdef HAVE_JASPER + "Rome.jp2", +#endif "color_palette_alpha.png", "multipage.tif", "rle.hdr", @@ -109,6 +112,16 @@ TEST(Imgcodecs_imread, regression) } } +#ifdef HAVE_JASPER +TEST(Imgcodecs_jasper, regression) +{ + const string folder = string(cvtest::TS::ptr()->get_data_path()) + "/readwrite/"; + + ASSERT_TRUE(imread_compare(folder + "Bretagne2.jp2", IMREAD_UNCHANGED)); + ASSERT_TRUE(imread_compare(folder + "Bretagne2.jp2", IMREAD_GRAYSCALE)); +} +#endif + class CV_GrfmtWriteBigImageTest : public cvtest::BaseTest { public: From 54ab3137d5c417a6060abf1ae85a31abaf23fe32 Mon Sep 17 00:00:00 2001 From: Ashod Nakashian Date: Sun, 29 Mar 2015 16:49:47 -0400 Subject: [PATCH 3/4] Simplified temp filename generation. --- 3rdparty/libjasper/jas_stream.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/3rdparty/libjasper/jas_stream.c b/3rdparty/libjasper/jas_stream.c index 4c5db5871b..3ba7a837db 100644 --- a/3rdparty/libjasper/jas_stream.c +++ b/3rdparty/libjasper/jas_stream.c @@ -345,6 +345,7 @@ jas_stream_t *jas_stream_tmpfile() { jas_stream_t *stream; jas_stream_fileobj_t *obj; + char *tmpname; if (!(stream = jas_stream_create())) { return 0; @@ -365,14 +366,12 @@ jas_stream_t *jas_stream_tmpfile() #ifdef _WIN32 /* Choose a file name. */ - char lpTempPathBuffer[MAX_PATH]; - const DWORD dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); + tmpname = tempnam(NULL, NULL); + strcpy(obj->pathname, tmpname); + free(tmpname); /* Open the underlying file. */ - if (dwRetVal >= MAX_PATH || dwRetVal == 0 || - sprintf_s(obj->pathname, MAX_PATH, "%s\\tmp.XXXXXXXXXX", lpTempPathBuffer) <= 0 || - _mktemp_s(obj->pathname, MAX_PATH) || - (obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY | O_TEMPORARY | _O_SHORT_LIVED, + if ((obj->fd = open(obj->pathname, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | O_BINARY | O_TEMPORARY | _O_SHORT_LIVED, JAS_STREAM_PERMS)) < 0) { jas_stream_destroy(stream); return 0; From f75f2ffd48a4256dcb347cd79e241c07d9e3b419 Mon Sep 17 00:00:00 2001 From: Ashod Nakashian Date: Fri, 3 Apr 2015 20:59:13 -0400 Subject: [PATCH 4/4] Jpeg2k color to greyscale conversion on non-Windows is done post decoding because system libjasper segfaults when decoding color images as greyscale. --- modules/imgcodecs/src/grfmt_jpeg2000.cpp | 25 +++++++++++++++++++++++- modules/imgcodecs/src/loadsave.cpp | 9 +-------- modules/imgcodecs/test/test_grfmt.cpp | 22 +++++++++++++-------- 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/modules/imgcodecs/src/grfmt_jpeg2000.cpp b/modules/imgcodecs/src/grfmt_jpeg2000.cpp index 83fd55a594..e499c58b89 100644 --- a/modules/imgcodecs/src/grfmt_jpeg2000.cpp +++ b/modules/imgcodecs/src/grfmt_jpeg2000.cpp @@ -45,6 +45,7 @@ #ifdef HAVE_JASPER #include "grfmt_jpeg2000.hpp" +#include "opencv2/imgproc.hpp" #ifdef WIN32 #define JAS_WIN_MSVC_BUILD 1 @@ -159,6 +160,21 @@ bool Jpeg2KDecoder::readData( Mat& img ) jas_stream_t* stream = (jas_stream_t*)m_stream; jas_image_t* image = (jas_image_t*)m_image; +#ifndef WIN32 + // At least on some Linux instances the + // system libjasper segfaults when + // converting color to grey. + // We do this conversion manually at the end. + Mat clr; + if (CV_MAT_CN(img.type()) < CV_MAT_CN(this->type())) + { + clr.create(img.size().height, img.size().width, this->type()); + color = true; + data = clr.ptr(); + step = (int)clr.step; + } +#endif + if( stream && image ) { bool convert; @@ -171,7 +187,7 @@ bool Jpeg2KDecoder::readData( Mat& img ) else { convert = (jas_clrspc_fam( jas_image_clrspc( image ) ) != JAS_CLRSPC_FAM_GRAY); - colorspace = JAS_CLRSPC_SGRAY; // TODO GENGRAY or SGRAY? + colorspace = JAS_CLRSPC_SGRAY; // TODO GENGRAY or SGRAY? (GENGRAY fails on Win.) } // convert to the desired colorspace @@ -256,6 +272,13 @@ bool Jpeg2KDecoder::readData( Mat& img ) close(); +#ifndef WIN32 + if (!clr.empty()) + { + cv::cvtColor(clr, img, COLOR_BGR2GRAY); + } +#endif + return result; } diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 8526a4a3f0..383c25a2b3 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -374,15 +374,8 @@ imreadmulti_(const String& filename, int flags, std::vector& mats) type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1); } - // established the required input image size. - CvSize size; - size.width = decoder->width(); - size.height = decoder->height(); - - Mat mat; - mat.create(size.height, size.width, type); - // read the image data + Mat mat(decoder->height(), decoder->width(), type); if (!decoder->readData(mat)) { break; diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp index 5ef0164fec..92238a95f0 100644 --- a/modules/imgcodecs/test/test_grfmt.cpp +++ b/modules/imgcodecs/test/test_grfmt.cpp @@ -102,13 +102,17 @@ TEST(Imgcodecs_imread, regression) for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); ++i) { - ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_UNCHANGED)); - ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_GRAYSCALE)); - ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_COLOR)); - ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_ANYDEPTH)); - ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_ANYCOLOR)); - if (i != 2) // GDAL does not support hdr - ASSERT_TRUE(imread_compare(folder + string(filenames[i]), IMREAD_LOAD_GDAL)); + const string path = folder + string(filenames[i]); + ASSERT_TRUE(imread_compare(path, IMREAD_UNCHANGED)); + ASSERT_TRUE(imread_compare(path, IMREAD_GRAYSCALE)); + ASSERT_TRUE(imread_compare(path, IMREAD_COLOR)); + ASSERT_TRUE(imread_compare(path, IMREAD_ANYDEPTH)); + ASSERT_TRUE(imread_compare(path, IMREAD_ANYCOLOR)); + if (path.substr(path.length() - 3) != "hdr") + { + // GDAL does not support hdr + ASSERT_TRUE(imread_compare(path, IMREAD_LOAD_GDAL)); + } } } @@ -117,8 +121,10 @@ TEST(Imgcodecs_jasper, regression) { const string folder = string(cvtest::TS::ptr()->get_data_path()) + "/readwrite/"; - ASSERT_TRUE(imread_compare(folder + "Bretagne2.jp2", IMREAD_UNCHANGED)); + ASSERT_TRUE(imread_compare(folder + "Bretagne2.jp2", IMREAD_COLOR)); ASSERT_TRUE(imread_compare(folder + "Bretagne2.jp2", IMREAD_GRAYSCALE)); + ASSERT_TRUE(imread_compare(folder + "Grey.jp2", IMREAD_COLOR)); + ASSERT_TRUE(imread_compare(folder + "Grey.jp2", IMREAD_GRAYSCALE)); } #endif