Apple ProRAW データ構造のメモ

ProRAW が iOS 14.3 から対応されました.

自前ツールで読めるようにしたいですね. とりあえず読めました. Semantic map layer もいけました.

## ProRAW とは?

Halide Camera(ちなみに Camera image processing を高速化したりなどの Halide lang https://halide-lang.org/ とは別. 紛らわしいですね)による解説があります.

Understanding ProRAW
https://blog.halide.cam/understanding-proraw-4eed556d4c54

ありがとうございます.

フォーマットは他の RAW と同じく DNG(TIFF) です.

ProRAW(DNG)とありますが, 他の DNG(通常 1 channel の mosaiced 画像)とは異なり, 画像データはすでに demosaic されたあとの RGB データになっています.
denoise やら HDR 合成などを 専用 IP で処理したあとの結果のため, 実際に bayer の状態のデータを出すのが HW 的に無理(or 出したくない)というのもあるかもしれません.

したがって sensor RAW 値を取得して物理量で何か処理したいとか, 自前の debayer/denoise と組み合わせてなにか処理したい場合には向かない形式ですね.

Lightroom 的な感じでレタッチメインのアプリ開発をしている場合は, demosaic や noise reduction を考慮しなくて良いので扱いが楽になります.

また, channel とタイルごとに huffman テーブルがあるので実質的なダイナミックレンジが高い(各チャネル 16bit で [0, 65535])画像が得られます(+ 肌領域などの semantic map もある)ので, レタッチやフィルタ処理がしやすくなっています


### Raw Digger で見てみる.

とりあえず Raw Digger https://www.rawdigger.com/ で見てみます.

![Screenshot from 2020-12-19 17-16-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/fa243e19-97b3-5d10-f239-2fbd08b337e1.png)


EXIF は以下の感じです.


```
---- ExifTool ----
ExifTool Version Number              : 12.06
---- File ----
File Name                            : IMG_***.DNG
Directory                            : 
File Size                            : 25 MB
File Modification Date/Time          : 
File Access Date/Time                : 
File Creation Date/Time              : 
File Permissions                     : rw-rw-rw-
File Type                            : DNG
File Type Extension                  : dng
MIME Type                            : image/x-adobe-dng
Exif Byte Order                      : Big-endian (Motorola, MM)
---- EXIF ----
Make                                 : Apple
Camera Model Name                    : iPhone 12 Pro Max
Preview Image Start                  : 64112
Orientation                          : Rotate 90 CW
Rows Per Strip                       : 3024
Preview Image Length                 : 3744713
Software                             : 14.3
Modify Date                          : 
Image Width                          : 4032
Image Height                         : 3024
Bits Per Sample                      : 12 12 12
Compression                          : JPEG
Photometric Interpretation           : Linear Raw
Samples Per Pixel                    : 3
Planar Configuration                 : Chunky
Tile Width                           : 504
Tile Length                          : 378
Tile Offsets                         : (Binary data 557 bytes, use -b option to extract)
Tile Byte Counts                     : (Binary data 447 bytes, use -b option to extract)
Linearization Table                  : (Binary data 23273 bytes, use -b option to extract)
Black Level                          : 0 0 0
White Level                          : 65535 65535 65535
Noise Profile                        : 3e-005 3e-008
Default Black Render                 : None
Subfile Type                         : Transparency mask, [16]
Strip Offsets                        : 3808828
Strip Byte Counts                    : 58984
Exposure Time                        : 1/121
F Number                             : 1.6
Exposure Program                     : Program AE
ISO                                  : 100
Exif Version                         : 0232
Date/Time Original                   : 
Create Date                          : 
Offset Time                          : +09:00
Offset Time Original                 : +09:00
Offset Time Digitized                : +09:00
Shutter Speed Value                  : 1/121
Aperture Value                       : 1.6
Brightness Value                     : 3.986063072
Exposure Compensation                : 0
Metering Mode                        : Multi-segment
Flash                                : Auto, Did not fire
Focal Length                         : 5.1 mm
Subject Area                         : 2002 1503 2213 1327
Sub Sec Time Original                : 175
Sub Sec Time Digitized               : 175
Exif Image Width                     : 4032
Exif Image Height                    : 3024
Sensing Method                       : One-chip color area
Scene Type                           : Directly photographed
Exposure Mode                        : Auto
White Balance                        : Auto
Focal Length In 35mm Format          : 26 mm
Lens Info                            : 1.539999962-7.5mm f/1.6-2.4
Lens Make                            : Apple
Lens Model                           : iPhone 12 Pro Max back triple camera 5.1mm f/1.6
GPS Latitude Ref                     : North
GPS Longitude Ref                    : East
GPS Altitude Ref                     : Above Sea Level
GPS Speed Ref                        : km/h
GPS Speed                            : 0
GPS Img Direction Ref                :
GPS Img Direction                    : 
GPS Dest Bearing Ref                 : 
GPS Dest Bearing                     : 
GPS Date Stamp                       : 
GPS Horizontal Positioning Error     : 
DNG Version                          : 1.4.0.0
DNG Backward Version                 : 1.3.0.0
Unique Camera Model                  : iPhone13,4 back camera
Color Matrix 1                       : 1.2890625 -0.6268655658 -0.237611264 -0.4374913871 1.49353826 -0.02780930698 -0.04431796074 0.1669107676 0.6011510491
Color Matrix 2                       : 0.954613328 -0.3694036305 -0.1263036281 -0.4197171032 1.302622795 0.09318488836 -0.1094128639 0.2405354381 0.4359321594
As Shot Neutral                      : 0.3930902183 1 0.653686583
Baseline Exposure                    : 2.005519629
Baseline Sharpness                   : 1.5
Calibration Illuminant 1             : Standard Light A
Calibration Illuminant 2             : D65
Noise Reduction Applied              : 0.9499999881
Profile Name                         : Apple Embedded Color Profile
Profile Tone Curve                   : (Binary data 7182 bytes, use -b option to extract)
Preview Image                        : (Binary data 3744713 bytes, use -b option to extract)
---- XMP ----
XMP Toolkit                          : XMP Core 6.0.0
Semantic Segmentation Matte Version  : 65536
Auxiliary Image Type                 : urn:com:apple:photo:2020:aux:semanticskymatte
---- MakerNotes ----
Run Time Flags                       : Valid
Run Time Value                       : 137468691052833
Run Time Scale                       : 1000000000
Run Time Epoch                       : 0
Acceleration Vector                  : -0.0118339099 -0.991778612 -0.004879828543
---- Composite ----
Run Time Since Power Up              : 1 days 14:11:09
Aperture                             : 1.6
Image Size                           : 4032x3024
Lens ID                              : iPhone 12 Pro Max back triple camera 5.1mm f/1.6
Megapixels                           : 12.2
Scale Factor To 35 mm Equivalent     : 5.1
Shutter Speed                        : 1/121
Create Date                          : 
Date/Time Original                   : 
Modify Date                          : 
GPS Altitude                         : 
GPS Latitude                         : 
GPS Longitude                        : 
Circle Of Confusion                  : 0.006 mm
Field Of View                        : 69.4 deg
Focal Length                         : 5.1 mm (35 mm equivalent: 26.0 mm)
GPS Position                         : 
Hyperfocal Distance                  : 2.76 m
Light Value                          : 8.3
```

Maker note は独自のは無い? のかな. 
カスタムデータは XMP(Adobe のなんか独自 specification)であるようです.

https://experienceleague.adobe.com/docs/experience-manager-64/assets/administer/xmp.html?lang=ja

それ以外は普通の EXIF データなので扱いが楽です.

## ProRAW の構造

デフォルトのカメラアプリ利用の場合, おおむね撮影条件によって 3 or 4 layers で構成されています.
(RAW, JPEG に加えて, semantic map が 1 or 2 レイヤー)

- ProRAW データ?(12 bit)
  - LosslessJPEG
  - 画像を 8x8 分割したタイルになっている.
  - component 3 なので, RGB レイヤーごと.
- semantic map
  - 撮影条件によって 1 or 2 枚ある模様.
- JPEG データ(8bit)

RAW は LosslessJPEG での可逆圧縮になっています.
(channel 3, predicator 7 でした)

lossless jpeg の channel 3, predicator 7 はあまり無い形式のようで, ~~RawTherapee など対応していないので開くとてへんな結果になります.~~ 最近 RawTherapee で対応されました https://github.com/Beep6581/RawTherapee/issues/6036
(Darktable はまだのようです)


![Screenshot from 2020-12-19 21-23-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/071d2b2f-e996-6008-3c2a-e66ac937993f.png)

dcraw ですとうまくデコードできました

![Screen Shot 2020-12-20 at 17.21.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/a5a71d02-f20e-bffa-5804-d5f36345a2aa.png)

TinyDNGLoader で使っている lj92 に `channel > 2 & predicator > 2` のときにデコードがうまくいかないのがわかったので修正して, TinyDNGLoader でも読めるようにしました :tada:
(長く険しいデバッグを二営業日ほどかけてなんとか対応した)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ねんがんの Apple ProRAW データのデコードに成功したぞ!!! 🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🥳🥳🥳🥳🥳🥳🥳🥳🥳🎊🎊🎊🎊🎊🎊🎊🎊🍣🍣🍣🍣🍣🍣🍣🍣✌️✌️✌️✌️✌️✌️ <a href="https://t.co/Aa3xmLeviX">pic.twitter.com/Aa3xmLeviX</a></p>&mdash; Syoyo Fujita 🌸 レイトラ ® 🐯 2 周年 🎉 (@syoyo) <a href="https://twitter.com/syoyo/status/1340644201017405442?ref_src=twsrc%5Etfw">December 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

TinyDNGLoader の最新を引けばいけます.

https://github.com/syoyo/tinydngloader

## Dynamic range

ProRAW は 12bit(4096 段階) の Lossless 圧縮ですが, 展開後のピクセル値は 16bit(`[0, 65535]`)になります.
blacklevel はゼロのため, 16bit の全体を使うことができます.

また, Lossless 圧縮では前のピクセルの平均(predictor 7)を取ってから huffman 圧縮している(huffman はテーブルは最大 12bit の 4096 エントリ?)を作っているのと, RGB とタイルごとに huffman テーブルがあるため, 実質的に高いダイナミックレンジを期待できます.

たとえば日の入りのデータですと, `[0, 65535]` の範囲にピクセル値が入ることが実現できていています

![Screenshot from 2021-01-02 16-52-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/904e7927-bc80-e0cb-5c18-115861debe6e.png)

(0 に近いほうは quantization によるものなのか, ヒストグラムでみるとすこし歯抜けになっていますが)

ProRAW は画像を 8x8 のタイルに分割しており, タイルと channel ごとに huffman テーブルは変わっていますから, 空間的な輝度変化のあるダイナミックレンジの高いシーンに強い気もします(e.g. 海に沈む夕日などのショット).
タイルの境界で量子化誤差が気になりそうな気がしますが, 実際のところは知覚できるほどのアーティファクトはさそうです(もしくはエンコード前にうまく処理しているのかもしれません).

## Semantic map

### SemanticName

TIFF Tag 52526 に Semantic map 用の識別子があります.

https://discuss.pixls.us/t/apple-proraw-whats-the-perspective-for-future-support-in-foss/20835/19

https://helpx.adobe.com/photoshop/kb/dng-specification-tags.html

とりあえず以下の文字列を取得できました.

`urn:com:apple:photo:2018:aux:portraiteffectsmatte`
(ポートレート用のマット画像)

`urn:com:apple:photo:2019:aux:semanticskinmatte`
(skin 領域のマット画像と思われます)

`urn:com:apple:photo:2020:aux:semanticskynmatte`
(空領域のマット画像と思われます)

データ自体は通常の 8bit grayscale JPEG でした.
(compression 34892 で, DNG 仕様上は lossy JPEG とありますが実際には普通の JPEG データ. したがって stb_image などでパースできます)

例えば Front camera の画像ですと以下のようなマップが取得できました.

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ねんがんの Apple ProRAW から semantic map の extraction に成功したぞ!!!! 🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊🎊㊗️㊗️㊗️㊗️㊗️㊗️㊗️㊗️㊗️😍😍😍😍😍😍😍😍 Front camera だと portrait alpha と skin segmentation map が取得できるっぽい. 勝てます ✌️ <a href="https://t.co/4h2UDn3dUS">pic.twitter.com/4h2UDn3dUS</a></p>&mdash; Syoyo Fujita 🌸 レイトラ ® 🐯 2 周年 🎉 (@syoyo) <a href="https://twitter.com/syoyo/status/1340725384917045248?ref_src=twsrc%5Etfw">December 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


### depth は対応していない

LiDAR データなど生の depth 出力は対応していません. 特許関連なのですかね?
depth も DNG に埋め込みたい場合, 自前で iOS コードを書くになるでしょうか.


## rawpy で読む

rawpy で普通に読めました :tada:

pixel 値の検証(linear かどうかなど)は python(e.g. JupyterLab) でやるのがよさそうです!

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">python rawpy で ProRAW 48MP DNG 読めました 🤘 <a href="https://t.co/60KwmyHj5V">pic.twitter.com/60KwmyHj5V</a></p>&mdash; syoyo.eth 🌸 レイトラ ® 🐯 4 周年 🎉 (@syoyo) <a href="https://twitter.com/syoyo/status/1595838892598775808?ref_src=twsrc%5Etfw">November 24, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## TODO, 今後

* [x] LosslessJPEG decoder を修正する
* [x] semantic map を読み込む
* [ ] デコードした画像(camera matrix などで補正する前)がリニアになっているか確認する
 
## References

* JavaScript での lossless JPEG のデコード: https://github.com/rawdevjs/lossless-jpeg-decoder
* CR2ファイルのRawデータを読み取ってみる　その７　Lossless JPEGのデコード1- DHT https://www.swetake.com/photo/cr2/cr2-7.html