Skip to content

Commit 18a1b8f

Browse files
authored
Merge pull request #97 from cheesema/developPython
Develop python
2 parents 7273931 + 0890e0e commit 18a1b8f

File tree

14 files changed

+688
-80
lines changed

14 files changed

+688
-80
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,28 @@ All examples except Example_get_apr require an already produced APR, such as tho
114114

115115
For tutorial on how to use the examples, and explanation of data-structures see [the library guide](./docs/lib_guide.pdf).
116116

117+
## Python support
118+
119+
Basic functionality is supported in Python through wrappers. To build the python module,
120+
use the CMake option
121+
122+
`-DAPR_BUILD_PYTHON_WRAPPERS=ON`
123+
124+
Example usage of the available functionality:
125+
126+
| Example | How to ... |
127+
|:--|:--|
128+
| [Example_get_apr_from_array](./examples/python_examples/Example_get_apr_from_array.py) | create an APR from an ndarray and store as hdf5. |
129+
| [Example_get_apr_from_file](./examples/python_examples/Example_get_apr_from_file.py) | create an APR from a TIFF and store as hdf5. |
130+
| [Example_reconstruct_image](./examples/python_examples/Example_reconstruct_image.py) | read in an APR and reconstruct a pixel image |
131+
132+
Note that you may have to manually change the `sys.path.insert()` statements before `import pyApr` in these scripts to insert your build folder.
133+
117134
## Coming soon
118135

