Skip to content

Commit

Permalink
Add Lazy Array
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasteuwen committed Sep 1, 2024
1 parent a0ffb8a commit 438f293
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 14 deletions.
29 changes: 22 additions & 7 deletions examples/annotations_to_mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""This code provides an example of how to convert annotations to a mask."""
import json
from pathlib import Path

import numpy as np
import PIL.Image

from dlup.annotations_experimental import SlideAnnotations
Expand Down Expand Up @@ -41,16 +41,31 @@

print("Getting geometries")

for polygon in region.polygons.get_geometries():
print(polygon)
# for polygon in region.polygons.get_geometries():
# print(polygon)
polys = region.polygons.get_geometries()
curr_mask = region.polygons.to_mask()
print(curr_mask)
print(np.asarray(curr_mask).shape)

import time
start_time = time.time()
# Let's grab the polygons

mask = LUT[region.polygons.to_mask().numpy()]

print(f"Time lazy: {time.time() - start_time}")

start_time = time.time()
mask = LUT[region.polygons.to_mask_no_lazy()]
print(f"Time eager: {time.time() - start_time}")

mask = LUT[region.polygons.to_mask()]
PIL.Image.fromarray(mask).save("mask.png")

print("Getting geometries")

for polygon in region.polygons.get_geometries():
print(polygon)
# for polygon in region.polygons.get_geometries():
# print(polygon)

with open("test.xml", "w") as f:
f.write(annotations.as_dlup_xml())
Expand All @@ -63,5 +78,5 @@
region2 = annotations2.read_region((0, 0), scaling, bbox[1])
LUT = annotations2.color_lut

mask = LUT[region.polygons.to_mask()]
mask = LUT[region.polygons.to_mask().numpy()]
PIL.Image.fromarray(mask).save("mask2.png")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,4 @@ branch = true
parallel = false # To see if there are threading issues

[tool.coverage.html]
directory = "htmlcov"
directory = "htmlcov"
7 changes: 6 additions & 1 deletion src/geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "geometry/base.h"
#include "geometry/box.h"
#include "geometry/lazy_array.h"
#include "geometry/collection.h"
#include "geometry/exceptions.h"
#include "geometry/factory.h"
Expand Down Expand Up @@ -145,9 +146,13 @@ PYBIND11_MODULE(_geometry, m) {
.def_property_readonly("boxes", &GeometryCollection::getBoxes)
.def_property_readonly("points", &GeometryCollection::getPoints);

declare_lazy_array<int>(m, "LazyArrayInt");

py::class_<PolygonCollection, std::shared_ptr<PolygonCollection>>(m, "PolygonCollection")
.def("get_geometries", &PolygonCollection::getGeometries)
.def("to_mask", &PolygonCollection::toMask, py::arg("default_value") = 0);
.def("to_mask", &PolygonCollection::toMask, py::arg("default_value") = 0)
.def("to_mask_no_lazy", &PolygonCollection::toMaskNonLazy, py::arg("default_value") = 0);


py::class_<AnnotationRegion, std::shared_ptr<AnnotationRegion>>(m, "AnnotationRegion")
.def_property_readonly("polygons", &AnnotationRegion::getPolygons)
Expand Down
47 changes: 47 additions & 0 deletions src/geometry/lazy_array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef DLUP_GEOMETRY_LAZY_ARRAY_H
#define DLUP_GEOMETRY_LAZY_ARRAY_H

#include <functional>
#include <memory>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <vector>

namespace py = pybind11;

template <typename T>
class LazyArray {
public:
using ComputeFunction = std::function<py::array_t<T>()>;

LazyArray(ComputeFunction compute_func) : compute_func_(std::move(compute_func)), computed_(false) {}

py::array_t<T> numpy() {
if (!computed_) {
data_ = compute_func_();
computed_ = true;
}
return data_;
}

py::array_t<T> operator*() { return numpy(); }

// Changed this method to return py::array_t<T> directly
py::array_t<T> py_numpy() { return numpy(); }

private:
ComputeFunction compute_func_;
py::array_t<T> data_;
bool computed_;
};

template <typename T>
void declare_lazy_array(py::module &m, const std::string &type_name) {
py::class_<LazyArray<T>>(m, type_name.c_str())
.def(py::init<typename LazyArray<T>::ComputeFunction>())
.def("numpy", &LazyArray<T>::py_numpy)
.def("__array__", &LazyArray<T>::py_numpy)
.def("__repr__", [](const LazyArray<T> &) { return "<LazyArray: use numpy() or __array__() to compute>"; });
}

#endif // DLUP_GEOMETRY_LAZY_ARRAY_H
29 changes: 24 additions & 5 deletions src/geometry/polygon_collection.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include "factory.h"
#include "lazy_array.h"
#include <mutex>
#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
Expand All @@ -27,18 +28,36 @@ class PolygonCollection {
return py_objects;
}

py::array_t<int> toMask(int default_value = 0) const {
py::array_t<int> toMaskNonLazy(int default_value = 0) const {
auto mask = generateMaskFromAnnotations(polygons_, mask_size_, default_value);
std::cout << "Outside lambda - Number of polygons: " << polygons_.size() << std::endl;

int width = std::get<0>(mask_size_);
int height = std::get<1>(mask_size_);

return py::array_t<int>({height, width}, mask->data());
}
}

LazyArray<int> toMask(int default_value = 0) const {
// Capture polygons_ and mask_size_ by value
auto polygons_copy = polygons_;
auto mask_size_copy = mask_size_;

return LazyArray<int>([polygons_copy, mask_size_copy, default_value]() {
auto mask = generateMaskFromAnnotations(polygons_copy, mask_size_copy, default_value);
int width = std::get<0>(mask_size_copy);
int height = std::get<1>(mask_size_copy);
return py::array_t<int>({height, width}, mask->data());
});
}





private:
std::vector<std::shared_ptr<Polygon>> polygons_;
std::tuple<int, int> mask_size_;
private:
std::vector<std::shared_ptr<Polygon>> polygons_;
std::tuple<int, int> mask_size_;
};

#endif // DLUP_POLYGON_COLLECTION_H

0 comments on commit 438f293

Please sign in to comment.