///|
pub fn patch_values(image : GrayImage, bounds : Bounds) -> Array[Double] {
let result : Array[Double] = []
for y in bounds.min_y..<(bounds.max_y + 1) {
for x in bounds.min_x..<(bounds.max_x + 1) {
result.push(image.at(x, y))
}
}
result
}
///|
pub fn normalized_patch_score(
image : GrayImage,
template : GrayImage,
x : Int,
y : Int,
) -> Double {
if template.width <= 0 || template.height <= 0 {
0.0
} else {
let image_values : Array[Double] = []
let template_values : Array[Double] = []
for dy in 0.. MatchResult {
let mut found = false
let mut location = Point::Point(x=0.0, y=0.0)
let mut score = -2.0
for y in 0..<(image.height - template.height + 1).max(0) {
for x in 0..<(image.width - template.width + 1).max(0) {
let current = normalized_patch_score(image, template, x, y)
if current > score {
score = current
location = Point::Point(x=Double::from_int(x), y=Double::from_int(y))
}
if current >= minimum_score {
found = true
}
}
}
{ found, location, score, candidates: if found { [location] } else { [] } }
}
///|
pub fn template_candidates(
image : GrayImage,
template : GrayImage,
minimum_score : Double,
maximum_count : Int,
) -> Array[MatchResult] {
let result : Array[MatchResult] = []
for y in 0..<(image.height - template.height + 1).max(0) {
for x in 0..<(image.width - template.width + 1).max(0) {
let score = normalized_patch_score(image, template, x, y)
if score >= minimum_score {
let candidate = {
found: true,
location: Point::Point(x=Double::from_int(x), y=Double::from_int(y)),
score,
candidates: [],
}
let mut index = 0
while index < result.length() && result[index].score >= score {
index += 1
}
result.insert(index, candidate)
if result.length() > maximum_count.max(1) {
ignore(result.pop())
}
}
}
}
result
}
///|
pub fn suppress_nearby_matches(
matches : Array[MatchResult],
radius : Double,
) -> Array[MatchResult] {
let result : Array[MatchResult] = []
for item in matches {
let mut keep = true
for selected in result {
if distance(item.location, selected.location) < radius.max(0.0) {
keep = false
}
}
if keep {
result.push(item)
}
}
result
}
///|
pub fn image_patch(
image : GrayImage,
top_left : Point,
width : Int,
height : Int,
) -> GrayImage {
let result = GrayImage(width=width.max(0), height=height.max(0))
for y in 0.. GrayImage {
let width = first.width.min(second.width)
let height = first.height.min(second.height)
let result = GrayImage(width~, height~)
for y in 0.. Double {
let difference = patch_difference(first, second)
if difference.pixels.is_empty() {
0.0
} else {
mean_value(difference.pixels.map(fn(value) { value * value }))
}
}
///|
pub fn patch_peak_signal_to_noise(
first : GrayImage,
second : GrayImage,
) -> Double {
let mse = patch_mean_squared_error(first, second)
if mse <= 0.0000000001 {
100.0
} else {
10.0 * @math.log10(1.0 / mse)
}
}
///|
pub fn match_score_map(image : GrayImage, template : GrayImage) -> GrayImage {
let width = (image.width - template.width + 1).max(0)
let height = (image.height - template.height + 1).max(0)
let result = GrayImage(width~, height~)
for y in 0.. Histogram {
histogram(match_score_map(image, template), bins, bounds={
min: -1.0,
max: 1.0,
})
}
///|
pub fn match_centroid(matches : Array[MatchResult]) -> Point {
if matches.is_empty() {
Point::Point(x=0.0, y=0.0)
} else {
let mut x = 0.0
let mut y = 0.0
for item in matches {
x += item.location.x
y += item.location.y
}
Point::Point(
x=x / Double::from_int(matches.length()),
y=y / Double::from_int(matches.length()),
)
}
}
///|
pub fn match_confidence(
match_result : MatchResult,
minimum_score : Double,
) -> Double {
normalized_quality(match_result.score, minimum_score, 1.0)
}
///|
pub fn match_result_report(match_result : MatchResult) -> String {
let out = StringBuilder()
out.write_string("found=")
out.write_string(match_result.found.to_string())
out.write_string("; score=")
out.write_string(match_result.score.to_string())
out.write_string("; location=(")
out.write_string(match_result.location.x.to_string())
out.write_string(",")
out.write_string(match_result.location.y.to_string())
out.write_string(")")
out.to_string()
}
///|
pub fn compare_templates(
image : GrayImage,
first : GrayImage,
second : GrayImage,
) -> Int {
let first_score = best_template_match(image, first, -1.0).score
let second_score = best_template_match(image, second, -1.0).score
if first_score > second_score {
1
} else if first_score < second_score {
-1
} else {
0
}
}