macs_io¶
A minimal C++ library for reading and writing MACS images. The latest version can be found here. You can also download a test dataset.
Installation¶
To build the library you need:
A C++ compiler (GCC/Clang or MSVC have been tested)
The Qt library
The OpenCV library
Make based systems
$ cmake <path-to-macs_io> -DCMAKE_INSTALL_PREFIX=<optional_install_location>
$ make
$ make install
Visual Studio
$ cmake <path-to-macs_io>^
-G"Visual Studio 15 2017 Win64"^
-DCMAKE_PREFIX_PATH=C:\Qt\5.11.3\msvc2017_64\lib\cmake
# open macs_io.sln
Usage¶
To use the library, you can either use cmake
cmake_minimum_required(VERSION 2.8.12)
project(my_sample C CXX)
find_package(macs_io REQUIRED)
add_executable(my_sample main.cpp)
target_link_libraries(my_sample macs_io)
or simply add the source files macs_io.cpp
and MacsMetaData.cpp
to your project.
Examples¶
There are three examples included:
macs_decode
The sample macs_decode
shows how to use macs_io to read a MACS image and write a jpg/tif/png. It takes the following options:
$ macs_decode -h
Usage:
macs_decode [options] in.macs out.jpg
where options are:
Stretch:
stretch_min=0.0 stretch factor min
stretch_max=1.0 stretch factor max
gamma=1.0 gamma correction
Devignetting:
devignette_a=0.0 model based devignetting parameter
devignette_b=0.0 model based devignetting parameter
devignette_c=0.0 model based devignetting parameter
devignette_offset=0 model based devignetting parameter
devignette_factor=1.0 model based devignetting parameter
Color balance:
color_balance_r=1.0 color balance parameter
color_balance_g=1.0 color balance parameter
color_balance_b=1.0 color balance parameter
Distortion:
cx=w/2 principal point
cy=h/2 principal point
k1=0.0 radial lens distortion parameter
k2=0.0 radial lens distortion parameter
k3=0.0 radial lens distortion parameter
$ macs_decode helgoland.macs helgoland.tif
$ macs_decode stretch_min=0 stretch_max=0.4
helgoland.macs helgoland_stretch.tif
$ macs_decode stretch_min=0.1 stretch_max=0.53 gamma=0.5
helgoland.macs helgoland_gamma.tif
$ macs_decode stretch_min=0.08 stretch_max=0.53 gamma=0.5
devignette_a=-0.313252 devignette_b=-2.59249 devignette_c=2.2651
helgoland.macs helgoland_devignetted.tif
$ macs_decode img1.macs img1.jpg
macs_encode
which reads a jpg/tif/png and writes a macs image, with metadata. You need to pass the information if the input image is a single channel (gray) image or should be interpreted as a bayer mosaic.
$ macs_encode color=BGGR poster_raw.tif poster.macs
$ macs_decode poster.macs poster.tif
$ macs_decode poster.macs poster_cc.tif
color_balance_g=0.9 color_balance_r=1.0 color_balance_b=1.3
macs_info
which prints the basic metadata of a macs image
$ macs_info ./20180815-235854_YukonCoast_MACS/33552_Cam-NIR-50/02135_032746170_600.macs
MACS Image info:
File name: "02135_032746170_600.macs"
Dimensons: 4864 x 3232
Format: "Mono12Packed"
Pose event from "2018-08-15 22.14.24.127"
Lat: 69.5177
Lon: -139.093
Alt: 391.843
Roll: 0.875793 degrees.
Pitch: 2.57359 degrees.
Yaw: 23.8121 degrees.
Vel: 229.041 km/h
Meta Data:
camVendor "DLR-OS"
camModel "hr16070MFLGEC"
camName "Cam-NIR-50"
camSerial "33552"
camMAC "ac:4f:fc:00:51:f4"
camIP "192.168.101.236"
camFirmware "1.6.5"
affix ""
Theory¶
Lens distortion¶
We use the radial lens distortion model commonly used in computer vision.
Where
\((x_{\mathrm {d} },\ y_{\mathrm {d} }) =\) distorted image point as projected on image plane using specified lens,
\((x_{\mathrm {u} },\ y_{\mathrm {u} }) =\) undistorted image point as projected by an ideal pinhole camera,
\((x_{\mathrm {c} },\ y_{\mathrm {c} }) =\) distortion center,
\(K_{\mathrm {n} } =\) radial distortion coefficient, and
\({\displaystyle {r = \sqrt {(x_{\mathrm {d} }-x_{\mathrm {c} })^{2}+(y_{\mathrm {d} }-y_{\mathrm {c} })^{2}}}}\)
Sometimes there is a need to convert from a different photogrammetric parametrization (like Inpho, or Pictran). Here are some code snippets to perform that conversion.
Converting the Inpho distortion model to the CV model
# Input in Inpho format
w = 7920
h = 6002
# pixel size in mm
ps_mm = 4.6/1000
# principal point in mm
cx_mm = 0.306176
cy_mm = 0.160448
inpho_k1 = -1.476649e-05
inpho_k2 = -3.085708e-08
inpho_k3 = 0
# Inpho to CV
cx_px = w/2 + cx_mm/ps_mm
cy_px = h/2 - cy_mm/ps_mm
k1 = inpho_k1*ps_mm**2
k2 = inpho_k2*ps_mm**4
k3 = inpho_k3*ps_mm**6
(cx_px, cy_px), (k1,k2,k3)
((4026.56, 2966.12), (-3.124589284e-10, -1.3816121798848e-17, 0.0))
Converting the Pictran distortion model to the CV model
# Input in Pictran format
w = 7920
h = 6002
# pixel size in mm
ps_mm = 4.6/1000
# principal point in mm
x0 = 0.306176
y0 = 0.160448
A1 = -1.476649e-05
A2 = -3.085708e-08
#Pictran to CV
cx_px = w/2 + x0/ps_mm;
cy_px = h/2 - y0/ps_mm;
k1 = A1*ps_mm**2
k2 = A2*ps_mm**4
k3 = 0.0
(cx_px, cy_px), (k1,k2,k3)
((4026.56, 2966.12), (-3.124589284e-10, -1.3816121798848e-17, 0.0))
Devignetting¶
We use a parametric devignetting function which multiplies each pixel by a gain function which is defined as follows:
where
is the normalized radius of \((x, y)\), i.e., the Euclidean distance of \((x, y)\) from the image center \((\bar{x}, \bar{y})\), divided by the image diagonal. Thus, \(r = 0\) in the image center and \(r = 1\) in each of the four corners. [Rohlfing]
API¶
The entire interface is contained in macs_io.h
:
namespace MACS
{
enum class PixelFormat {
Mono12Packed = 0x010C0047,
BayerGR12Packed = 0x010C0057,
Mono16 = 0x01100007,
BayerGR16 = 0x0110002E,
INVALID = 0
}; // see GenICam SFNC V2.2 #4.30 / PFNC V2.0 (http://www.emva.org/wp-content/uploads/PFNC.h)
QString pixelformatToString(PixelFormat format) ;
struct PoseEvent
{
QDateTime time;
double roll=0, pitch=0, yaw=0;
double lat=0, lon=0, alt=0;
double veln=0, vele=0, velup=0; // Velocity north east up m/s
bool isValid()const{return time.isValid();}
};
QDataStream &operator>>(QDataStream &in, PoseEvent &poseEvent);
QDataStream &operator<<(QDataStream &out, const PoseEvent &poseEvent);
struct CorrectionOptions
{
struct {
double gamma = 1.0;
double min = 0.0, max = 1.0;
}stretch;
struct{
// Formula (12) in http://www.stanford.edu/~rohlfing/2012-rohlfing-single_image_vignetting_correction.pdf
uint16_t offset=0;
double factor = 1.0;
double a = 0.0, b = 0.0, c = 0.0;
double cx = 0.0, cy = 0.0;
}devignetting;
struct{
double r = 1.0, g = 1.0, b = 1.0;
}color_balance;
struct {
double cx_px = -1.0, cy_px = -1.0;
double k1 = 0.0, k2 = 0.0, k3 = 0.0;
}distortion;
bool convertTo8bit = true;
};
struct Image
{
QSize size;
QByteArray data;
PixelFormat pixelFormat = PixelFormat::INVALID;
int pitch = 0;
QString fileName;
MacsMetaData meta;
PoseEvent georef;
bool isValid()const;
int bitDepth()const; //<! 12 or 16
cv::Mat getCorrectedImage(const CorrectionOptions& options = {}) const; //<! returns a 16 bit 1 or 3 channel image
QImage to8Bit(const CorrectionOptions& options = {}) const;
bool exportImage(const QString& fileName, const CorrectionOptions& options = {}) const;
QString errorMsg;
bool load(const QString& fileName);
bool save(const QString& fileName, bool preview = false, bool compression = false) const;
};
}