Skip to content

Commit b114d6f

Browse files
author
joeljonsson
committed
Put utility classes for python wrappers in separate files. Added functionality from python and cleaned up code.
1 parent 186a4c4 commit b114d6f

File tree

6 files changed

+311
-90
lines changed

6 files changed

+311
-90
lines changed

src/algorithm/APRConverter.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class APRConverter: public LocalIntensityScale, public ComputeGradient, public L
6161
template<typename T>
6262
void auto_parameters(const PixelData<T> &input_img);
6363

64+
6465
private:
6566

6667
//pointer to the APR structure so member functions can have access if they need
@@ -139,7 +140,7 @@ bool APRConverter<ImageType>::get_apr_method_from_file(APR<ImageType> &aAPR, con
139140
}
140141

141142

142-
auto_parameters(inputImage);
143+
//auto_parameters(inputImage);
143144
method_timer.stop_timer();
144145

145146
return get_apr_method(aAPR, inputImage);
@@ -150,6 +151,10 @@ bool APRConverter<ImageType>::get_apr_method_from_file(APR<ImageType> &aAPR, con
150151
*/
151152
template<typename ImageType> template<typename T>
152153
bool APRConverter<ImageType>::get_apr_method(APR<ImageType> &aAPR, PixelData<T>& input_image) {
154+
155+
if( par.auto_parameters ) {
156+
auto_parameters(input_image);
157+
}
153158
apr = &aAPR; // in case it was called directly
154159

155160
total_timer.start_timer("Total_pipeline_excluding_IO");

src/algorithm/APRParameters.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class APRParameters {
3333
float noise_sd_estimate = 0;
3434
float background_intensity_estimate = 0;
3535

36+
bool auto_parameters = true;
37+
3638
bool normalized_input = false;
3739

3840
bool neighborhood_optimization = true;

src/data_structures/Mesh/PixelData.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,25 @@ public :
255255
#endif
256256
}
257257

258+
/**
259+
* Initialize with provided mesh without copying.
260+
* @param aSizeOfY
261+
* @param aSizeOfX
262+
* @param aSizeOfZ
263+
* @param aArray pointer to data
264+
*/
265+
void init_from_mesh(int aSizeOfY, int aSizeOfX, int aSizeOfZ, T* aArray) {
266+
y_num = aSizeOfY;
267+
x_num = aSizeOfX;
268+
z_num = aSizeOfZ;
269+
size_t size = (size_t)y_num * x_num * z_num;
270+
271+
//TODO: fix this for python wrappers?
272+
//meshMemory.reset(aArray);
273+
274+
mesh.set(aArray, size);
275+
}
276+
258277
/**
259278
* Initialize mesh with dimensions taken from provided mesh
260279
* @tparam S

src/wrapper/PyAPR.hpp

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
//
2+
// Created by Joel Jonsson on 29.06.18.
3+
//
4+
5+
#ifndef LIBAPR_PYAPR_HPP
6+
#define LIBAPR_PYAPR_HPP
7+
8+
#include <pybind11/pybind11.h>
9+
#include <pybind11/stl.h>
10+
#include <pybind11/numpy.h>
11+
12+
#include "ConfigAPR.h"
13+
#include "data_structures/APR/APR.hpp"
14+
15+
#include "PyPixelData.hpp"
16+
17+
namespace py = pybind11;
18+
19+
// -------- Utility classes to be wrapped in python ----------------------------
20+
template <typename T>
21+
class PyAPR {
22+
template<typename> friend class PyPixelData;
23+
APR <T> apr;
24+
25+
public:
26+
27+
PyAPR () {}
28+
29+
/**
30+
* Reads in the given HDF5 APR file.
31+
*
32+
* @param aAprFileName
33+
*/
34+
void read_apr(const std::string &aAprFileName) {
35+
apr.read_apr(aAprFileName);
36+
}
37+
38+
// TODO: add more versions of write_apr, with compression options etc?
39+
/**
40+
* Writes the APR to a HDF5 file without(?) compression.
41+
*
42+
* @param aOutputFile
43+
*/
44+
void write_apr(const std::string &aOutputFile) {
45+
apr.write_apr("", aOutputFile);
46+
}
47+
48+
/**
49+
* Returns the piecewise constant reconstruction from the APR instance as a PyPixelData object. This can be cast
50+
* into a numpy array without copy using 'arr = numpy.array(obj, copy=False)'.
51+
*
52+
* @return PyPixelData holding the reconstructed image
53+
*/
54+
PyPixelData<T> pc_recon() {
55+
56+
PixelData<T> reconstructedImage;
57+
58+
APRReconstruction().interp_img(apr, reconstructedImage, apr.particles_intensities);
59+
60+
/*
61+
// this creates a copy...
62+
return py::array_t<T>({reconstructedImage.x_num, reconstructedImage.y_num, reconstructedImage.z_num},
63+
{sizeof(T) * reconstructedImage.y_num * reconstructedImage.x_num, sizeof(T), sizeof(T) * reconstructedImage.y_num},
64+
reconstructedImage.mesh.get());
65+
*/
66+
67+
//this does not copy, and can be cast to numpy.array on python side without copy (set copy=False)
68+
return PyPixelData<T>(reconstructedImage);
69+
}
70+
71+
/**
72+
* Returns the smooth reconstruction from the APR instance as a PyPixelData object. This can be cast into a numpy
73+
* array without copy using 'arr = numpy.array(obj, copy=False)'.
74+
*
75+
* @return PyPixelData holding the reconstructed image
76+
*/
77+
PyPixelData<T> smooth_recon() {
78+
79+
PixelData<T> reconstructedImage;
80+
81+
APRReconstruction().interp_parts_smooth(apr, reconstructedImage, apr.particles_intensities);
82+
83+
return PyPixelData<T>(reconstructedImage);
84+
}
85+
86+
/**
87+
* Sets the parameters for the APR conversion.
88+
*
89+
* @param par pyApr.APRParameters object
90+
*/
91+
void set_parameters(const py::object &par) {
92+
93+
if( py::isinstance<APRParameters>(par) ) {
94+
apr.parameters = par.cast<APRParameters>();
95+
} else {
96+
throw std::invalid_argument("Input has to be a pyApr.APRParameters object.");
97+
}
98+
99+
}
100+
101+
/**
102+
* Computes the APR from the input python array.
103+
*
104+
* @param input image as python (numpy) array
105+
*/
106+
void get_apr_from_array(py::array &input) {
107+
108+
auto buf = input.request();
109+
110+
111+
// Some checks, may need some polishing
112+
if( buf.ptr == nullptr ) {
113+
std::cerr << "Could not pass buffer in call to apr_from_array" << std::endl;
114+
}
115+
116+
if ( !input.writeable() ) {
117+
std::cerr << "Input array must be writeable" << std::endl;
118+
}
119+
120+
if( !py::isinstance<py::array_t<T>>(input) ) {
121+
throw std::invalid_argument("Conflicting types. Make sure the input array is of the same type as the AprType instance.");
122+
}
123+
124+
auto *ptr = (T *) buf.ptr;
125+
126+
PixelData<T> input_img;
127+
128+
//TODO: fix memory/ownership passing or just revert to copying?
129+
input_img.init_from_mesh(buf.shape[1], buf.shape[0], buf.shape[2], ptr); // may lead to memory issues
130+
131+
apr.get_apr(input_img);
132+
}
133+
134+
/**
135+
* Reads in the provided tiff file and computes its APR. Note: parameters for the APR conversion should be set
136+
* before by using set_parameters.
137+
*
138+
* @param aInputFile path to the tiff image file
139+
*/
140+
void get_apr_from_file(const std::string &aInputFile) {
141+
const TiffUtils::TiffInfo aTiffFile(aInputFile);
142+
143+
apr.parameters.input_dir = "";
144+
apr.parameters.input_image_name = aInputFile;
145+
apr.get_apr();
146+
}
147+
148+
};
149+
150+
// -------- Templated wrapper -------------------------------------------------
151+
template <typename DataType>
152+
void AddPyAPR(pybind11::module &m, const std::string &aTypeString) {
153+
using AprType = PyAPR<DataType>;
154+
std::string typeStr = "Apr" + aTypeString;
155+
py::class_<AprType>(m, typeStr.c_str())
156+
.def(py::init())
157+
.def("read_apr", &AprType::read_apr, "Method to read HDF5 APR files")
158+
.def("write_apr", &AprType::write_apr, "Writes the APR instance to a HDF5 file")
159+
.def("reconstruct", &AprType::pc_recon, py::return_value_policy::move, "returns the piecewise constant image reconstruction as a python array")
160+
.def("reconstruct_smooth", &AprType::smooth_recon, py::return_value_policy::move, "returns a smooth image reconstruction as a python array")
161+
.def("set_parameters", &AprType::set_parameters, "Set parameters for APR conversion")
162+
.def("get_apr_from_array", &AprType::get_apr_from_array, "Construct APR from input array (no copy)")
163+
.def("get_apr_from_file", &AprType::get_apr_from_file, "Construct APR from input .tif image");
164+
}
165+
166+
#endif //LIBAPR_PYAPR_HPP

src/wrapper/PyPixelData.hpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// Created by Joel Jonsson on 29.06.18.
3+
//
4+
5+
#ifndef LIBAPR_PYPIXELDATA_HPP
6+
#define LIBAPR_PYPIXELDATA_HPP
7+
8+
#include <pybind11/pybind11.h>
9+
#include <pybind11/stl.h>
10+
#include <pybind11/numpy.h>
11+
12+
#include "data_structures/Mesh/PixelData.hpp"
13+
14+
namespace py = pybind11;
15+
16+
// -------- Utility classes to be wrapped in python ----------------------------
17+
/**
18+
* Currently only using this class to return PixelData objects to python as arrays without copy. It could be made more
19+
* complete with constructor methods and other functionality, but I don't think it is necessary.
20+
*
21+
* @tparam T type of mesh elements
22+
*/
23+
template<typename T>
24+
class PyPixelData {
25+
26+
PixelData<T> image;
27+
28+
public:
29+
PyPixelData() {}
30+
31+
PyPixelData(PixelData<T> &aInput) {
32+
image.swap(aInput);
33+
}
34+
35+
/**
36+
* @return pointer to the mesh data
37+
*/
38+
T *data() {return image.mesh.get();}
39+
40+
/**
41+
* @return width of the domain (number of columns)
42+
*/
43+
int width() const {return image.x_num;}
44+
45+
/**
46+
* @return height of the domain (number of rows)
47+
*/
48+
int height() const {return image.y_num;}
49+
50+
/**
51+
* @return depth of the domain
52+
*/
53+
int depth() const {return image.z_num;}
54+
};
55+
56+
template<typename DataType>
57+
void AddPyPixelData(pybind11::module &m, const std::string &aTypeString) {
58+
using PixelDataType = PyPixelData<DataType>;
59+
std::string typeStr = "PixelData" + aTypeString;
60+
py::class_<PixelDataType>(m, typeStr.c_str(), py::buffer_protocol())
61+
.def("width", &PixelDataType::width, "Returns number of columns (x)")
62+
.def("height", &PixelDataType::height, "Returns number of rows (y)")
63+
.def("depth", &PixelDataType::depth, "Returns the depth (z)")
64+
.def_buffer([](PixelDataType &a) -> py::buffer_info{
65+
return py::buffer_info(
66+
a.data(),
67+
sizeof(DataType),
68+
py::format_descriptor<DataType>::format(),
69+
3,
70+
{a.width(), a.height(), a.depth()},
71+
{sizeof(DataType) * a.height(), sizeof(DataType), sizeof(DataType) * a.width() * a.height()}
72+
);
73+
});
74+
}
75+
76+
#endif //LIBAPR_PYPIXELDATA_HPP

0 commit comments

Comments
 (0)