Cinema4K seems to be working. #139

This commit is contained in:
John Evans 2014-03-07 11:00:20 -05:00
commit d68b1aacb1
5 changed files with 108 additions and 17 deletions

View file

@ -1,4 +1,4 @@
Mar 06, 2014 - Added Cinema2K write support. Mar 06, 2014 - Added Cinema2K, Cinema4K write support.
Changed constructor for ChannelDefinition box. Removed support Changed constructor for ChannelDefinition box. Removed support
for Python 2.6. Added write support for JP2 UUID, DataEntryURL, for Python 2.6. Added write support for JP2 UUID, DataEntryURL,
Palette and Component Mapping boxes, JPX Association, NumberList Palette and Component Mapping boxes, JPX Association, NumberList

View file

@ -5,7 +5,7 @@ ChangeLog
0.6.0 (pending) 0.6.0 (pending)
=============== ===============
* Added Cinema2K write support. * Added Cinema2K, Cinema4K write support.
* Added lxml requirement. * Added lxml requirement.
* added set_printoptions, get_printoptions function * added set_printoptions, get_printoptions function
* dropped support for Python 2.6, added support for Python 3.4 * dropped support for Python 2.6, added support for Python 3.4

View file

@ -13,7 +13,7 @@ both read and write JPEG 2000 files, but you may wish to install version 2.0
or the 2.0+ version from OpenJPEG's development trunk for better performance. or the 2.0+ version from OpenJPEG's development trunk for better performance.
If you do that, you should compile it as a shared library (named *openjp2* If you do that, you should compile it as a shared library (named *openjp2*
instead of *openjpeg*) from the developmental source that you can retrieve instead of *openjpeg*) from the developmental source that you can retrieve
via subversion. As of this time of writing, svn revision r2366 works. via subversion. As of this time of writing, svn revision r2369 works.
You should also download the test data for the purpose of configuring You should also download the test data for the purpose of configuring
and running OpenJPEG's test suite, check their instructions for all this. and running OpenJPEG's test suite, check their instructions for all this.
You should set the **OPJ_DATA_ROOT** environment variable for the purpose You should set the **OPJ_DATA_ROOT** environment variable for the purpose

View file

@ -163,22 +163,32 @@ class Jp2k(Jp2kBox):
msg += "profile if the file type box brand is 'jp2 '." msg += "profile if the file type box brand is 'jp2 '."
warnings.warn(msg) warnings.warn(msg)
def _set_cinema_params(self, cparams, fps): def _set_cinema_params(self, cparams, cinema_mode, fps):
"""Populate compression parameters structure for cinema2K. """Populate compression parameters structure for cinema2K.
Parameters Parameters
---------- ----------
params : ctypes struct
Corresponds to compression parameters structure used by the
library.
cinema_mode : str
Either 'cinema2k' or 'cinema4k'
fps : int fps : int
Frames per second, should be either 24 or 48. Frames per second, should be either 24 or 48.
""" """
if fps == 24: if cinema_mode == 'cinema2k':
cparams.cp_cinema = CINEMA_MODE['cinema2k_24'] if fps == 24:
elif fps == 48: cparams.cp_cinema = CINEMA_MODE['cinema2k_24']
cparams.cp_cinema = CINEMA_MODE['cinema2k_48'] elif fps == 48:
cparams.cp_cinema = CINEMA_MODE['cinema2k_48']
else:
raise IOError('Cinema2K frame rate must be either 24 or 48.')
cparams.cp_rsiz = RSIZ['CINEMA2K']
else: else:
raise IOError('Cinema2K frame rate must be either 24 or 48.') cparams.cp_cinema = CINEMA_MODE['cinema4k_24']
cparams.cp_rsiz = RSIZ['CINEMA4K']
cparams.cp_rsiz = RSIZ['CINEMA2K']
# No tiling # No tiling
cparams.tile_size_on = opj2.FALSE cparams.tile_size_on = opj2.FALSE
cparams.cp_tdx = 1 cparams.cp_tdx = 1
@ -216,9 +226,17 @@ class Jp2k(Jp2kBox):
# TODO: warning or error # TODO: warning or error
cparams.tcp_numlayers = 1 cparams.tcp_numlayers = 1
if cparams.numresolution > 6: #TODO only for cinema2k if cinema_mode == 'cinema2k':
# TODO: warning or error if cparams.numresolution > 6:
cparams.numresolution = 6 # TODO: warning or error
cparams.numresolution = 6
else:
if cparams.numresolution < 2:
# TODO: warning or error
cparams.numresolution = 1
elif cparams.numresolution > 7:
cparams.numresolution = 7
# precincts # precincts
cparams.csty |= 0x01 cparams.csty |= 0x01
@ -230,8 +248,25 @@ class Jp2k(Jp2kBox):
# Progression order shall be CPRL # Progression order shall be CPRL
cparams.prog_order = PROGRESSION_ORDER['CPRL'] cparams.prog_order = PROGRESSION_ORDER['CPRL']
# progression order changes not allowed for 2K # TODO not for 4K: # progression order changes not allowed for 2K
cparams.numpocs = 0 if cinema_mode == 'cinema2k':
cparams.numpocs = 0
else:
cparams.poc[0].tile = 1
cparams.poc[0].resno0 = 0
cparams.poc[0].compno0 = 0
cparams.poc[0].layno1 = 1
cparams.poc[0].resno1 = cparams.numresolution - 1
cparams.poc[0].compno1 = 3
cparams.poc[0].prg1 = PROGRESSION_ORDER['CPRL']
cparams.poc[1].tile = 1
cparams.poc[1].resno0 = 0
cparams.poc[1].compno0 = 0
cparams.poc[1].layno1 = 1
cparams.poc[1].resno1 = cparams.numresolution
cparams.poc[1].compno1 = 3
cparams.poc[1].prg1 = PROGRESSION_ORDER['CPRL']
cparams.numpocs = 2
def _populate_cparams(self, **kwargs): def _populate_cparams(self, **kwargs):
"""Populate compression parameters structure from input arguments. """Populate compression parameters structure from input arguments.
@ -300,11 +335,11 @@ class Jp2k(Jp2kBox):
cparams.cp_disto_alloc = 1 cparams.cp_disto_alloc = 1
if 'cinema2k' in kwargs: if 'cinema2k' in kwargs:
self._set_cinema_params(cparams, kwargs['cinema2k']) self._set_cinema_params(cparams, 'cinema2k', kwargs['cinema2k'])
return cparams return cparams
if 'cinema4k' in kwargs: if 'cinema4k' in kwargs:
self._set_cinema_params(cparams, kwargs['cinema2k']) self._set_cinema_params(cparams, 'cinema4k', kwargs['cinema4k'])
return cparams return cparams
if 'cbsize' in kwargs: if 'cbsize' in kwargs:

View file

@ -44,6 +44,48 @@ class TestSuiteWrite(unittest.TestCase):
def tearDown(self): def tearDown(self):
pass pass
def check_cinema4k_codestream(self, codestream, image_size):
"""Common out for cinema2k tests."""
# SIZ: Image and tile size
# Profile: "3" means cinema2K
self.assertEqual(codestream.segment[1].rsiz, 4)
# Reference grid size
self.assertEqual((codestream.segment[1].xsiz,
codestream.segment[1].ysiz),
image_size)
# Reference grid offset
self.assertEqual((codestream.segment[1].xosiz,
codestream.segment[1].yosiz), (0, 0))
# Tile size
self.assertEqual((codestream.segment[1].xtsiz,
codestream.segment[1].ytsiz),
image_size)
# Tile offset
self.assertEqual((codestream.segment[1].xtosiz,
codestream.segment[1].ytosiz),
(0, 0))
# bitdepth
self.assertEqual(codestream.segment[1].bitdepth, (12, 12, 12))
# signed
self.assertEqual(codestream.segment[1].signed,
(False, False, False))
# subsampling
self.assertEqual(list(zip(codestream.segment[1].xrsiz,
codestream.segment[1].yrsiz)),
[(1, 1)] * 3)
# COD: Coding style default
self.assertFalse(codestream.segment[2].scod & 2) # no sop
self.assertFalse(codestream.segment[2].scod & 4) # no eph
self.assertEqual(codestream.segment[2].spcod[0], glymur.core.CPRL)
self.assertEqual(codestream.segment[2].layers, 1)
self.assertEqual(codestream.segment[2].spcod[3], 1) # mct
self.assertEqual(codestream.segment[2].spcod[4], 5) # levels
self.assertEqual(tuple(codestream.segment[2].code_block_size),
(32, 32)) # cblksz
def check_cinema2k_codestream(self, codestream, image_size): def check_cinema2k_codestream(self, codestream, image_size):
"""Common out for cinema2k tests.""" """Common out for cinema2k tests."""
# SIZ: Image and tile size # SIZ: Image and tile size
@ -86,6 +128,20 @@ class TestSuiteWrite(unittest.TestCase):
@unittest.skipIf(not _HAS_SKIMAGE_FREEIMAGE_SUPPORT,
"Cannot read input image without scikit-image/freeimage")
def test_NR_ENC_ElephantDream_4K_tif_21_encode(self):
relfile = 'input/nonregression/ElephantDream_4K.tif'
infile = opj_data_file(relfile)
data = skimage.io.imread(infile)
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
j = Jp2k(tfile.name, 'wb')
j.write(data, cinema4k=True)
codestream = j.get_codestream()
self.check_cinema4k_codestream(codestream, (4096, 2160))
@unittest.skipIf(not _HAS_SKIMAGE_FREEIMAGE_SUPPORT, @unittest.skipIf(not _HAS_SKIMAGE_FREEIMAGE_SUPPORT,
"Cannot read input image without scikit-image/freeimage") "Cannot read input image without scikit-image/freeimage")
def test_NR_ENC_X_5_2K_24_235_CBR_STEM24_000_tif_19_encode(self): def test_NR_ENC_X_5_2K_24_235_CBR_STEM24_000_tif_19_encode(self):