forked from jbresearch/cr2_scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jbcr2.py
173 lines (153 loc) · 5.71 KB
/
jbcr2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2015-2018 Johann A. Briffa
#
# This file is part of CR2_Scripts.
#
# CR2_Scripts is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CR2_Scripts is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CR2_Scripts. If not, see <http:https://www.gnu.org/licenses/>.
import os
import tempfile
import commands
import numpy as np
## replace data strips for specified IFD
def replace_ifd(tiff, k, data):
print "IFD#%d: Replacing data strip with length %d" % (k, len(data))
# get references to required IFD
IFD, ifd_offset, strips = tiff.data[k]
# replace data strips with new data
assert strips
del strips[:]
strips.append(data)
# update IFD data
if 273 in IFD:
assert 279 in IFD
assert 513 not in IFD and 514 not in IFD
IFD[279] = (4, 1, [len(data)], 0)
elif 513 in IFD:
assert 514 in IFD
assert 273 not in IFD and 279 not in IFD
IFD[514] = (4, 1, [len(data)], 0)
else:
raise AssertionError("Reference to data strip not found in IFD#%d" % k)
return
## convert lossless JPEG encoded input file to raw data
def decode_lossless_jpeg(filename):
# create folder for temporary files
tmpfolder = tempfile.mkdtemp()
# decode input file with Stanford PVRG software
cmd = 'pvrg-jpeg -d -s "%s" -o "%s"' % (filename, os.path.join(tmpfolder, "parts"))
st, out = commands.getstatusoutput(cmd)
if st != 0:
raise AssertionError('Error decoding JPEG file: %s' % out)
# Laurent Clévy's example:
# Image (w x h): 5184 x 3456
# 4 color components (w x h): 0x538 x 0xdbc = 1336 x 3516 each
# interleaved components: 5344 x 3516
# border: 160 x 60 on declared image size
# 3 slices (w): 2x 0x6c0 + 0x760 = 2x 1728 + 1888 = 5344
# each slice takes: 432 pixels from each of 4 colors (first two)
# 472 pixels from each of 4 colors (last one)
# interpret output to determine the number of color components and precision
component_list = []
precision = None
for line in out.split('\n'):
if line.startswith('>> '):
record = line.split()
f = record[4]
w = int(record[6])
h = int(record[8])
component_list.append((f,w,h))
elif line.startswith('Caution: precision type:'):
record = line.split()
precision = int(record[3])
print "RAW data precision: %d" % precision
# number of color components
n = len(component_list)
# first assemble color components
width = sum([w for f,w,h in component_list])
height = component_list[0][2]
assert all([h == height for f,w,h in component_list])
a = np.zeros((height, width), dtype=np.dtype('>H'))
for i, (f,w,h) in enumerate(component_list):
# read raw data for this component
b = np.fromfile(f, dtype=np.dtype('>H'))
b.shape = (h,w)
# insert into assembled color image
a[:,i::n] = b
# remove temporary file
os.remove(f)
# remove (empty) temporary folder
os.rmdir(tmpfolder)
return a, len(component_list), precision
## encode raw image to lossless JPEG output file
def encode_lossless_jpeg(a, components, precision, filename):
# create folder for temporary files
tmpfolder = tempfile.mkdtemp()
# determine image size
height, width = a.shape
# determine color components to create
component_list = []
for i in range(components):
f = os.path.join(tmpfolder, 'parts.%d' % (i+1))
component_list.append(f)
# next split color components
parts = []
for i, f in enumerate(component_list):
# space for raw data for this color component
b = np.zeros((height, width / components), dtype=np.dtype('>H'))
# extract data from sliced color image
b = a[:,i::components]
# save to file
b.tofile(f)
# keep a copy to return to caller
parts.append(b)
# convert raw data color components to lossless JPEG encoded file
cmd = 'pvrg-jpeg -ih %d -iw %d -k 1 -p %d -s "%s"' % \
(height, width / components, precision, filename)
for i, f in enumerate(component_list):
cmd += ' -ci %d %s' % (i+1, f)
st, out = commands.getstatusoutput(cmd)
if st != 0:
raise AssertionError('Error encoding JPEG file: %s' % out)
# remove temporary files
for i, f in enumerate(component_list):
os.remove(f)
# remove (empty) temporary folder
os.rmdir(tmpfolder)
return parts
## unslice sensor image
def unslice_image(a, width, height, slices):
# make a list of the width of each slice
slice_widths = [slices[1]] * slices[0] + [slices[2]]
assert sum(slice_widths) == width
# unslice image
I = np.zeros((height, width), dtype=np.dtype('>H'))
for i, sw in enumerate(slice_widths):
col_s = sum(slice_widths[0:i])
col_e = col_s + sw
I[:,col_s:col_e] = a.flat[col_s*height:col_e*height].reshape(height,sw)
return I
## slice sensor image
def slice_image(I, width, height, slices):
# make a list of the width of each slice
slice_widths = [slices[1]] * slices[0] + [slices[2]]
assert sum(slice_widths) == width
# slice image
a = np.zeros((height, width), dtype=np.dtype('>H'))
for i, sw in enumerate(slice_widths):
col_s = sum(slice_widths[0:i])
col_e = col_s + sw
a.flat[col_s*height:col_e*height] = I[:,col_s:col_e].flat
return a