119136
* more examples for APR-based filtering and segmentation
120137
* deployment of the Java wrappers to Maven Central so they can be used in your project directly
121138
* support for loading the APR in [Fiji](https://fiji.sc), including [scenery-based](https://github.com/scenerygraphics/scenery) 3D rendering
122-
* basic python wrapper support
123139
* improved java wrapper support
124140
* CUDA GPU-accelerated APR generation and processing
125141

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Joel Jonsson, 2018
2+
3+
import os, sys
4+
import argparse
5+
import numpy as np
6+
7+
from TIFFreadwrite import readTiff
8+
9+
sys.path.insert(0, "../../cmake-build-release") #change this to your build folder
10+
import pyApr
11+
12+
"""
13+
Example script that reads in a .tif image to a numpy array and computes the APR from it. The resulting APR
14+
is written to a HDF5 file in directory of the input file.
15+
16+
Usage: python Example_get_apr_from_file.py -d /home/user/images/ -i myImage.tif -o myAPR
17+
"""
18+
def main(args):
19+
20+
filePath = os.path.join(args.directory, args.input)
21+
22+
apr = pyApr.AprShort() # assuming 16 bit integers
23+
24+
# ----------------------- APR parameter settings ----------------------- #
25+
pars = pyApr.APRParameters()
26+
27+
# Set some parameters manually
28+
pars.Ip_th = 1000
29+
pars.sigma_th = 100
30+
pars.sigma_th_max = 10
31+
pars.rel_error = 0.1
32+
pars.lmbda = 1
33+
34+
# Or try using the auto_parameters
35+
pars.auto_parameters = False
36+
37+
apr.set_parameters(pars)
38+
# ----------------------- APR Conversion ----------------------- #
39+
40+
img = readTiff(filePath).astype(np.uint16) # numpy.ndarray
41+
42+
apr.get_apr_from_array(img)
43+
44+
outPath = os.path.join(args.directory, args.output)
45+
46+
apr.write_apr(outPath)
47+
48+
49+
if __name__ == '__main__':
50+
parser = argparse.ArgumentParser(description="Example script: read in a TIFF image as a numpy array and compute its "
51+
"APR. The resulting APR is saved as a HDF5 file in the given directory.")
52+
parser.add_argument('--input', '-i', type=str, help="Name of the input .tif image")
53+
parser.add_argument('--directory', '-d', type=str, help="Directory of the input (and output) file")
54+
parser.add_argument('--output', '-o', type=str, help="Name of the output HDF5 file")
55+
args = parser.parse_args()
56+
57+
main(args)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Joel Jonsson, 2018
2+
3+
import os, sys
4+
import argparse
5+
6+
sys.path.insert(0, "../../cmake-build-release") #change this to your build folder
7+
import pyApr
8+
9+
"""
10+
Example script that computes an APR from a .tif image and saves the APR to a HDF5 file in directory of the input file.
11+
12+
Usage: python Example_get_apr_from_file.py -d /Users/foo/Documents/myDir/ -i myImage.tif -o myAPR
13+
"""
14+
def main(args):
15+
16+
filePath = os.path.join(args.directory, args.input)
17+
18+
apr = pyApr.AprShort() # assuming 16 bit integers
19+
20+
# ----------------------- Parameter settings ----------------------- #
21+
pars = pyApr.APRParameters()
22+
23+
# Set some parameters manually
24+
pars.Ip_th = 1000
25+
pars.sigma_th = 100
26+
pars.sigma_th_max = 10
27+
pars.rel_error = 0.1
28+
pars.lmbda = 1
29+
30+
# Or try using the auto_parameters
31+
pars.auto_parameters = False
32+
apr.set_parameters(pars)
33+
34+
# ----------------------- APR Conversion ----------------------- #
35+
36+
apr.get_apr_from_file(filePath)
37+
38+
outPath = os.path.join(args.directory, args.output)
39+
40+
apr.write_apr(outPath)
41+
42+
43+
if __name__ == '__main__':
44+
parser = argparse.ArgumentParser(description="Example script: compute the APR from a TIFF image and write the result to a HDF5 file.")
45+
parser.add_argument('--input', '-i', type=str, help="Name of the input .tif image")
46+
parser.add_argument('--directory', '-d', type=str, help="Directory of the input file")
47+
parser.add_argument('--output', '-o', type=str, help="Name of the output HDF5 file")
48+
args = parser.parse_args()
49+
50+
main(args)
51+
52+
53+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Joel Jonsson, 2018
2+
3+
import os, sys
4+
import argparse
5+
import numpy as np
6+
from TIFFreadwrite import writeTiff
7+
8+
sys.path.insert(0, "../../cmake-build-release") #change this to your build folder
9+
import pyApr
10+
11+
"""
12+
Example script that reads an APR from a given HDF5 file, reconstructs the pixel image and writes it to .tif
13+
14+
Usage: python Example_reconstruct_image.py -d /home/user/images/ -i myAPR.h5 -o reconstructedImage.tif
15+
"""
16+
def main(args):
17+
18+
apr = pyApr.AprShort() # assuming 16 bit integers
19+
20+
# read in the APR file
21+
filePath = os.path.join(args.directory, args.input)
22+
apr.read_apr(filePath)
23+
24+
# reconstruct image
25+
if args.smooth:
26+
arr = apr.reconstruct_smooth() # smooth reconstruction
27+
else:
28+
arr = apr.reconstruct() # piecewise constant reconstruction
29+
30+
# convert PyPixelData object to numpy array without copy
31+
arr = np.array(arr, copy=False)
32+
33+
# write image to file
34+
outPath = os.path.join(args.directory, args.output)
35+
writeTiff(outPath, arr, compression=None)
36+
37+
38+
if __name__ == '__main__':
39+
parser = argparse.ArgumentParser(description="Example script: read an APR from a HDF5 file, reconstruct the pixel image"
40+
" and save it as TIFF.")
41+
parser.add_argument('--input', '-i', type=str, help="Name of the input APR file")
42+
parser.add_argument('--directory', '-d', type=str, help="Directory of the input file")
43+
parser.add_argument('--output', '-o', type=str, help="Name of the output .tif file")
44+
parser.add_argument('--smooth', action='store_true', default=False, help="(Optional) use smooth reconstruction")
45+
args = parser.parse_args()
46+
47+
main(args)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from libtiff import TIFF, TIFFfile
2+
import numpy as np
3+
4+
def writeTiff(fileName, array, compression=None):
5+
"""Write input (numpy) array to tiff file with the specified name or path"""
6+
7+
outTiff = TIFF.open(fileName, mode='w')
8+
9+
array = array.squeeze().astype(dtype=np.uint16) # cast array to uint16
10+
11+
ndims = len(array.shape)
12+
13+
if ndims == 3:
14+
15+
for zInd in range(array.shape[2]):
16+
outTiff.write_image(array[:, :, zInd], compression=compression, write_rgb=False)
17+
18+
elif 0 < ndims < 3:
19+
20+
outTiff.write_image(array, compression=compression, write_rgb=False)
21+
22+
else:
23+
raise ValueError('Input array must have between 1 and 3 dimensions')
24+
25+
outTiff.close()
26+
27+
return None
28+
29+
def readTiff(fileName):
30+
"""
31+
Read a tiff file into a numpy array
32+
Usage: img = readTiff(fileName)
33+
"""
34+
tiff = TIFFfile(fileName)
35+
samples, sample_names = tiff.get_samples()
36+
37+
outList = []
38+
for sample in samples:
39+
outList.append(np.copy(sample))
40+
41+
out = np.concatenate(outList, axis=-1)
42+
43+
tiff.close()
44+
45+
return out
1.6 KB
Binary file not shown.

src/algorithm/APRConverter.hpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class APRConverter {
5252
template<typename T>
5353
void auto_parameters(const PixelData<T> &input_img);
5454

55+
5556
private:
5657

5758
//pointer to the APR structure so member functions can have access if they need
@@ -138,23 +139,22 @@ inline bool APRConverter<ImageType>::get_apr_method_from_file(APR<ImageType> &aA
138139
for (size_t i = 0; i < inputImage.mesh.size(); ++i) {
139140
inputImage.mesh[i] = (inputImage.mesh[i] - mm.min) * maxValue / (mm.max - mm.min);
140141
}
141-
}
142142

143-
//normalize the input parameters if required
144-
if(par.Ip_th!=-1){
145-
std::cout << "Scaled input intensity threshold" << std::endl;
146-
par.Ip_th = (par.Ip_th - mm.min)* maxValue / (mm.max - mm.min);
147-
}
143+
//normalize the input parameters if required
144+
if(par.Ip_th!=-1){
145+
std::cout << "Scaled input intensity threshold" << std::endl;
146+
par.Ip_th = (par.Ip_th - mm.min)* maxValue / (mm.max - mm.min);
147+
}
148148

149-
if(par.min_signal!=-1){
150-
std::cout << "Scaled input min signal threshold" << std::endl;
151-
par.min_signal = (par.min_signal)* maxValue / (mm.max - mm.min);
149+
if(par.min_signal!=-1){
150+
std::cout << "Scaled input min signal threshold" << std::endl;
151+
par.min_signal = (par.min_signal)* maxValue / (mm.max - mm.min);
152+
}
152153
}
153-
154154
}
155155

156156

157-
auto_parameters(inputImage);
157+
//auto_parameters(inputImage);
158158
method_timer.stop_timer();
159159

160160
return get_apr_method(aAPR, inputImage);
@@ -165,8 +165,13 @@ inline bool APRConverter<ImageType>::get_apr_method_from_file(APR<ImageType> &aA
165165
*/
166166
template<typename ImageType> template<typename T>
167167
inline bool APRConverter<ImageType>::get_apr_method(APR<ImageType> &aAPR, PixelData<T>& input_image) {
168+
168169
apr = &aAPR; // in case it was called directly
169170

171+
if( par.auto_parameters ) {
172+
auto_parameters(input_image);
173+
}
174+
170175
total_timer.start_timer("Total_pipeline_excluding_IO");
171176

172177
init_apr(aAPR, input_image);

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/APR/APRIterator.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,15 @@ class APRIterator : public GenIterator {
3737

3838
inline bool set_neighbour_iterator(APRIterator &original_iterator, const uint8_t& direction, const uint8_t& index);
3939
protected:
40-
4140
bool find_next_child(const uint8_t& direction,const uint8_t& index);
4241

43-
4442
uint64_t start_index(const uint16_t level, const uint64_t offset);
4543

46-
4744
uint64_t max_row_level_offset(const uint16_t x,const uint16_t z,const uint16_t num_parts);
4845

49-
50-
5146
};
5247

5348

54-
5549
uint64_t APRIterator::start_index(const uint16_t level, const uint64_t offset){
5650

5751
if(this->current_particle_cell.pc_offset == 0){

src/data_structures/Mesh/PixelData.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,26 @@ public :
277277
}
278278

279279

280+
/**
281+
* Initialize with provided mesh without copying.
282+
* @param aSizeOfY
283+
* @param aSizeOfX
284+
* @param aSizeOfZ
285+
* @param aArray pointer to data
286+
*/
287+
void init_from_mesh(int aSizeOfY, int aSizeOfX, int aSizeOfZ, T* aArray) {
288+
y_num = aSizeOfY;
289+
x_num = aSizeOfX;
290+
z_num = aSizeOfZ;
291+
size_t size = (size_t)y_num * x_num * z_num;
292+
293+
//TODO: fix this for python wrappers?
294+
//meshMemory.reset(aArray);
295+
296+
mesh.set(aArray, size);
297+
}
298+
299+
280300
/**
281301
* Initializes mesh with provided dimensions with default value of used type
282302
* @param aSizeOfY

0 commit comments

Comments
 (0)