/
MWT_Align.h
175 lines (139 loc) · 5.58 KB
/
MWT_Align.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* Copyright (C) 2017 Rex A. Kerr and Calico Life Sciences
*
* This file is a part of the Multi-Worm Tracker and is distributed under the
* terms of the GNU Lesser General Public Licence version 2.1 (LGPL 2.1).
* For details, see file LICENSE, or http://www.gnu.org/licences
*/
#ifndef MWT_ALIGN
#define MWT_ALIGN
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "MWT_Geometry.h"
#include "MWT_Lists.h"
#include "MWT_Storage.h"
#include "MWT_Image.h"
/****************************************************************
Image Alignment
****************************************************************/
class ShiftWeight {
public:
float shift;
float weight;
ShiftWeight() : shift(0), weight(0) {}
ShiftWeight(float s, float w) : shift(s), weight(w) {}
};
class Feature1D {
public:
float position;
float strength;
float diameter;
int sign;
Feature1D() : position(0), strength(0), diameter(0), sign(0) {}
Feature1D(float p, float s, float d, int sgn): position(p), strength(s), diameter(d), sign(sgn) {}
ShiftWeight operator-(Feature1D& that) {
return ShiftWeight(position - that.position, (sign * that.sign) * fminf(strength, that.strength));
}
};
class Profile {
public:
enum Collapse { OverX, OverY };
float *reference;
float *squareref;
float *buffer;
float center;
float jitter;
int* hist;
Feature1D features[8];
int n_features;
Rectangle source;
Collapse direction;
int n;
int n_alloc;
Profile() : reference(NULL), squareref(NULL), buffer(NULL), hist(NULL), source(Rectangle(Point(1,1), Point(0,0))), n_alloc(0) {}
Profile(const Rectangle src, Collapse dir);
~Profile() {
n_alloc = 0;
if (reference != NULL) {
delete[] reference;
reference = NULL;
}
if (squareref != NULL) {
delete[] squareref;
squareref = NULL;
}
if (buffer != NULL) {
delete[] buffer;
buffer = NULL;
}
if (hist != NULL) {
delete[] hist;
hist = NULL;
}
}
private:
float find_mean(float *values, int count);
ShiftWeight histify(float *values, int count);
float find_center_via_hist(float *values, int count, ShiftWeight sw);
void load_best_features(int m);
void compute_new_values();
float sort_and_size(Feature1D *data, int k, int *ix); // Sorts by position, returns mean diameter
void set_margins(int dist, Collapse dir, Rectangle &sub, Rectangle &add, int &absdist);
Rectangle constrain_source(Rectangle frameBounds, Rectangle regionBounds);
float best_tiled_inside(Image& frame, Rectangle search);
float best_tiled_inside8(Image8& frame, Rectangle search);
float best_shifted_inside(Image& frame, Rectangle search, int& shift);
float best_shifted_inside8(Image8& frame, Rectangle search, int& shift);
void constrain_bounds_nearby(Rectangle &bounds);
public:
/** Sets the same bounds as used by a different profile but reset the edges (ready for a fresh scan) */
void imitate(const Profile& that);
/** Quality score for how useful of a profile we have for alignment */
float quality();
/** Adopt an already-computed profile */
void adopt(float *profile, int length);
/** Adopt a profile from the given image */
void imprint(Image& frame);
/** Adopt a profile from the given 8 bit image */
void imprint8(Image8& frame);
/** Updates the profile to be shifted from the current position in the direction of collapse as indicated */
void slide(Image& frame, int distance);
/** Updates the profile to be shifted from the current position in the direction of collapse as indicated */
void slide8(Image8& frame, int distance);
/** Updates the profile to be shifted from the current position in the direction of variation as indicated */
void scroll(Image& frame, int distance);
/** Updates the profile to be shifted from the current position in the direction of variation as indicated */
void scroll8(Image8& frame, int distance);
/** Find and adopt the best quality within `search`, keeping the dimensions of the Profile.
* The current position is updated to the best position. Distances and widths are rounded to
* a multiple of four.
*
* The Profile will be imprinted on the best position when this routine is complete.
*
* Returns a quality score (absolute value is meaningless, but can be used for rankings).
*
* (Note: the search is not exhaustive.)
*/
float best_inside(Image& frame, Rectangle search);
/** Find and adopt the best quality within `search`, keeping the dimensions of the Profile.
* The current position is updated to the best position. Distances and widths are rounded to
* a multiple of four.
*
* The Profile will be imprinted on the best position when this routine is complete.
*
* Returns a quality score (absolute value is meaningless, but can be used for rankings).
*
* (Note: the search is not exhaustive.)
*/
float best_inside8(Image8& frame, Rectangle search);
/** Given the profile in `probe`, find the offset between the stored profile and the probe profile. */
float align(Profile* that);
/** Find the offset between the image in `frame` and the stored profile in `*that` by computing and comparing the new profile. */
inline float delta(Image& frame, Profile* that) { imprint(frame); return align(that); }
/** Find the offset between the 8 bit image in `frame` and the stored profile in `*that` by computing and comparing the new profile. */
inline float delta8(Image8& frame, Profile* that) { imprint8(frame); return align(that); }
friend int test_mwt_align_best();
};
int test_mwt_align();
#endif