Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
python3-convert-jp4
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Elphel
python3-convert-jp4
Commits
1213b32b
Commit
1213b32b
authored
Jun 07, 2018
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
initial + splitting composite images
parent
58bb6b94
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
663 additions
and
0 deletions
+663
-0
elphel_exif.py
elphel_exif.py
+176
-0
jp4-to-png.py
jp4-to-png.py
+89
-0
jp4.py
jp4.py
+398
-0
No files found.
elphel_exif.py
0 → 100644
View file @
1213b32b
__author__
=
"Oleg Dzhimiev"
__copyright__
=
"Copyright (C) 2018 Elphel Inc."
__license__
=
"GPL-3.0+"
__email__
=
"oleg@elphel.com"
'''
Example usage:
test.py:
import elphel_exif
info = elphel_exif.Exif("test.jpeg")
print(info)
print(info.MakerNote)
print(info.exif.toString())
'''
from
PIL
import
Image
from
PIL.ExifTags
import
TAGS
,
GPSTAGS
# Might be needed by some applications like:
# panoramic of Eyesis4Pi, composite images
def
elphel_add_to_PIL_TAGS
():
TAGS
[
0x0129
]
=
'Page'
TAGS
[
0xC62F
]
=
'Camera Serial Number'
# Open file and Parse
def
elphel_get_exif
(
f
):
ret
=
{}
i
=
Image
.
open
(
f
)
info
=
i
.
_getexif
()
elphel_add_to_PIL_TAGS
()
for
tag
,
value
in
info
.
items
():
decoded
=
TAGS
.
get
(
tag
,
tag
)
if
decoded
==
'GPSInfo'
:
gret
=
{}
for
gtag
,
gval
in
value
.
items
():
gdecoded
=
GPSTAGS
.
get
(
gtag
,
gtag
)
gret
[
gdecoded
]
=
gval
value
=
gret
if
decoded
==
'MakerNote'
:
value
=
elphel_MakerNote_parse
(
value
)
ret
[
decoded
]
=
value
return
ret
# Init with default values
def
elphel_MakerNote_defaults
():
ret
=
{}
# defaults
ret
[
'COLOR_MODE'
]
=
0
return
ret
# Based on JP46_Reader_camera.java's jp46Reorder()
def
elphel_MakerNote_parse
(
MakerNote
):
ret
=
{}
ret
=
elphel_MakerNote_defaults
()
ret
[
'GAIN_R'
]
=
MakerNote
[
0
]
/
65536.0
ret
[
'GAIN_G'
]
=
MakerNote
[
1
]
/
65536.0
ret
[
'GAIN_GB'
]
=
MakerNote
[
2
]
/
65536.0
ret
[
'GAIN_B'
]
=
MakerNote
[
3
]
/
65536.0
ret
[
'BLACK_R'
]
=
(
MakerNote
[
4
]
>>
24
)
/
256.0
ret
[
'BLACK_G'
]
=
(
MakerNote
[
5
]
>>
24
)
/
256.0
ret
[
'BLACK_GB'
]
=
(
MakerNote
[
6
]
>>
24
)
/
256.0
ret
[
'BLACK_B'
]
=
(
MakerNote
[
7
]
>>
24
)
/
256.0
ret
[
'GAMMA_R'
]
=
((
MakerNote
[
4
]
>>
16
)
&
0xff
)
/
100.0
ret
[
'GAMMA_G'
]
=
((
MakerNote
[
5
]
>>
16
)
&
0xff
)
/
100.0
ret
[
'GAMMA_GB'
]
=
((
MakerNote
[
6
]
>>
16
)
&
0xff
)
/
100.0
ret
[
'GAMMA_B'
]
=
((
MakerNote
[
7
]
>>
16
)
&
0xff
)
/
100.0
ret
[
'GAMMA_SCALE_R'
]
=
MakerNote
[
4
]
&
0xffff
ret
[
'GAMMA_SCALE_G'
]
=
MakerNote
[
5
]
&
0xffff
ret
[
'GAMMA_SCALE_GB'
]
=
MakerNote
[
6
]
&
0xffff
ret
[
'GAMMA_SCALE_B'
]
=
MakerNote
[
7
]
&
0xffff
if
len
(
MakerNote
)
>=
14
:
if
(
MakerNote
[
10
]
&
0xc0000000
)
!=
0
:
composite
=
1
else
:
composite
=
0
ret
[
'COMPOSITE'
]
=
composite
if
composite
:
ret
[
'HEIGHT1'
]
=
MakerNote
[
11
]
&
0xffff
ret
[
'BLANK1'
]
=
(
MakerNote
[
11
]
>>
16
)
&
0xffff
ret
[
'HEIGHT2'
]
=
MakerNote
[
12
]
&
0xffff
ret
[
'BLANK2'
]
=
(
MakerNote
[
12
]
>>
16
)
&
0xffff
ret
[
'HEIGHT3'
]
=
(
MakerNote
[
9
]
>>
16
)
-
ret
[
'HEIGHT1'
]
-
ret
[
'BLANK1'
]
-
ret
[
'HEIGHT2'
]
-
ret
[
'BLANK2'
]
ret
[
'FLIPH1'
]
=
(
MakerNote
[
10
]
>>
24
)
&
0x1
ret
[
'FLIPV1'
]
=
(
MakerNote
[
10
]
>>
25
)
&
0x1
ret
[
'FLIPH2'
]
=
(
MakerNote
[
10
]
>>
26
)
&
0x1
ret
[
'FLIPV2'
]
=
(
MakerNote
[
10
]
>>
27
)
&
0x1
ret
[
'FLIPH3'
]
=
(
MakerNote
[
10
]
>>
28
)
&
0x1
ret
[
'FLIPV3'
]
=
(
MakerNote
[
10
]
>>
29
)
&
0x1
ret
[
'PORTRAIT'
]
=
(
MakerNote
[
13
]
>>
7
)
&
0x1
ret
[
'YTABLEFORC'
]
=
(
MakerNote
[
13
]
>>
15
)
&
0x1
ret
[
'QUALITY'
]
=
MakerNote
[
13
]
&
0x7f
ret
[
'CQUALITY'
]
=
(
MakerNote
[
13
]
>>
8
)
&
0x7f
if
ret
[
'CQUALITY'
]
==
0
:
ret
[
'CQUALITY'
]
=
ret
[
'QUALITY'
]
ret
[
'CORING_INDEX_Y'
]
=
(
MakerNote
[
13
]
>>
16
)
&
0x7f
ret
[
'CORING_INDEX_C'
]
=
(
MakerNote
[
13
]
>>
24
)
&
0x7f
if
ret
[
'CORING_INDEX_C'
]
==
0
:
ret
[
'CORING_INDEX_C'
]
=
ret
[
'CORING_INDEX_Y'
]
if
len
(
MakerNote
)
>=
12
:
ret
[
'WOI_LEFT'
]
=
MakerNote
[
8
]
&
0xffff
ret
[
'WOI_WIDTH'
]
=
MakerNote
[
8
]
>>
16
ret
[
'WOI_TOP'
]
=
MakerNote
[
9
]
&
0xffff
ret
[
'WOI_HEIGHT'
]
=
MakerNote
[
9
]
>>
16
ret
[
'FLIPH'
]
=
MakerNote
[
10
]
&
0x1
ret
[
'FLIPV'
]
=
(
MakerNote
[
10
]
>>
1
)
&
0x1
ret
[
'BAYER_MODE'
]
=
(
MakerNote
[
10
]
>>
2
)
&
0x3
ret
[
'COLOR_MODE'
]
=
(
MakerNote
[
10
]
>>
4
)
&
0x0f
ret
[
'DCM_HOR'
]
=
(
MakerNote
[
10
]
>>
8
)
&
0x0f
ret
[
'DCM_VERT'
]
=
(
MakerNote
[
10
]
>>
12
)
&
0x0f
ret
[
'BIN_HOR'
]
=
(
MakerNote
[
10
]
>>
16
)
&
0x0f
ret
[
'BIN_VERT'
]
=
(
MakerNote
[
10
]
>>
20
)
&
0x0f
# HW specific temperature readings
if
len
(
MakerNote
)
>=
16
:
ret
[
'TEMP1'
]
=
(
MakerNote
[
14
]
>>
0
)
&
0xffff
ret
[
'TEMP2'
]
=
(
MakerNote
[
14
]
>>
16
)
&
0xffff
ret
[
'TEMP3'
]
=
(
MakerNote
[
14
]
>>
0
)
&
0xffff
ret
[
'TEMP4'
]
=
(
MakerNote
[
14
]
>>
16
)
&
0xffff
return
ret
# Class
class
Exif
:
def
__init__
(
self
,
f
):
self
.
f
=
f
self
.
data
=
elphel_get_exif
(
f
)
self
.
MakerNote
=
self
.
data
[
'MakerNote'
]
#self.color_mode = self.data['MakerNote']['COLOR_MODE']
def
toString
(
self
):
res
=
''
for
k
in
self
.
data
:
if
k
!=
'MakerNote'
:
res
+=
str
(
k
)
+
": "
+
str
(
self
.
data
[
k
])
+
"
\n
"
res
+=
"MakerNote:
\n
"
for
k
in
self
.
data
[
'MakerNote'
]:
res
+=
" "
+
str
(
k
)
+
": "
+
str
(
self
.
data
[
'MakerNote'
][
k
])
+
"
\n
"
return
res
[:
-
1
]
jp4-to-png.py
0 → 100644
View file @
1213b32b
#!/usr/bin/env python3
import
jp4
#import cv2
import
numpy
as
np
import
sys
from
PIL
import
Image
,
ImageOps
try
:
filename
=
sys
.
argv
[
1
]
except
IndexError
:
filename
=
"test.jp4"
img
=
jp4
.
JP4
(
filename
)
# print exif
#print(img.exif.toString())
# deblock if JP4 (auto read from exif) skip if other
img
.
deblock
()
img
.
demosaic_bilinear
()
img
.
saturation
()
I
=
img
.
image
[
...
,[
2
,
1
,
0
]]
.
astype
(
np
.
uint8
)
res
=
Image
.
fromarray
(
I
)
#res.save("result.png")
# also works
#res.save("result.jpeg")
# for Eyesis4pi
exif
=
img
.
exif
mn
=
exif
.
MakerNote
#print(exif.MakerNote)
# common
# WOI_WIDTH
# FLIPH
# FLIPV
# PORTRAIT
# COMPOSITE
# individual
# HEIGHTx, 1..3
# FLIPHx, 1..3
# FLIPVx, 1..3
# BLANKx, only 1 and 2
if
mn
[
'COMPOSITE'
]:
W
=
mn
[
'WOI_WIDTH'
]
H
=
mn
[
'WOI_HEIGHT'
]
FH
=
mn
[
'FLIPH'
]
FV
=
mn
[
'FLIPV'
]
#if FV:
# I =
v_offset
=
0
for
i
in
range
(
1
,
4
):
try
:
height
=
mn
[
'HEIGHT'
+
str
(
i
)]
#fliph = mn['FLIPH'+str(i)]
flipv
=
mn
[
'FLIPV'
+
str
(
i
)]
except
KeyError
:
# break for '_9'
break
try
:
blank
=
mn
[
'BLANK'
+
str
(
i
)]
except
KeyError
:
blank
=
0
crop
=
res
.
crop
((
0
,
v_offset
,
W
,
v_offset
+
height
))
if
flipv
:
crop
=
ImageOps
.
flip
(
crop
)
# if eyesis4pi, 1&2 - rotate 90CW, 3 - 90CCW
if
i
<
3
:
crop
=
crop
.
rotate
(
-
90
,
expand
=
1
)
else
:
crop
=
crop
.
rotate
(
90
,
expand
=
1
)
crop
.
save
(
"result_"
+
str
(
i
)
+
".jpeg"
)
v_offset
+=
height
+
blank
jp4.py
0 → 100644
View file @
1213b32b
__copyright__
=
"Copyright 2018, Elphel, Inc."
__license__
=
"GPL-3.0+"
__maintainer__
=
"Oleg Dzhimiev"
__email__
=
"oleg@elphel.com"
import
numpy
as
np
#import imageio
import
elphel_exif
from
PIL
import
Image
,
ImageOps
'''
Python image manipulation libs:
Lib Reads image as Exif Image manipulations Comment
Pillow(PIL) Image + + likes np.uint8 arrays
imageio numpy.array - - almost useless
opencv numpy.array - +
Recommendations:
'''
# clear from code
def
get_exif
(
filename
):
exif
=
elphel_exif
.
Exif
(
filename
)
# exif.f - filename
# exif.data - parsed (as dict) exif with parsed MakeNote
# exif.MakerNote - parsed as dict
return
exif
# clear from code
def
naur
(
a
):
b0
=
a
[
0
]
b0
=
np
.
reshape
(
b0
,(
1
,
b0
.
shape
[
0
]))
b
=
a
[:
-
1
]
b
=
np
.
concatenate
((
b0
,
b
),
axis
=
0
)
return
b
# clear from code
def
nabr
(
a
):
b0
=
a
[
-
1
]
b0
=
np
.
reshape
(
b0
,(
1
,
b0
.
shape
[
0
]))
b
=
a
[
1
:]
b
=
np
.
concatenate
((
b
,
b0
),
axis
=
0
)
return
b
# clear from code
def
nalc
(
a
):
b0
=
a
[::,
0
]
b0
=
np
.
reshape
(
b0
,(
b0
.
shape
[
0
],
1
))
b
=
a
[::,:
-
1
]
b
=
np
.
concatenate
((
b0
,
b
),
axis
=
1
)
return
b
# clear from code
def
narc
(
a
):
b0
=
a
[::,
-
1
]
b0
=
np
.
reshape
(
b0
,(
b0
.
shape
[
0
],
1
))
b
=
a
[::,
1
:]
b
=
np
.
concatenate
((
b
,
b0
),
axis
=
1
)
return
b
class
JP4
:
def
__init__
(
self
,
filename
=
"test.jp4"
):
# open image using PIL
#i = Image.open(filename)
#self.px = i.load()
#self.px = scipy.misc.imread(filename, flatten=False, mode='RGB')
#self.h, self.w, self.chn = self.px.shape
self
.
exif
=
get_exif
(
filename
)
# not JP4 - no deblock
self
.
need_deblocking
=
True
if
self
.
exif
.
MakerNote
[
'COLOR_MODE'
]
==
5
else
False
self
.
need_demosaicing
=
True
if
self
.
need_deblocking
else
False
#print(self.exif.color_mode)
#print(self.exif.MakerNote['GAIN_R'])
#print(self.exif.MakerNote['GAIN_G'])
#print(self.exif.MakerNote['GAIN_B'])
#print(self.exif.MakerNote['GAIN_GB'])
if
self
.
exif
.
MakerNote
[
'BAYER_MODE'
]
==
0
:
self
.
bayer
=
[[
"Gr"
,
"R"
],[
"B"
,
"Gb"
]]
elif
self
.
exif
.
MakerNote
[
'BAYER_MODE'
]
==
1
:
self
.
bayer
=
[[
"R"
,
"Gr"
],[
"Gb"
,
"B"
]]
elif
self
.
exif
.
MakerNote
[
'BAYER_MODE'
]
==
2
:
self
.
bayer
=
[[
"B"
,
"Gb"
],[
"Gr"
,
"R"
]]
elif
self
.
exif
.
MakerNote
[
'BAYER_MODE'
]
==
3
:
self
.
bayer
=
[[
"Gb"
,
"B"
],[
"R"
,
"Gr"
]]
# open image
# TODO: do not open twice (the 1st opening was when reading exif)
im
=
Image
.
open
(
filename
)
# TODO: handle orientation
# imageio - takes care about orientation
# PIL - does not, which is fine - just need to change bayer mosaic
# rotated 90 CW
if
self
.
exif
.
data
[
'Orientation'
]
==
6
:
# keep bayer
pass
# horizontal mirror then rotated 270 CW
elif
self
.
exif
.
data
[
'Orientation'
]
==
5
:
# change bayer mosaic
if
self
.
bayer
==
[[
"Gr"
,
"R"
],[
"B"
,
"Gb"
]]:
self
.
bayer
=
[[
"B"
,
"Gb"
],[
"Gr"
,
"R"
]]
#im = ImageOps.mirror(im)
#im = im.rotate(270)
# TODO: change bayer due to flips here
# 'L' is 8 bit mode
#self.image = scipy.misc.imread(filename, flatten=False, mode='L')
#im_arr = imageio.imread(filename)
#im = im.rotate(90)
#im = ImageOps.mirror(im)
#im_arr = im.getdata()
im_arr
=
np
.
fromstring
(
im
.
tobytes
(),
dtype
=
np
.
uint8
)
im_arr
=
im_arr
.
reshape
((
im
.
size
[
1
],
im
.
size
[
0
]))
print
(
im_arr
.
shape
)
self
.
image
=
im_arr
self
.
h
,
self
.
w
=
self
.
image
.
shape
# in JP4 format the 16x16 block is arranged in 8x32,
# where color channels are grouped in 8x8 (8x8Gr, 8x8R, 8x8B, 8x8Gb)
# the 1st line of 8x32 blocks is the left half of the image
# the 2nd line of 8x32 blocks is the right half
def
deblock
(
self
):
if
not
self
.
need_deblocking
:
return
0
# tmp copy
I
=
np
.
copy
(
self
.
image
)
W
=
self
.
w
H
=
self
.
h
bayer
=
self
.
bayer
# 16x16 block
block
=
np
.
zeros
((
16
,
16
))
# 16xW
stripe
=
np
.
zeros
((
16
,
W
))
I
=
np
.
reshape
(
I
,(
H
>>
4
,
16
,
W
))
for
i
in
range
(
I
.
shape
[
0
]):
# stripe 16xW
stripe
=
np
.
copy
(
I
[
i
])
for
j
in
range
(
0
,
W
,
16
):
if
j
<
W
/
2
:
k
=
0
l
=
2
*
j
else
:
k
=
8
l
=
int
(
2
*
(
j
-
W
/
2
))
# gr r b gb
block
[
0
::
2
,
0
::
2
]
=
stripe
[
k
:
k
+
8
,
l
+
0
:
l
+
0
+
8
]
block
[
0
::
2
,
1
::
2
]
=
stripe
[
k
:
k
+
8
,
l
+
8
:
l
+
8
+
8
]
block
[
1
::
2
,
0
::
2
]
=
stripe
[
k
:
k
+
8
,
l
+
16
:
l
+
16
+
8
]
block
[
1
::
2
,
1
::
2
]
=
stripe
[
k
:
k
+
8
,
l
+
24
:
l
+
24
+
8
]
I
[
i
,
0
:
16
,
j
:
j
+
16
]
=
block
I
=
np
.
reshape
(
I
,(
H
,
W
))
self
.
image
=
I
# gamma encode, gamma correct
# incorrect, do not use
def
apply_gamma
(
self
):
print
(
"apply gamma"
)
#I = np.copy(self.image.astype(np.int32))
I
=
np
.
copy
(
self
.
image
)
gain_r
=
self
.
exif
.
MakerNote
[
'GAIN_R'
]
gain_gr
=
self
.
exif
.
MakerNote
[
'GAIN_G'
]
gain_b
=
self
.
exif
.
MakerNote
[
'GAIN_B'
]
gain_gb
=
self
.
exif
.
MakerNote
[
'GAIN_GB'
]
I
[
0
::
2
,
0
::
2
]
=
I
[
0
::
2
,
0
::
2
]
**
(
1
/
gain_gr
)
I
[
0
::
2
,
1
::
2
]
=
I
[
0
::
2
,
1
::
2
]
**
(
1
/
gain_r
)
I
[
1
::
2
,
0
::
2
]
=
I
[
1
::
2
,
0
::
2
]
**
(
1
/
gain_b
)
I
[
1
::
2
,
1
::
2
]
=
I
[
1
::
2
,
1
::
2
]
**
(
1
/
gain_gb
)
self
.
image
=
I
# unapply gamma
# incorrect, do not use
def
linearize
(
self
):
print
(
"unapply gamma"
)
I
=
np
.
copy
(
self
.
image
.
astype
(
np
.
float
))
gain_r
=
self
.
exif
.
MakerNote
[
'GAIN_R'
]
gain_gr
=
self
.
exif
.
MakerNote
[
'GAIN_G'
]
gain_b
=
self
.
exif
.
MakerNote
[
'GAIN_B'
]
gain_gb
=
self
.
exif
.
MakerNote
[
'GAIN_GB'
]
I
[
0
::
2
,
0
::
2
]
=
I
[
0
::
2
,
0
::
2
]
**
gain_gr
I
[
0
::
2
,
1
::
2
]
=
I
[
0
::
2
,
1
::
2
]
**
gain_r
I
[
1
::
2
,
0
::
2
]
=
I
[
1
::
2
,
0
::
2
]
**
gain_b
I
[
1
::
2
,
1
::
2
]
=
I
[
1
::
2
,
1
::
2
]
**
gain_gb
# OpenCV uses BGR format
self
.
image
=
I
# simple but incorrect, with 2x downsampling
# from here: https://groups.google.com/forum/#!topic/pydc1394/KycTwjyBDV0
def
demosaic_simple_downsample
(
self
):
if
not
self
.
need_demosaicing
:
return
0
# no need in clipping
I
=
np
.
copy
(
self
.
image
)
R
=
I
[
0
::
2
,
1
::
2
]
G
=
I
[
1
::
2
,
1
::
2
]
/
2
+
I
[
0
::
2
,
0
::
2
]
/
2
B
=
I
[
1
::
2
,
0
::
2
]
# OpenCV uses BGR format
I
=
np
.
dstack
([
B
,
G
,
R
])
self
.
image
=
I
def
demosaic_bilinear_slow_and_true
(
self
):
if
not
self
.
need_demosaicing
:
return
0
bayer
=
self
.
bayer
I
=
np
.
copy
(
self
.
image
.
astype
(
np
.
float
))
R
=
np
.
copy
(
I
)
G
=
np
.
copy
(
I
)
B
=
np
.
copy
(
I
)
h
,
w
=
I
.
shape
for
j
in
range
(
h
):
for
i
in
range
(
w
):
jt
=
j
+
1
if
j
==
0
else
j
-
1
jb
=
j
-
1
if
j
==
h
-
1
else
j
+
1
il
=
i
+
1
if
i
==
0
else
i
-
1
ir
=
i
-
1
if
i
==
w
-
1
else
i
+
1
px_0
=
I
[
j
,
i
]
px_t
,
px_b
,
px_l
,
px_r
=
I
[
jt
,
i
],
I
[
jb
,
i
],
I
[
j
,
il
],
I
[
j
,
ir
]
px_tl
,
px_tr
,
px_bl
,
px_br
=
I
[
jt
,
il
],
I
[
jt
,
ir
],
I
[
jb
,
il
],
I
[
jb
,
ir
]
if
(
bayer
[
j
%
2
][
i
%
2
]
==
"Gr"
):
R
[
j
,
i
]
=
(
px_l
+
px_r
)
/
2
G
[
j
,
i
]
=
(
4
*
px_0
+
px_tl
+
px_tr
+
px_bl
+
px_br
)
/
8
B
[
j
,
i
]
=
(
px_t
+
px_b
)
/
2
elif
(
bayer
[
j
%
2
][
i
%
2
]
==
"R"
):
R
[
j
,
i
]
=
px_0
G
[
j
,
i
]
=
(
px_t
+
px_b
+
px_l
+
px_r
)
/
4
B
[
j
,
i
]
=
(
px_tl
+
px_tr
+
px_bl
+
px_br
)
/
4
elif
(
bayer
[
j
%
2
][
i
%
2
]
==
"B"
):
R
[
j
,
i
]
=
(
px_tl
+
px_tr
+
px_bl
+
px_br
)
/
4
G
[
j
,
i
]
=
(
px_t
+
px_b
+
px_l
+
px_r
)
/
4
B
[
j
,
i
]
=
px_0
elif
(
bayer
[
j
%
2
][
i
%
2
]
==
"Gb"
):
R
[
j
,
i
]
=
(
px_t
+
px_b
)
/
2
G
[
j
,
i
]
=
(
4
*
px_0
+
px_tl
+
px_tr
+
px_bl
+
px_br
)
/
8
B
[
j
,
i
]
=
(
px_l
+
px_r
)
/
2
# OpenCV uses BGR format
I
=
np
.
dstack
([
B
,
G
,
R
])
self
.
image
=
I
return
I
def
demosaic_bilinear
(
self
):
if
not
self
.
need_demosaicing
:
return
0
bayer
=
self
.
bayer
# int16 is enough, int32 - native and faster? need to test
I
=
np
.
copy
(
self
.
image
.
astype
(
np
.
int32
))
R
=
np
.
copy
(
I
)
G
=
np
.
copy
(
I
)
B
=
np
.
copy
(
I
)
# this depends on bayer
p00
=
I
[
0
::
2
,
0
::
2
]
p01
=
I
[
0
::
2
,
1
::
2
]
p10
=
I
[
1
::
2
,
0
::
2
]
p11
=
I
[
1
::
2
,
1
::
2
]
if
bayer
==
[[
"Gr"
,
"R"
],[
"B"
,
"Gb"
]]:
R
[
0
::
2
,
0
::
2
]
=
(
p01
+
nalc
(
p01
))
/
2
G
[
0
::
2
,
0
::
2
]
=
(
4
*
p00
+
p11
+
naur
(
p11
)
+
nalc
(
p11
+
naur
(
p11
)))
/
8
B
[
0
::
2
,
0
::
2
]
=
(
p10
+
naur
(
p10
))
/
2
R
[
0
::
2
,
1
::
2
]
=
p01
G
[
0
::
2
,
1
::
2
]
=
(
p00
+
narc
(
p00
)
+
p11
+
naur
(
p11
))
/
4
B
[
0
::
2
,
1
::
2
]
=
(
p10
+
naur
(
p10
)
+
narc
(
p10
+
naur
(
p10
)))
/
4
R
[
1
::
2
,
0
::
2
]
=
(
p01
+
nabr
(
p01
)
+
nalc
(
p01
+
nabr
(
p01
)))
/
4
G
[
1
::
2
,
0
::
2
]
=
(
p11
+
nalc
(
p11
)
+
p00
+
nabr
(
p00
))
/
4
B
[
1
::
2
,
0
::
2
]
=
p10
R
[
1
::
2
,
1
::
2
]
=
(
p01
+
nabr
(
p01
))
/
2
G
[
1
::
2
,
1
::
2
]
=
(
4
*
p11
+
p00
+
nabr
(
p00
)
+
narc
(
p00
+
nabr
(
p00
)))
/
8
B
[
1
::
2
,
1
::
2
]
=
(
p10
+
narc
(
p10
))
/
2
elif
bayer
==
[[
"R"
,
"Gr"
],[
"Gb"
,
"B"
]]:
R
[
0
::
2
,
0
::
2
]
=
p00
G
[
0
::
2
,
0
::
2
]
=
(
p01
+
nalc
(
p01
)
+
p10
+
naur
(
p10
))
/
4
B
[
0
::
2
,
0
::
2
]
=
(
p11
+
naur
(
p11
)
+
nalc
(
p11
+
naur
(
p11
)))
/
4
R
[
0
::
2
,
1
::
2
]
=
(
p00
+
narc
(
p00
))
/
2
G
[
0
::
2
,
1
::
2
]
=
(
4
*
p01
+
p10
+
naur
(
p10
)
+
narc
(
p10
+
naur
(
p10
)))
/
8
B
[
0
::
2
,
1
::
2
]
=
(
p11
+
naur
(
p11
))
/
2
R
[
1
::
2
,
0
::
2
]
=
(
p00
+
nabr
(
p00
))
/
2
G
[
1
::
2
,
0
::
2
]
=
(
4
*
p10
+
p01
+
nabr
(
p01
)
+
nalc
(
p01
+
nabr
(
p01
)))
/
8
B
[
1
::
2
,
0
::
2
]
=
(
p11
+
nalc
(
p11
))
/
2
R
[
1
::
2
,
1
::
2
]
=
(
p00
+
nabr
(
p00
)
+
narc
(
p00
+
nabr
(
p00
)))
/
4
G
[
1
::
2
,
1
::
2
]
=
(
p01
+
nabr
(
p01
)
+
p10
+
narc
(
p10
))
/
4
B
[
1
::
2
,
1
::
2
]
=
p11
elif
bayer
==
[[
"B"
,
"Gb"
],[
"Gr"
,
"R"
]]:
R
[
0
::
2
,
0
::
2
]
=
(
p11
+
naur
(
p11
)
+
nalc
(
p11
+
naur
(
p11
)))
/
4
G
[
0
::
2
,
0
::
2
]
=
(
p10
+
naur
(
p10
)
+
p01
+
nalc
(
p01
))
/
4
B
[
0
::
2
,
0
::
2
]
=
p00
R
[
0
::
2
,
1
::
2
]
=
(
p11
+
naur
(
p11
))
/
2
G
[
0
::
2
,
1
::
2
]
=
(
4
*
p01
+
p10
+
naur
(
p10
)
+
narc
(
p10
+
naur
(
p10
)))
/
8
B
[
0
::
2
,
1
::
2
]
=
(
p00
+
narc
(
p00
))
/
2
R
[
1
::
2
,
0
::
2
]
=
(
p11
+
nalc
(
p11
))
/
2
G
[
1
::
2
,
0
::
2
]
=
(
4
*
p10
+
p01
+
nabr
(
p01
)
+
nalc
(
p01
+
nabr
(
p01
)))
/
8
B
[
1
::
2
,
0
::
2
]
=
(
p00
+
nabr
(
p00
))
/
2
R
[
1
::
2
,
1
::
2
]
=
p11
G
[
1
::
2
,
1
::
2
]
=
(
p10
+
narc
(
p10
)
+
p01
+
nabr
(
p01
))
/
4
B
[
1
::
2
,
1
::
2
]
=
(
p00
+
nabr
(
p00
)
+
narc
(
p00
+
nabr
(
p00
)))
/
4
# OpenCV uses BGR format
I
=
np
.
dstack
([
B
,
G
,
R
])
self
.
image
=
I
return
I
def
saturation
(
self
):
I
=
self
.
image
.
astype
(
np
.
int32
)
# use '2' for now
s
=
2
r
=
I
[:,:,
2
]
g
=
I
[:,:,
1
]
b
=
I
[:,:,
0
]
Y
=
0.299
*
r
+
0.5870
*
g
+
0.144
*
b
Cb
=
128
+
s
*
(
-
0.1687
*
r
-
0.3313
*
g
+
0.500
*
b
)
Cr
=
128
+
s
*
(
0.5
*
r
-
0.4187
*
g
-
0.0813
*
b
)
Cb
[
Cb
<
0
]
=
0
Cb
[
Cb
>
255
]
=
255
Cr
[
Cr
<
0
]
=
0
Cr
[
Cr
>
255
]
=
255
r
=
Y
+
1.402
*
(
Cr
-
128
)
g
=
Y
-
0.34414
*
(
Cb
-
128
)
-
0.71414
*
(
Cr
-
128
)
b
=
Y
+
1.772
*
(
Cb
-
128
)
r
[
r
<
0
]
=
0
r
[
r
>
255
]
=
255
g
[
g
<
0
]
=
0
g
[
g
>
255
]
=
255
b
[
b
<
0
]
=
0
b
[
b
>
255
]
=
255
# OpenCV uses BGR format
I
=
np
.
dstack
([
b
,
g
,
r
])
self
.
image
=
I
return
I
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment