Extension Name

	E57_LEICA_Camera_Distortion
	
XML namespace

	DIST		xmlns:dist="http://www.libe57.org/E57_LEICA_Camera_Distortion.txt"

Contact

	Aldo Facchin, Leica GeoSystems (aldo . facchin @ leica-geosystems.com)
	Stan Coleby, Cerisoft LLC (stan . coleby @ gmail.com)

Contributors

	none.
	
Version

	Last Modified Date: October 3, 2014
		Revision: 1

Dependencies

	none.
 
Overview

	This extension adds camera distortion to the pinhole camera model.
	This allows the camera image to be stored in the original form and
	allows the image corrections to be done by the user if that user needs
	to overlay the image on the point data.  However, many applications
	only want the original photographs, positions, directions, timestamps,
	and doesn't need to do the overlaya such as in mobile scanning applications.
	
IP Status

	No known IP claims.

New <E57Root> Fields

	none.

New PointRecord Fields

	none.
	
New <data3D> Fields	

	none.
	
New <images2D> Fields

	Element Name			Type						Description
		
	"dist:distortion"		Structure				Image camera distortion structure
	
	"dist:CameraNumber"		Integer					Optional - Camera number in a multiple camera app (1 - n).
	"dist:Type"				String					Distortion Type like "OpenCV"
	
	"dist:CV_K1"			Float					radial distortion coefficients.
	"dist:CV_K2"			Float					radial distortion coefficients.
	"dist:CV_K3"			Float					radial distortion coefficients.
	"dist:CV_K4"			Float					radial distortion coefficients.
	"dist:CV_K5"			Float					radial distortion coefficients.
	"dist:CV_K6"			Float					radial distortion coefficients.
	"dist:CV_P1"			Float					tangential distortion coefficients.
	"dist:CV_P2"			Float					tangential distortion coefficients.
	"dist:CV_CX"			Float					principal point usually at image centerX in pixel units.
	"dist:CV_CY"			Float					principal point usually at image centerY in pixel units.
	"dist:CV_FX"			Float					X focal lengths expressed in pixel units.
	"dist:CV_FY"			Float					Y focal lengths expressed in pixel units.
	"dist:CV_HEIGHT"		Integer					image X in pixel units.
	"dist:CV_WIDTH"			Integer					image Y in pixel units.
	

	The camera distortion information is unique for each camera used.  However, in order for each image to standard
	on its own, this distortion data should be included with each "image2D" data struction for each jpgs.
	
	The Optional CameraNumber is a 1 to n camera position used in mobil scanners to indicate which camera was used.
	The writer should include each image in sequence that was taken at the same time i.e. camera 1, camera 2,.. camera n, 
	camera 1 from next position or timestampe etc.
	
	
XML Example

<images2D type="Vector" allowHeterogeneousChildren="1">
    <vectorChild type="Structure">
	...
		<dist:distortion type="Structure">
			<dist:CameraNumber type="Integer" minimum="0" maximum="100">1</dist:CameraNumber>
			<dist:Type type="String"><![CDATA[OpenCV]]></dist:Type>
			<dist:CV_K1 type="Float">-1.7010328174209699e-001</dist:CV_K1>
			<dist:CV_K2 type="Float">1.12322889607517e-001</dist:CV_K2>
			<dist:CV_K3 type="Float">-1.77362716988726e-002</dist:CV_K3>
			<dist:CV_K4 type="Float"/>
			<dist:CV_K5 type="Float"/>
			<dist:CV_K6 type="Float"/>
			<dist:CV_P1 type="Float">8.0965912894873104e-004</dist:CV_P1>
			<dist:CV_P2 type="Float">6.8468997337824003e-005</dist:CV_P2>
			<dist:CV_CX type="Float">1.0097520611508299e+003</dist:CV_CX>
			<dist:CV_CY type="Float">1.03193331309306e+003</dist:CV_CY>
			<dist:CV_FX type="Float">1.5040567047204299e+003</dist:CV_FX>
			<dist:CV_FY type="Float">1.5040567047204299e+003</dist:CV_FY>
			<dist:CV_HEIGHT type="Integer">2000</dist:CV_HEIGHT>
			<dist:CV_WIDTH type="Integer">2000</dist:CV_WIDTH>
		</dist:distortion>
	...
    </vectorChild>
 </images2D>

Sample Code

//////////////////////////////////
// Writing Extension declaration//
//////////////////////////////////
// FoundationAPI
	_imf.extensionsAdd("dist","http://www.libe57.org/E57_DIST_Camera_Distortion.txt");
	...
// Sample API
	e57::Writer pWriter(...);
	pWriter.GetRawIMF().extensionsAdd("dist","http://www.libe57.org/E57_DIST_Camera_Distortion.txt");
	
///////////////////////////////	
// Write distortion
//////////////////////////////

//Given good distortion data
	integer cameraNumber = 1;
	ustring distortionType = "OpenCV";
	integer imageX = ..;
	integer imageY = ..;
	double CV_K1 = ..;
	double CV_K2 = ..;
	double CV_K3 = ..;
	double CV_K4 = ..;
	double CV_K5 = ..;
	double CV_K6 = ..;
	double CV_P1 = ..;
	double CV_P2 = ..;
	double CV_CX = ..;
	double CV_CY = ..;
	double CV_FX = ..;
	double CV_FY = ..;

	integer imageIndex = ..;  Get the image index
	...
	
// Sample API	
	ImageFile	_imf = pWriter.GetRawIMF();
	VectorNode	_images2D = pWriter.GetRawImages2D();
	if( (imageIndex < 0) || (imageIndex >= _images2D.childCount()))
		return false;

