///|
pub fn Roi::from_bounds(id : String, bounds : Bounds, image : GrayImage) -> Roi {
let mask = BinaryMask(width=image.width, height=image.height)
for y in bounds.min_y..<(bounds.max_y + 1) {
for x in bounds.min_x..<(bounds.max_x + 1) {
mask.set(x, y, true)
}
}
{ id, bounds, mask }
}
///|
pub fn Roi::from_mask(id : String, mask : BinaryMask) -> Roi {
{ id, bounds: mask.bounds(), mask }
}
///|
pub fn Roi::crop(roi : Roi, image : GrayImage) -> GrayImage {
crop_image(image, roi.bounds)
}
///|
pub fn Roi::masked_image(
roi : Roi,
image : GrayImage,
background : Double,
) -> GrayImage {
let result = GrayImage(
width=image.width,
height=image.height,
fill=background,
)
for y in 0.. Array[Double] {
let result : Array[Double] = []
for y in roi.bounds.min_y..<(roi.bounds.max_y + 1) {
for x in roi.bounds.min_x..<(roi.bounds.max_x + 1) {
if roi.mask.at(x, y) {
result.push(image.at(x, y))
}
}
}
result
}
///|
pub fn Roi::statistics(roi : Roi, image : GrayImage) -> StatsSummary {
describe_samples(roi.values(image))
}
///|
pub fn roi_grid(
image : GrayImage,
columns : Int,
rows : Int,
margin : Int,
) -> Array[Roi] {
let result : Array[Roi] = []
let safe_columns = columns.max(1)
let safe_rows = rows.max(1)
let cell_width = image.width / safe_columns
let cell_height = image.height / safe_rows
for row in 0.. Double {
let values = roi.values(image)
maximum_value(values) - minimum_value(values)
}
///|
pub fn roi_edge_density(
roi : Roi,
image : GrayImage,
threshold : Double,
) -> Double {
let edges = threshold_edges_in_roi(roi, image, threshold)
let area = roi.mask.count()
if area == 0 {
0.0
} else {
Double::from_int(edges.count()) / Double::from_int(area)
}
}
///|
pub fn threshold_edges_in_roi(
roi : Roi,
image : GrayImage,
threshold : Double,
) -> BinaryMask {
let edges = image_to_mask(gradient_magnitude(image), threshold)
edges.intersect(roi.mask)
}
///|
pub fn roi_components(
roi : Roi,
image : GrayImage,
threshold : Double,
) -> Array[Component] {
label_components(
threshold_image(roi.masked_image(image, 0.0), threshold).intersect(roi.mask),
)
}
///|
pub fn roi_report(roi : Roi, image : GrayImage) -> String {
let summary = roi.statistics(image)
let out = StringBuilder()
out.write_string(roi.id)
out.write_string(" mean=")
out.write_string(summary.mean.to_string())
out.write_string(" stddev=")
out.write_string(summary.standard_deviation.to_string())
out.write_string(" count=")
out.write_string(summary.count.to_string())
out.to_string()
}
///|
pub fn combine_rois(rois : Array[Roi], width : Int, height : Int) -> BinaryMask {
let result = BinaryMask(width~, height~)
for roi in rois {
for y in 0.. Bool {
for i in 0.. Point {
let component = largest_component(roi.mask)
component.centroid
}
///|
pub fn expand_roi(roi : Roi, padding : Int, image : GrayImage) -> Roi {
let margin = padding.max(0)
Roi::from_bounds(
roi.id,
{
min_x: roi.bounds.min_x - margin,
min_y: roi.bounds.min_y - margin,
max_x: roi.bounds.max_x + margin,
max_y: roi.bounds.max_y + margin,
},
image,
)
}
///|
pub fn shrink_roi(roi : Roi, padding : Int, image : GrayImage) -> Roi {
let margin = padding.max(0)
Roi::from_bounds(
roi.id,
{
min_x: roi.bounds.min_x + margin,
min_y: roi.bounds.min_y + margin,
max_x: roi.bounds.max_x - margin,
max_y: roi.bounds.max_y - margin,
},
image,
)
}