Loading...
Searching...
No Matches
DistanceTransformFillOp.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31#ifndef DISTANCETRANSFORMFILLOP_H_
32#define DISTANCETRANSFORMFILLOP_H_
33
34#include <drain/image/ImageFile.h> // debugging
35#include <drain/util/Fuzzy.h>
36#include "FunctorOp.h"
37#include "DistanceTransformOp.h"
38
39
40namespace drain
41{
42
43namespace image
44{
45
47
52template <class T>
54{
55public:
56
57 virtual inline
58 int srcAlpha() const {
59 return 2; // REQUIRED
60 };
61
62 // proximity (inverted distance)
63 typedef float dist_t;
64
65 virtual
67
68 virtual
69 void getDstConf(const ImageConf & srcConf, ImageConf & dstConf) const {
70
71 dstConf.setGeometry(srcConf.getGeometry());
72 if (!dstConf.hasAlphaChannel())
73 dstConf.setAlphaChannelCount(1);
74
75 }
76
77
79 virtual // TODO: non-virtual, ie, final!
80 void makeCompatible(const ImageConf & src, Image & dst) const {
81
82 drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
83 mout.debug3("src: ", src);
84
85 ImageConf dstConf(dst.getConf());
86 dstConf.setCoordinatePolicy(src.getCoordinatePolicy());
87 getDstConf(src, dstConf);
88
89 if (!dstConf.typeIsSet())
90 dstConf.setType(src.getType());
91
92 if (!dstConf.hasAlphaChannel())
93 dstConf.setAlphaChannelCount(1);
94
95
96 dst.setConf(dstConf);
97
98 mout.debug("clearing alpha (use traverseChannel(s) to avoid)" );
99
100 // Important
101 dst.getAlphaChannel().fill(0);
102
103 mout.debug3("dst: ", dst);
104
105 };
106
107
109
110 virtual
111 void traverseChannel(const Channel &src, const Channel &srcAlpha, Channel &dst, Channel &dstAlpha) const {
112 ImageTray<const Channel> srcTray; //(src, srcAlpha);
113 srcTray.setChannels(src);
114 srcTray.setAlphaChannels(srcAlpha);
115 ImageTray<Channel> dstTray; //(dst, dstAlpha);
116 dstTray.setChannels(dst);
117 dstTray.setAlphaChannels(dstAlpha);
118 traverseChannels(srcTray, dstTray);
119 };
120
121
122
123protected:
124
125 DistanceTransformFillOp(const std::string &name, const std::string &description, dist_t horz = 14.0, dist_t vert = DistanceModel::nan_f,
126 DistanceModel::topol_t topology=DistanceModel::KNIGHT) : // PIX_ADJACENCY_
127 DistanceTransformOp<T>(name, description, horz, vert, topology), alphaThreshold(0.0, 0.0) {
128 this->parameters.link("alphaThreshold", alphaThreshold.tuple(), "0..1").fillArray = true;
129 };
130
131 //DistanceTransformFillOp(const DistanceTransformFillOp & op) : DistanceTransformOp<T>(op) {
132 //};
133
134
136
138
139 //double alphaThreshold;
140 drain::Range<double> alphaThreshold;
141
142};
143
148template <class T>
150 // void DistanceTransformFillOp<T>::process(const ImageFrame &src, const ImageFrame &srcAlpha, ImageFrame & dst, ImageFrame & dstAlpha) const {
151
152 drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
153
154 mout.debug("start: ", *this );
155
156 if (!src.hasAlpha()){
157 mout.warn("src: ", src );
158 mout.error("required alpha channel missing in src" );
159 return;
160 }
161 else
162 mout.debug2("src: ", src );
163
164 if (!dst.hasAlpha()){
165 mout.warn("dst: ", dst );
166 mout.error("required alpha channel missing in dst" );
167 return;
168 }
169 else
170 mout.debug2("dst: ", dst );
171
172
173 // mout.debug3("init params: " );
174 mout.debug3("init params, using alpha: " );
175 this->initializeParameters(src.getAlpha(), dst.getAlpha());
176 // dst.getAlpha().fill(0); NEW: MOved to ...
177
178 //drain::image::File::write(src.getAlpha(), "dts-a.png");
179 //drain::image::File::write(dst.getAlpha(),"dt0-a.png");
180
181
182 mout.debug("calling traverseDownRight" );
183 // mout.debug2(src );
184 // mout.debug2(dst );
185 traverseDownRight(src, dst);
186 /*
187 if (getImgLog().getVerbosity() > 10){
188 drain::image::File::write(dst,"dtd-i.png");
189 drain::image::File::write(dstAlpha,"dtd-a.png");
190 }
191 */
192
193 mout.debug("calling traverseUpLeft" );
194 // mout.debug2(dst );
195 traverseUpLeft(dst, dst);
196 /*
197 if (getImgLog().getVerbosity() > 10){
198 drain::image::File::write(dst,"dtu-i.png");
199 drain::image::File::write(dstAlpha,"dtu-a.png");
200 }
201 */
202 if (alphaThreshold.max > 0.0){ // TODO: check if (0,1) = neutral
203
204 Channel & dstAlpha = dst.alpha.get();
205
206 UnaryFunctorOp<FuzzyStep<double>,true> threshold;
207 threshold.functor.set(alphaThreshold);
208 mout.debug("Thresholding: ", threshold.functor );
209 // mout.debug(threshold );
210 threshold.traverseChannel(dstAlpha, dstAlpha);
211 //FilePng::write(dstAlpha, "a2.png");
212 }
213
214
215}
216
218
222template <class T>
224
225 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
226
227 mout.debug("distModel: ", this->distanceModel );
228
229 DistanceNeighbourhood chain;
230 this->distanceModel.createChain(chain, true);
231
232 mout.debug2("neighbourHood ", drain::sprinter(chain) );
233
234 const Channel & srcAlpha = srcTray.getAlpha();
235 Channel & dstAlpha = dstTray.getAlpha();
236
237 CoordinateHandler2D coordinateHandler(srcTray.get(0));
238 mout.debug("coordHandler ", coordinateHandler );
239
240 mout.debug3("src alpha:", srcAlpha );
241 mout.debug3("dst alpha:", dstAlpha );
242
244 Point2D<int> p;
245 Point2D<int> pTest;
246 Point2D<int> pWin;
247
248 // Winning distance
249 dist_t dWin;
250 // Distance candidate
251 dist_t dTest;
252
253 const size_t K = std::min(srcTray.size(), dstTray.size());
254
255 const Range<int> & xRange = coordinateHandler.getXRange();
256 const Range<int> & yRange = coordinateHandler.getYRange();
257
258 size_t address = 0;
259 size_t addressWin = 0;
260
261 mout.debug("main loop, K=", K );
262 for (p.y=0; p.y<=yRange.max; ++p.y){
263 for (p.x=0; p.x<=xRange.max; ++p.x){
264
265 address = dstAlpha.address(p.x, p.y);
266
267 // Take source value as default
268 dWin = srcAlpha.get<dist_t>(address);
269 pWin.setLocation(p);
270
271 for (const DistanceElement & elem: chain){
272 pTest.setLocation(p.x + elem.diff.x, p.y + elem.diff.y);
273 coordinateHandler.handle(pTest);
274 dTest = this->distanceModel.decrease(dstAlpha.get<dist_t>(pTest), elem.coeff);
275 if (dTest > dWin){
276 dWin = dTest;
277 pWin = pTest; // consider direct addressWin = dstAlpha.address(pWin.x, pWin.y); so, pTest
278 }
279 }
280
281
282 // Finally, update target image (if data found)
283 if (dWin > 0.0){
284
285 dstAlpha.put(address, dWin);
286
287 addressWin = dstAlpha.address(pWin.x, pWin.y);
288
289 if (addressWin != address){
290 for (size_t k=0; k<K; ++k) // copy from DST
291 dstTray.get(k).put(address, dstTray.get(k).get<dist_t>(addressWin));
292 }
293 else {
294 for (size_t k=0; k<K; ++k) // copy from SRC
295 dstTray.get(k).put(address, srcTray.get(k).get<dist_t>(address));
296 }
297
298 }
299
300 /*
301 if ((p.x == p.y) && ((p.x&15)==0)){
302 std::cerr << p << "\t a=" << address << ", aW=" << addressWin << "\t" << dWin << '>' << dTest << '\t';
303 std::cerr << p << "\t s=" << srcAlpha.get<dist_t>(address) << '=' << srcAlpha.get<dist_t>(p) << '\t';
304 std::cerr << p << "\t d=" << dstAlpha.get<dist_t>(address) << '=' << dstAlpha.get<dist_t>(p) << '\n';
305 }
306 */
307
308 }
309 }
310
311}
312
313
314
316
320template <class T>
322
323 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
324 mout.debug("start" );
325
326 mout.debug2("this->distanceModel", this->distanceModel );
327
328 DistanceNeighbourhood chain;
329 this->distanceModel.createChain(chain, false);
330
331 CoordinateHandler2D coordinateHandler(srcTray.get(0));
332
333 const Channel & srcAlpha = srcTray.getAlpha();
334 Channel & dstAlpha = dstTray.getAlpha();
335
337 Point2D<int> p;
338 Point2D<int> pTest;
339 Point2D<int> pWin;
340
341 // proximity (inverted distance)
342 dist_t dWin;
343 dist_t dTest;
344
345 // Current position
346 size_t address;
347 // Winning position
348 size_t addressWin;
349
350 const size_t K = std::min(srcTray.size(), dstTray.size());
351
352 const Range<int> & xRange = coordinateHandler.getXRange();
353 const Range<int> & yRange = coordinateHandler.getYRange();
354
355 mout.debug("main loop, K=", K);
356
357 for (p.y=yRange.max; p.y>=0; --p.y){
358 for (p.x=xRange.max; p.x>=0; --p.x){
359
360 address = dstAlpha.address(p.x, p.y);
361
362 dWin = srcAlpha.get<dist_t>(address);
363 pWin.setLocation(p);
364
365 for (const DistanceElement & elem: chain){
366 pTest.setLocation(p.x + elem.diff.x, p.y + elem.diff.y);
367 coordinateHandler.handle(pTest);
368 dTest = this->distanceModel.decrease(dstAlpha.get<dist_t>(pTest), elem.coeff);
369 if (dTest > dWin){
370 dWin = dTest;
371 pWin = pTest;
372 }
373 }
374
375
376 // Finally, update target image (if stronger data found)
377 if (dWin > 0.0){
378
379 dstAlpha.put(address, dWin);
380
381 addressWin = dstAlpha.address(pWin.x, pWin.y);
382
383 if (addressWin != address){
384 for (size_t k=0; k<K; ++k) // copy from DST
385 dstTray.get(k).put(address, dstTray.get(k).get<dist_t>(addressWin));
386 }
387 else {
388 for (size_t k=0; k<K; ++k) // copy from SRC
389 dstTray.get(k).put(address, srcTray.get(k).get<dist_t>(address));
390 }
391
392 }
393
394 }
395 }
396}
397
398
399
400
401
402
403
404
406
448{
449
450public:
451
452 inline
453 DistanceTransformFillLinearOp(dist_t horz = 12.3, dist_t vert = DistanceModel::nan_f,
454 DistanceModel::topol_t topology=DistanceModel::KNIGHT) :
455 DistanceTransformFillOp<DistanceModelLinear> (__FUNCTION__, "Spreads intensities linearly up to distance defined by alpha channel.",
456 horz, vert, topology) {
457 };
458
459};
460
461
501class DistanceTransformFillExponentialOp : public DistanceTransformFillOp<DistanceModelExponential>
502{
503
504public:
505
506 inline
507 DistanceTransformFillExponentialOp(dist_t horz = 12.0, dist_t vert = DistanceModel::nan_f,
508 //DistanceModel::topol_t topology=DistanceModel::PIX_ADJACENCY_KNIGHT) :
509 DistanceModel::topol_t topology=DistanceModel::KNIGHT) :
510 DistanceTransformFillOp<DistanceModelExponential> (__FUNCTION__, "Spreads intensities exponentially up to distance defined by alpha intensities.",
511 horz, vert, topology) {
512 };
513
514};
515
516
517}
518}
519
520
521#endif /* DISTANCETRANSFORMFILL_H_ */
522
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:312
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:430
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:666
Logger & error(const TT &... args)
Echoes.
Definition Log.h:416
Logger & debug2(const TT &... args)
Debug information.
Definition Log.h:676
Definition Range.h:52
Image with static geometry.
Definition ImageChannel.h:60
Definition CoordinateHandler.h:77
virtual coord_overflow_t handle(int &x, int &y) const
Ensures the validity of the coordinates. If inside limits, arguments (x,y) remain intact and 0 is ret...
Definition CoordinateHandler.h:205
Definition DistanceModel.h:76
Definition DistanceTransformFillOp.h:502
Spreeads values using inverse linear distance transform.
Definition DistanceTransformFillOp.h:448
Template for DistanceTransformFillLinearOp and DistanceTransformFillExponentialOp.
Definition DistanceTransformFillOp.h:54
void traverseUpLeft(ImageTray< Channel > &src, ImageTray< Channel > &dst) const
Step 1/2: backward traversal.
Definition DistanceTransformFillOp.h:321
void traverseChannels(const ImageTray< const Channel > &src, ImageTray< Channel > &dst) const
Definition DistanceTransformFillOp.h:149
virtual int srcAlpha() const
Tell if alpha channel(s) is required in input.
Definition DistanceTransformFillOp.h:58
virtual void getDstConf(const ImageConf &srcConf, ImageConf &dstConf) const
Ensures dst the same geometry and type with src.
Definition DistanceTransformFillOp.h:69
virtual void makeCompatible(const ImageConf &src, Image &dst) const
Like ImageOp::makeCompatible(), but clears the alpha channel.
Definition DistanceTransformFillOp.h:80
void traverseDownRight(const ImageTray< const Channel > &src, ImageTray< Channel > &dst) const
Step 1/2: forward traversal.
Definition DistanceTransformFillOp.h:223
virtual void traverseChannel(const Channel &src, const Channel &srcAlpha, Channel &dst, Channel &dstAlpha) const
Apply to single channel with alpha.
Definition DistanceTransformFillOp.h:111
Definition DistanceTransformOp.h:58
bool typeIsSet() const
Get the storage type.
Definition ImageConf.h:116
const std::type_info & getType() const
Linear scaling.
Definition ImageConf.h:110
void setType(const std::type_info &t)
Set storage type.
Definition ImageConf.h:121
Struct for image (excluding data)
Definition ImageConf.h:333
void setCoordinatePolicy(const T &policy)
Does not set any CoordinateHandler object.
Definition ImageConf.h:368
void put(size_t i, T x)
Sets the intensity in location i to x. See \address.
Definition ImageFrame.h:192
size_t address(size_t i) const
Computes the index location from image coordinates. Does not involve bit resolution.
Definition ImageFrame.h:148
T get(size_t i) const
Gets the intensity at location i. See address().
Definition ImageFrame.h:254
void fill(T x)
Sets the intensities to given value. Does not change image geometry.
Definition ImageFrame.h:330
Container applicable for Channels and Images, with alpha support.
Definition ImageTray.h:267
void setChannels(T2 &img)
Splits.
Definition ImageTray.h:402
void setAlphaChannels(T2 &img)
Splits.
Definition ImageTray.h:434
const image_t & getAlpha(size_t i=0) const
Returns the i'th alpha image.
Definition ImageTray.h:329
Class for multi-channel digital images. Supports dynamic typing with base types (char,...
Definition Image.h:184
const image_t & get(size_t i=0) const
Returns the i'th image.
Definition ImageTray.h:81
Class for using simple function objects (like std::functor) for sequential pixel iteration.
Definition FunctorOp.h:135
void traverseChannel(const Channel &src, Channel &dst) const
Process the image.
Definition FunctorOp.h:225
Definition DataSelector.cpp:1277
Definition Point.h:48