// Both API
		
	//access the image2D structure
	StructureNode image(_images2D.get(imageIndex));

	StructureNode distortion = StructureNode(_imf);
	image.set("dist:distortion", distortion);
	
	distortion.set("dist:CameraNumber", IntegerNode(imf, cameraNumber, NULL, 100));
	distortion.set("dist:Type", StringNode(imf, distortionType.c_str()));
	
	distortion.set("dist:CV_K1", FloatNode(imf, CV_K1));
	distortion.set("dist:CV_K2", FloatNode(imf, CV_K2));
	distortion.set("dist:CV_K3", FloatNode(imf, CV_K3));
	distortion.set("dist:CV_K4", FloatNode(imf, CV_K4));
	distortion.set("dist:CV_K5", FloatNode(imf, CV_K5));
	distortion.set("dist:CV_K6", FloatNode(imf, CV_K6));

	distortion.set("dist:CV_P1", FloatNode(imf, CV_P1));
	distortion.set("dist:CV_P2", FloatNode(imf, CV_P2));
	distortion.set("dist:CV_CX", FloatNode(imf, CV_CX));
	distortion.set("dist:CV_CY", FloatNode(imf, CV_CY));
	distortion.set("dist:CV_FX", FloatNode(imf, CV_FX));
	distortion.set("dist:CV_FY", FloatNode(imf, CV_FY));
	
	distortion.set("dist:CV_WIDTH", IntegerNode(imf, CV_WIDTH));
	distortion.set("dist:CV_HEIGHT", IntegerNode(imf, CV_HEIGHT));

///////////////////////////
//Read distortion data
/////////////////////////	

// Sample API	
	e57::Reader pReader(....);
	...
	VectorNode	_images2D = pReader.GetRawImages2D();
	if( (imageIndex < 0) || (imageIndex >= images2D.childCount()))
		return false;
		
// Both API

	//access the image2D structure
	StructureNode image(_images2D.get(imageIndex));

	ustring url;
	if (pReader.GetRawIMF().extensionsLookupPrefix("dist", url))
	{
		if(image.isDefined("dist:distortion"))
		{
			StructureNode distortion(image.get("dist:distortion"));

			if(distortion.isDefined("dist:CameraNumber"))
				cameraNumber = (long) IntegerNode(distortion.get("dist:CameraNumber")).value();

			if(distortion.isDefined("dist:Type"))
				distortionType = StringNode(distortion.get("dist:Type")).value().c_str();
			
			if(distortion.isDefined("dist:CV_K1"))
				CV_K1 = FloatNode(distortion.get("dist:CV_K1")).value();
			if(distortion.isDefined("dist:CV_K2"))
				CV_K2 = FloatNode(distortion.get("dist:CV_K2")).value();
			if(distortion.isDefined("dist:CV_K3"))
				CV_K3 = FloatNode(distortion.get("dist:CV_K3")).value();
			if(distortion.isDefined("dist:CV_K4"))
				CV_K4 = FloatNode(distortion.get("dist:CV_K4")).value();
			if(distortion.isDefined("dist:CV_K5"))
				CV_K5 = FloatNode(distortion.get("dist:CV_K5")).value();
			if(distortion.isDefined("dist:CV_K6"))
				CV_K6 = FloatNode(distortion.get("dist:CV_K6")).value();
			
			if(distortion.isDefined("dist:CV_P1"))
				CV_P1 = FloatNode(distortion.get("dist:CV_P1")).value();
			if(distortion.isDefined("dist:CV_P2"))
				CV_P2 = FloatNode(distortion.get("dist:CV_P2")).value();
			if(distortion.isDefined("dist:CV_CX"))
				CV_CX = FloatNode(distortion.get("dist:CV_CX")).value();
			if(distortion.isDefined("dist:CV_CY"))
				CV_CY = FloatNode(distortion.get("dist:CV_CY")).value();
			if(distortion.isDefined("dist:CV_FX"))
				CV_FX = FloatNode(distortion.get("dist:CV_FX")).value();
			if(distortion.isDefined("dist:CV_FY"))
				CV_FY = FloatNode(distortion.get("dist:CV_FY")).value();
			
			if(distortion.isDefined("dist:CV_HEIGHT"))
				CV_HEIGHT = IntegerNode(distortion.get("dist:CV_HEIGHT")).value();
			if(distortion.isDefined("dist:CV_WIDTH"))
				CV_WIDTH = IntegerNode(distortion.get("dist:CV_WIDTH")).value();
		}
	}
	
Issues

	none

ASTM E57 Listed

	Submitted Date: October 10, 2014

Revision History

	Revision 1, 2014/10/03
	- Initial version of this document

Copyright

	Copyright (c) 2014 Aldo Facchin Leica GeoSystems(aldo . facchin @ leica-geosystems.com), All Rights Reserved.

	Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this extension 
	and accompanying documentation covered by this license (this "Extension") to use, reproduce, display, distribute, 
	execute, and transmit this Extension, and to prepare derivative works of this Extension, and to permit third-parties 
	to whom this Extension is furnished to do so, all subject to the following:

	The copyright notices in this Extension and this entire statement, including the above license grant, this restriction 
	and the following disclaimer, must be included in all copies of this Extension, in whole or in part, and all derivative 
	works of this Extension, unless such copies or derivative works are solely in the form of machine-executable object code 
	generated by a source language processor.

Disclaimer

	THIS EXTENSION IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
	THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL 
	THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THIS EXTENSION BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN 
	CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS EXTENSION OR THE USE OR OTHER DEALINGS 
	IN THIS EXTENSION.