Cinema4K seems to be working. #139
This commit is contained in:
parent
af4b6e64bf
commit
d68b1aacb1
5 changed files with 108 additions and 17 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue