Path: blob/master/modules/imgcodecs/src/grfmt_jpeg2000.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "precomp.hpp"4344#ifdef HAVE_JASPER4546#include "grfmt_jpeg2000.hpp"47#include "opencv2/imgproc.hpp"4849#ifdef _WIN3250#define JAS_WIN_MSVC_BUILD 151#ifdef __GNUC__52#define HAVE_STDINT_H 153#endif54#endif5556#undef VERSION5758#include <jasper/jasper.h>59// FIXME bad hack60#undef uchar61#undef ulong6263namespace cv64{6566struct JasperInitializer67{68JasperInitializer() { jas_init(); }69~JasperInitializer() { jas_cleanup(); }70};7172static JasperInitializer initialize_jasper;737475/////////////////////// Jpeg2KDecoder ///////////////////7677Jpeg2KDecoder::Jpeg2KDecoder()78{79static const unsigned char signature_[12] = { 0, 0, 0, 0x0c, 'j', 'P', ' ', ' ', 13, 10, 0x87, 10};80m_signature = String((const char*)signature_, (const char*)signature_ + sizeof(signature_));81m_stream = 0;82m_image = 0;83}848586Jpeg2KDecoder::~Jpeg2KDecoder()87{88}8990ImageDecoder Jpeg2KDecoder::newDecoder() const91{92return makePtr<Jpeg2KDecoder>();93}9495void Jpeg2KDecoder::close()96{97if( m_stream )98{99jas_stream_close( (jas_stream_t*)m_stream );100m_stream = 0;101}102103if( m_image )104{105jas_image_destroy( (jas_image_t*)m_image );106m_image = 0;107}108}109110111bool Jpeg2KDecoder::readHeader()112{113bool result = false;114115close();116jas_stream_t* stream = jas_stream_fopen( m_filename.c_str(), "rb" );117m_stream = stream;118119if( stream )120{121jas_image_t* image = jas_image_decode( stream, -1, 0 );122m_image = image;123if( image ) {124CV_Assert(0 == (jas_image_tlx(image)) && "not supported");125CV_Assert(0 == (jas_image_tly(image)) && "not supported");126m_width = jas_image_width( image );127m_height = jas_image_height( image );128129int cntcmpts = 0; // count the known components130int numcmpts = jas_image_numcmpts( image );131int depth = 0;132for( int i = 0; i < numcmpts; i++ )133{134int depth_i = jas_image_cmptprec( image, i );135CV_Assert(depth == 0 || depth == depth_i); // component data type mismatch136depth = MAX(depth, depth_i);137if( jas_image_cmpttype( image, i ) > 2 )138continue;139int sgnd = jas_image_cmptsgnd(image, i);140int xstart = jas_image_cmpttlx(image, i);141int xend = jas_image_cmptbrx(image, i);142int xstep = jas_image_cmpthstep(image, i);143int ystart = jas_image_cmpttly(image, i);144int yend = jas_image_cmptbry(image, i);145int ystep = jas_image_cmptvstep(image, i);146CV_Assert(sgnd == 0 && "not supported");147CV_Assert(xstart == 0 && "not supported");148CV_Assert(ystart == 0 && "not supported");149CV_Assert(xstep == 1 && "not supported");150CV_Assert(ystep == 1 && "not supported");151CV_Assert(xend == m_width);152CV_Assert(yend == m_height);153cntcmpts++;154}155156if( cntcmpts )157{158CV_Assert(depth == 8 || depth == 16);159CV_Assert(cntcmpts == 1 || cntcmpts == 3);160m_type = CV_MAKETYPE(depth <= 8 ? CV_8U : CV_16U, cntcmpts > 1 ? 3 : 1);161result = true;162}163}164}165166if( !result )167close();168169return result;170}171172static void Jpeg2KDecoder_close(Jpeg2KDecoder* ptr)173{174ptr->close();175}176177bool Jpeg2KDecoder::readData( Mat& img )178{179Ptr<Jpeg2KDecoder> close_this(this, Jpeg2KDecoder_close);180bool result = false;181bool color = img.channels() > 1;182uchar* data = img.ptr();183size_t step = img.step;184jas_stream_t* stream = (jas_stream_t*)m_stream;185jas_image_t* image = (jas_image_t*)m_image;186187#ifndef _WIN32188// At least on some Linux instances the189// system libjasper segfaults when190// converting color to grey.191// We do this conversion manually at the end.192Mat clr;193if (CV_MAT_CN(img.type()) < CV_MAT_CN(this->type()))194{195clr.create(img.size().height, img.size().width, this->type());196color = true;197data = clr.ptr();198step = (int)clr.step;199}200#endif201202if( stream && image )203{204bool convert;205int colorspace;206if( color )207{208convert = (jas_image_clrspc( image ) != JAS_CLRSPC_SRGB);209colorspace = JAS_CLRSPC_SRGB;210}211else212{213convert = (jas_clrspc_fam( jas_image_clrspc( image ) ) != JAS_CLRSPC_FAM_GRAY);214colorspace = JAS_CLRSPC_SGRAY; // TODO GENGRAY or SGRAY? (GENGRAY fails on Win.)215}216217// convert to the desired colorspace218if( convert )219{220jas_cmprof_t *clrprof = jas_cmprof_createfromclrspc( colorspace );221if( clrprof )222{223jas_image_t *_img = jas_image_chclrspc( image, clrprof, JAS_CMXFORM_INTENT_RELCLR );224if( _img )225{226jas_image_destroy( image );227m_image = image = _img;228result = true;229}230else231{232jas_cmprof_destroy(clrprof);233CV_Error(Error::StsError, "JPEG 2000 LOADER ERROR: cannot convert colorspace");234}235jas_cmprof_destroy( clrprof );236}237else238{239CV_Error(Error::StsError, "JPEG 2000 LOADER ERROR: unable to create colorspace");240}241}242else243result = true;244245if( result )246{247int ncmpts;248int cmptlut[3];249if( color )250{251cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_B );252cmptlut[1] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_G );253cmptlut[2] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_RGB_R );254if( cmptlut[0] < 0 || cmptlut[1] < 0 || cmptlut[2] < 0 )255result = false;256ncmpts = 3;257}258else259{260cmptlut[0] = jas_image_getcmptbytype( image, JAS_IMAGE_CT_GRAY_Y );261if( cmptlut[0] < 0 )262result = false;263ncmpts = 1;264}265266if( result )267{268for( int i = 0; i < ncmpts; i++ )269{270int maxval = 1 << jas_image_cmptprec( image, cmptlut[i] );271int offset = jas_image_cmptsgnd( image, cmptlut[i] ) ? maxval / 2 : 0;272273int yend = jas_image_cmptbry( image, cmptlut[i] );274int ystep = jas_image_cmptvstep( image, cmptlut[i] );275int xend = jas_image_cmptbrx( image, cmptlut[i] );276int xstep = jas_image_cmpthstep( image, cmptlut[i] );277278jas_matrix_t *buffer = jas_matrix_create( yend / ystep, xend / xstep );279if( buffer )280{281if( !jas_image_readcmpt( image, cmptlut[i], 0, 0, xend / xstep, yend / ystep, buffer ))282{283if( img.depth() == CV_8U )284result = readComponent8u( data + i, buffer, validateToInt(step), cmptlut[i], maxval, offset, ncmpts );285else286result = readComponent16u( ((unsigned short *)data) + i, buffer, validateToInt(step / 2), cmptlut[i], maxval, offset, ncmpts );287if( !result )288{289jas_matrix_destroy( buffer );290CV_Error(Error::StsError, "JPEG2000 LOADER ERROR: failed to read component");291}292}293jas_matrix_destroy( buffer );294}295}296}297}298else299{300CV_Error(Error::StsError, "JPEG2000 LOADER ERROR: colorspace conversion failed");301}302}303304CV_Assert(result == true);305306#ifndef _WIN32307if (!clr.empty())308{309cv::cvtColor(clr, img, COLOR_BGR2GRAY);310}311#endif312313return result;314}315316317bool Jpeg2KDecoder::readComponent8u( uchar *data, void *_buffer,318int step, int cmpt,319int maxval, int offset, int ncmpts )320{321jas_matrix_t* buffer = (jas_matrix_t*)_buffer;322jas_image_t* image = (jas_image_t*)m_image;323int xstart = jas_image_cmpttlx( image, cmpt );324int xend = jas_image_cmptbrx( image, cmpt );325int xstep = jas_image_cmpthstep( image, cmpt );326int xoffset = jas_image_tlx( image );327int ystart = jas_image_cmpttly( image, cmpt );328int yend = jas_image_cmptbry( image, cmpt );329int ystep = jas_image_cmptvstep( image, cmpt );330int yoffset = jas_image_tly( image );331int x, y, x1, y1, j;332int rshift = cvRound(std::log(maxval/256.)/std::log(2.));333int lshift = MAX(0, -rshift);334rshift = MAX(0, rshift);335int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset;336337for( y = 0; y < yend - ystart; )338{339jas_seqent_t* pix_row = &jas_matrix_get( buffer, y / ystep, 0 );340uchar* dst = data + (y - yoffset) * step - xoffset;341342if( xstep == 1 )343{344if( maxval == 256 && offset == 0 )345for( x = 0; x < xend - xstart; x++ )346{347int pix = pix_row[x];348dst[x*ncmpts] = cv::saturate_cast<uchar>(pix);349}350else351for( x = 0; x < xend - xstart; x++ )352{353int pix = ((pix_row[x] + delta) >> rshift) << lshift;354dst[x*ncmpts] = cv::saturate_cast<uchar>(pix);355}356}357else if( xstep == 2 && offset == 0 )358for( x = 0, j = 0; x < xend - xstart; x += 2, j++ )359{360int pix = ((pix_row[j] + delta) >> rshift) << lshift;361dst[x*ncmpts] = dst[(x+1)*ncmpts] = cv::saturate_cast<uchar>(pix);362}363else364for( x = 0, j = 0; x < xend - xstart; j++ )365{366int pix = ((pix_row[j] + delta) >> rshift) << lshift;367pix = cv::saturate_cast<uchar>(pix);368for( x1 = x + xstep; x < x1; x++ )369dst[x*ncmpts] = (uchar)pix;370}371y1 = y + ystep;372for( ++y; y < y1; y++, dst += step )373for( x = 0; x < xend - xstart; x++ )374dst[x*ncmpts + step] = dst[x*ncmpts];375}376377return true;378}379380381bool Jpeg2KDecoder::readComponent16u( unsigned short *data, void *_buffer,382int step, int cmpt,383int maxval, int offset, int ncmpts )384{385jas_matrix_t* buffer = (jas_matrix_t*)_buffer;386jas_image_t* image = (jas_image_t*)m_image;387int xstart = jas_image_cmpttlx( image, cmpt );388int xend = jas_image_cmptbrx( image, cmpt );389int xstep = jas_image_cmpthstep( image, cmpt );390int xoffset = jas_image_tlx( image );391int ystart = jas_image_cmpttly( image, cmpt );392int yend = jas_image_cmptbry( image, cmpt );393int ystep = jas_image_cmptvstep( image, cmpt );394int yoffset = jas_image_tly( image );395int x, y, x1, y1, j;396int rshift = cvRound(std::log(maxval/65536.)/std::log(2.));397int lshift = MAX(0, -rshift);398rshift = MAX(0, rshift);399int delta = (rshift > 0 ? 1 << (rshift - 1) : 0) + offset;400401for( y = 0; y < yend - ystart; )402{403jas_seqent_t* pix_row = &jas_matrix_get( buffer, y / ystep, 0 );404ushort* dst = data + (y - yoffset) * step - xoffset;405406if( xstep == 1 )407{408if( maxval == 65536 && offset == 0 )409for( x = 0; x < xend - xstart; x++ )410{411int pix = pix_row[x];412dst[x*ncmpts] = cv::saturate_cast<ushort>(pix);413}414else415for( x = 0; x < xend - xstart; x++ )416{417int pix = ((pix_row[x] + delta) >> rshift) << lshift;418dst[x*ncmpts] = cv::saturate_cast<ushort>(pix);419}420}421else if( xstep == 2 && offset == 0 )422for( x = 0, j = 0; x < xend - xstart; x += 2, j++ )423{424int pix = ((pix_row[j] + delta) >> rshift) << lshift;425dst[x*ncmpts] = dst[(x+1)*ncmpts] = cv::saturate_cast<ushort>(pix);426}427else428for( x = 0, j = 0; x < xend - xstart; j++ )429{430int pix = ((pix_row[j] + delta) >> rshift) << lshift;431pix = cv::saturate_cast<ushort>(pix);432for( x1 = x + xstep; x < x1; x++ )433dst[x*ncmpts] = (ushort)pix;434}435y1 = y + ystep;436for( ++y; y < y1; y++, dst += step )437for( x = 0; x < xend - xstart; x++ )438dst[x*ncmpts + step] = dst[x*ncmpts];439}440441return true;442}443444445/////////////////////// Jpeg2KEncoder ///////////////////446447448Jpeg2KEncoder::Jpeg2KEncoder()449{450m_description = "JPEG-2000 files (*.jp2)";451}452453454Jpeg2KEncoder::~Jpeg2KEncoder()455{456}457458ImageEncoder Jpeg2KEncoder::newEncoder() const459{460return makePtr<Jpeg2KEncoder>();461}462463bool Jpeg2KEncoder::isFormatSupported( int depth ) const464{465return depth == CV_8U || depth == CV_16U;466}467468469bool Jpeg2KEncoder::write( const Mat& _img, const std::vector<int>& )470{471int width = _img.cols, height = _img.rows;472int depth = _img.depth(), channels = _img.channels();473depth = depth == CV_8U ? 8 : 16;474475if( channels > 3 || channels < 1 )476return false;477478jas_image_cmptparm_t component_info[3];479for( int i = 0; i < channels; i++ )480{481component_info[i].tlx = 0;482component_info[i].tly = 0;483component_info[i].hstep = 1;484component_info[i].vstep = 1;485component_info[i].width = width;486component_info[i].height = height;487component_info[i].prec = depth;488component_info[i].sgnd = 0;489}490jas_image_t *img = jas_image_create( channels, component_info, (channels == 1) ? JAS_CLRSPC_SGRAY : JAS_CLRSPC_SRGB );491if( !img )492return false;493494if(channels == 1)495jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_GRAY_Y );496else497{498jas_image_setcmpttype( img, 0, JAS_IMAGE_CT_RGB_B );499jas_image_setcmpttype( img, 1, JAS_IMAGE_CT_RGB_G );500jas_image_setcmpttype( img, 2, JAS_IMAGE_CT_RGB_R );501}502503bool result;504if( depth == 8 )505result = writeComponent8u( img, _img );506else507result = writeComponent16u( img, _img );508if( result )509{510jas_stream_t *stream = jas_stream_fopen( m_filename.c_str(), "wb" );511if( stream )512{513result = !jas_image_encode( img, stream, jas_image_strtofmt( (char*)"jp2" ), (char*)"" );514515jas_stream_close( stream );516}517518}519jas_image_destroy( img );520521return result;522}523524525bool Jpeg2KEncoder::writeComponent8u( void *__img, const Mat& _img )526{527jas_image_t* img = (jas_image_t*)__img;528int w = _img.cols, h = _img.rows, ncmpts = _img.channels();529jas_matrix_t *row = jas_matrix_create( 1, w );530if(!row)531return false;532533for( int y = 0; y < h; y++ )534{535const uchar* data = _img.ptr(y);536for( int i = 0; i < ncmpts; i++ )537{538for( int x = 0; x < w; x++)539jas_matrix_setv( row, x, data[x * ncmpts + i] );540jas_image_writecmpt( img, i, 0, y, w, 1, row );541}542}543544jas_matrix_destroy( row );545return true;546}547548549bool Jpeg2KEncoder::writeComponent16u( void *__img, const Mat& _img )550{551jas_image_t* img = (jas_image_t*)__img;552int w = _img.cols, h = _img.rows, ncmpts = _img.channels();553jas_matrix_t *row = jas_matrix_create( 1, w );554if(!row)555return false;556557for( int y = 0; y < h; y++ )558{559const ushort* data = _img.ptr<ushort>(y);560for( int i = 0; i < ncmpts; i++ )561{562for( int x = 0; x < w; x++)563jas_matrix_setv( row, x, data[x * ncmpts + i] );564jas_image_writecmpt( img, i, 0, y, w, 1, row );565}566}567568jas_matrix_destroy( row );569570return true;571}572573}574575#endif576577/* End of file. */578579580