README for PSIVT09-raw-wm Version 0.1; March 23, 2009 Python and C code implementing and testing the raw image watermark embedding and detection method proposed in the paper Peter Meerwald, Andreas Uhl, "Watermarking of raw digital images in camera firmware: embedding and detection", Proceedings of the 3rd Pacific-Rim Symposium on Image and Video Technology, PSIVT '09, Tokyo, Japan, Lecture Notes in Computer Science, Springer, volume 5414, 340-348, January 2009. The embedding part has been implemented for the Canon IXUS 70 and Canon Powershot A720 cameras. See http://wavelab.at/sources. Overview: There are two distinct parts, the firmware modification for embedding in camera hardware and the embedding/detection simulation. We'll first cover the firmware cross-compilation part. A brief description of the simulation part is below. Part 1 ------ How to build camera firmware: I assume you are familiar with the CHDK Canon add-on firmware and its build environment. Check the website http://chdk.wikia.com to setup a Linux-hosted cross-build environment. The modifications are based on CHDK SVN revision 470. The main file is firmware/wm.c which contains the embedding code and an implementation of the Mersenne Twister, a pseudo-random number generator (code is taken from R. Wagner, http://www-personal.umich.edu/~wagnerr/MersenneTwister.html). Note that the framebuffer dimensions have to be configured in fireware/wm.c In the function raw_savefile() in CHDK's file core/raw.c we place a hook to call our watermark embedding code: if (conf.watermark_mode) { started(); watermark(hook_raw_image_addr(), hook_raw_size()); finished(); } In CHDK's include/conf.h, add the following to the typedef struct { // ... int watermark_mode; int watermark_seed; int watermark_strength; // ... } Conf; The remaining stuff is for the GUI and the configuration options. Define watermarking sub-menu in core/gui.c: static CMenuItem wm_submenu_items[] = { {LANG_MENU_WATERMARK_MODE, MENUITEM_BOOL, &conf.watermark_mode }, {LANG_MENU_WATERMARK_SEED, MENUITEM_INT|MENUITEM_F_UNSIGNED| MENUITEM_F_MINMAX, &conf.watermark_seed, MENU_MINMAX(1, 10000)}, {LANG_MENU_WATERMARK_STRENGTH, MENUITEM_INT|MENUITEM_F_UNSIGNED| MENUITEM_F_MINMAX, &conf.watermark_strength, MENU_MINMAX(1, 100)}, {LANG_MENU_BACK, MENUITEM_UP }, {0} }; static CMenu wm_submenu = { LANG_MENU_WATERMARK_TITLE, NULL, wm_submenu_items }; And plug in our watermarking sub-menu into the raw menu: static CMenuItem raw_submenu_items[] = { // ... {LANG_MENU_WATERMARKING, MENUITEM_SUBMENU, (int*)&wm_submenu }, // .. In core/conf.c we add some new configuration options for us (note that N is the last used configuration ID, so we append our stuff at the end of the list): static const ConfInfo conf_info[] = { // ... CONF_INFO(N+1, conf.watermark_mode, CONF_DEF_VALUE, i:0, NULL), CONF_INFO(N+2, conf.watermark_seed, CONF_DEF_VALUE, i:1, NULL), CONF_INFO(N+3, conf.watermark_strength, CONF_DEF_VALUE, i:50, NULL), // ... Some trivial functions in core/conf.c: void ubasic_camera_set_watermark_mode(int mode) { conf.watermark_mode = mode; } void ubasic_camera_set_watermark_seed(int seed) { conf.watermark_seed = seed; } void ubasic_camera_set_watermark_strength(int strength) { conf.watermark_strength = strength; } Default language is added to core/gui_lang.c (note, replace N with appropriate numbers to put the strings at the end of the list): static char* gui_lang_default = \ // ... "N \"Watermarking\"\n" "N+1 \"Watermark Seed\"\n" "N+2 \"Watermark Strength\"\n" "N+3 \"Watermarking\"\n" "N+4 \"Watermarking ->\"\n" // ... And in core/gui_lang.h add some #defines (again, remember to replace N with the same number as choosen above): #define LANG_MENU_WATERMARK_MODE N #define LANG_MENU_WATERMARK_SEED N+1 #define LANG_MENU_WATERMARK_STRENGTH N+2 #define LANG_MENU_WATERMARK_TITLE N+3 #define LANG_MENU_WATERMARKING N+4 A very simple detector for the watermarked images produced by the camera firmware is available as well. First, run compile.sh to generate chdk.so. Then setup the pymt module provided in pymt/ by running python setup.py install Run det_chdk.py to detect the watermark in the demosaicked image. Part 2 ------ How to build: Run compile.sh to generate canonraw.so. This step needs a recent cython installed. How to run: The script test.sh demonstrates how to embed a watermark in the raw image, demosaick the image, compress the demosaicked image using JPEG and, finally, detect the watermark. jpg_detect.py outputs the detection response for 7 detectors for the polyphase components, the fused image and the filtered image (not described in paper). The responses are gives under H1 (detection with watermark watermark) and H0 (detection with an arbitrary watermark). test.sh would be executed 1000 times or so with varying watermark keys in order to allow estimation of reasonable parameters of the detection statistic under H0 and H1. The program results.py can compute probability of miss given the detection responses. Dependencies: The following programs and libraries need to be installed and in the execution path (shell or Python); the Debian/Ubuntu package names are given in brackets: * Python 2.5.2, http://www.python.org [python2.5] * Python Image Library (PIL) 1.1.6, http://www.pythonware.com/products/pil/ [python-imaging] * numpy 1.0.4, http://numpy.org [python-numpy] * scipy 0.6.0, http://scipy.org [python-scipy] * JPEG tools cjpeg, djpeg [libjpeg-progs] * Netpbm 10.0, http://netpbm.sourceforge.net [netpbm] * cython C-Extensions for Python, http://www.cython.org [cython] * ufraw 0.13, http://ufraw.sourceforge.net/ [ufraw] The code has been tested under Debian and Ubuntu Linux. Disclaimer: This material is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all. The material is prepared strictly for research use only, commercial use is prohibited. Do not distribute the material without written permission. If you publish any work based on this code, please cite the original paper. Contact: Please address any technical questions to Peter Meerwald (pmeerw@cosy.sbg.ac.at) or write to Andreas Uhl Department of Computer Sciences Universität Salzburg Jakob-Haringer-Str. 2 A-5020 Salzburg AUSTRIA Telephone: ++43 (0)662 8044 6303 Fax: ++43 (0)662 8044 172 Email: uhl@cosy.sbg.ac.at