Last active
December 23, 2022 23:07
-
-
Save alex-luxonis/a60d2d29692b74491838e72b69bdddc2 to your computer and use it in GitHub Desktop.
RAW headerless image to DNG format converter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note: install requirement: python3 -m pip install pidng | |
# If you get: SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats | |
# for now you may need to use python older than 3.10, so for example: | |
# python3.9 -m pip install pidng | |
# python3.9 to_dng.py capture_raw_1920x1080_93_10bit.bw -rot | |
from pidng.core import RAW2DNG, DNGTags, Tag | |
from pidng.defs import * | |
import numpy as np | |
import argparse | |
import struct | |
import sys | |
parser = argparse.ArgumentParser() | |
parser.add_argument('file_name_or_path') | |
parser.add_argument('-rot', '--rotated', action='store_true', | |
help='To be set if the image was captured with `ROTATE_180_DEG`, ' | |
'or it originates from an OAK-1 with default orientation') | |
args = parser.parse_args() | |
rawFile = args.file_name_or_path | |
print('Input file name:', rawFile) | |
if 1: | |
# Try to take image specs from file name, expecting: | |
# capture_raw_WWWWxHHHH_xxxxx_xxxxx_10bit.bw | |
name = rawFile.split('/')[-1] | |
try: | |
# capture_raw_WWWWxHHHH_... | |
width, height = [int(i) for i in name.split('_')[2].split('x')] | |
except ValueError: | |
# raw_WWWWxHHHH_... | |
width, height = [int(i) for i in name.split('_')[1].split('x')] | |
bpp = int(name.split('_')[-1].split('bit')[0]) | |
else: | |
width = 4056 | |
height = 3040 | |
bpp= 10 | |
print(f'>>> width: {width}, height: {height}, bpp: {bpp}') | |
# load raw data into 16-bit numpy array. | |
numPixels = width*height | |
rf = open(rawFile, mode='rb') | |
rawData = struct.unpack("H"*numPixels,rf.read(2*numPixels)) | |
rawFlatImage = np.zeros(numPixels, dtype=np.uint16) | |
rawFlatImage[:] = rawData[:] | |
rawImage = np.reshape(rawFlatImage,(height,width)) | |
# Next line commented out, as our image is already LSbit-justified | |
#rawImage = rawImage >> (16 - bpp) | |
# uncalibrated color matrix, just for demo. TODO | |
ccm1 = [[1000, 1000], [ 0, 1000], [ 0, 1000], | |
[ 0, 1000], [1000, 1000], [ 0, 1000], | |
[ 0, 1000], [ 0, 1000], [1000, 1000]] | |
# set DNG tags. | |
t = DNGTags() | |
t.set(Tag.ImageWidth, width) | |
t.set(Tag.ImageLength, height) | |
t.set(Tag.TileWidth, width) | |
t.set(Tag.TileLength, height) | |
t.set(Tag.Orientation, Orientation.Horizontal) | |
t.set(Tag.PhotometricInterpretation, PhotometricInterpretation.Color_Filter_Array) | |
t.set(Tag.SamplesPerPixel, 1) | |
t.set(Tag.BitsPerSample, bpp) | |
t.set(Tag.CFARepeatPatternDim, [2,2]) | |
t.set(Tag.CFAPattern, CFAPattern.BGGR if args.rotated else CFAPattern.RGGB) | |
# TODO should this be 1024 for 10-bit? | |
t.set(Tag.BlackLevel, (4096 >> (16 - bpp))) | |
t.set(Tag.WhiteLevel, ((1 << bpp) -1) ) | |
t.set(Tag.ColorMatrix1, ccm1) | |
t.set(Tag.CalibrationIlluminant1, CalibrationIlluminant.D65) | |
t.set(Tag.AsShotNeutral, [[1,1],[1,1],[1,1]]) | |
t.set(Tag.BaselineExposure, [[-150,100]]) | |
t.set(Tag.Make, "Camera Brand") | |
t.set(Tag.Model, "Camera Model") | |
t.set(Tag.DNGVersion, DNGVersion.V1_4) | |
t.set(Tag.DNGBackwardVersion, DNGVersion.V1_2) | |
t.set(Tag.PreviewColorSpace, PreviewColorSpace.sRGB) | |
# save to dng file. | |
r = RAW2DNG() | |
r.options(t, path="", compress=True) | |
r.convert(rawImage, filename="output") | |
print('Created: output.dng') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment