Commit 1213b32b authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

initial + splitting composite images

parent 58bb6b94
__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]
#!/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
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment