Loading...
Searching...
No Matches
PixelVectorOp.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 PixelVectorOP_H_
32#define PixelVectorOP_H_
33
34#include <cmath>
35
36#include "ImageOp.h"
37//#include "drain/util/Functor.h"
38//#include "drain/util/Fuzzy.h"
39//#include "drain/util/Registry.h"
40#include "drain/util/FunctorBank.h"
41
42#include "drain/util/FunctorPack.h"
43
44namespace drain
45{
46
47namespace image
48{
49
50
51
53
61class PixelVectorOp : public ImageOp
62{
63public:
64
65 virtual
66 void getDstConf(const ImageConf &srcConf, ImageConf & dstConf) const;
67 //void makeCompatible(const ImageFrame &src, Image &dst) const;
68
69 std::string functorDef;
70 // std::string functorParams;
71
72protected:
73
74 PixelVectorOp(const std::string & name, const std::string & description) :
75 ImageOp(name, description + " Post-scaling with desired functor."), rescale(0.0), POW(1.0), INVPOW(1.0) { //, l(1){ , rescale(0.0),
76 // parameters.separator = ':';
77 parameters.link("functor", this->functorDef);
78 // parameters.link("params", this->functorParams);
79 };
80
81 double rescale;
82 double POW;
83 double INVPOW;
84
85};
86
87
88
89class GrayOp : public PixelVectorOp
90{
91
92public:
93
94 std::string coefficients;
95 bool normalize;
96
97 // static char coeffSeparator = ':';
98
99 GrayOp() : PixelVectorOp(__FUNCTION__, "Convert multi-channel image to single."){
100 parameters.clear();
101 parameters.link("coeff", coefficients="1.0", "c[:c2:c3:...]");
102 parameters.link("normalize", normalize=true, "true|false");
103 //parameters.separator = 0;
104 };
105
106 virtual
107 void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const;
108
109
110
112 virtual inline
113 void traverseChannel(const Channel & src, Channel &dst) const {
114 drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
115 mout.warn("already a single-channel image?");
116 dst.copyData(src);
117 //throw std::runtime_error(name+"(ImageOp)::"+__FUNCTION__+"(src,dst) unimplemented.");
118 };
119
120
121};
122
123
124
125template <class F>
127{
128
129public:
130
131 BinaryPixelVectorOp(const std::string & name, const std::string & description) : PixelVectorOp(name, description){
132 };
133
134 virtual
135 inline
136 void process(const ImageFrame &src, Image &dst) const {
137 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
138 mout.debug("delegating: process(src, dst, dst)" );
139 process(src, dst, dst);
140 };
141
142 //double getValue(double src) const {return 0.0;};
143
144 virtual
145 inline
146 void process(const ImageFrame &src1, const ImageFrame &src2, Image &dst) const {
147
148 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
149
150 mout.debug("imitating: " );
151 //process2WithTemp(src, dst);
152
153 if (src2.hasOverlap(dst)){
154 Image tmp;
155 tmp.copyDeep(src2);
156 makeCompatible(src1.getConf(), dst);
157 traverseFrame(src1, tmp, dst);
158 /*
159 const ImageTray<const Channel> srcTray1(src1);
160 const ImageTray<const Channel> srcTray2(tmp);
161 ImageTray<Channel> dstTray(dst);
162 traverseChannels(srcTray1, srcTray2, dstTray);
163 */
164 }
165 else {
166 makeCompatible(src1.getConf(), dst);
167 /*
168 const ImageTray<const Channel> srcTray1(src1);
169 const ImageTray<const Channel> srcTray2(src2);
170 ImageTray<Channel> dstTray(dst);
171 traverseChannels(srcTray1, srcTray2, dstTray); */
172 traverseFrame(src1, src2, dst); // lower
173 }
174 };
175
176 virtual
177 void traverseChannels(const ImageTray<const Channel> & srcTray, ImageTray<Channel> & dstTray) const {
178 Logger mout(getImgLog(), __FILE__, __FUNCTION__);
179 mout.unimplemented("traverseChannels for one srcTray only " );
180 }
181
182 virtual
183 void traverseChannels(const ImageTray<const Channel> & src, const ImageTray<const Channel> & src2,
184 ImageTray<Channel> & dst) const;
185
186 void traverseFrame(const ImageFrame &src1, const ImageFrame &src2, ImageFrame &dst) const {
187
188 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
189 mout.debug("delegate to: traverseChannels(src, dst, dst)" );
190
191 ImageTray<const Channel> src1Channels;
192 src1Channels.setChannels(src1);
193
194 ImageTray<const Channel> src2Channels;
195 src2Channels.setChannels(src2);
196
197 ImageTray<Channel> dstChannels;
198 dstChannels.setChannels(dst);
199
200 traverseChannels(src1Channels, src2Channels, dstChannels);
201 }
202
203 /*
204 inline
205 double getValue(double src, double src2) const {
206 const BinaryFunctor & f = functor;
207 return f(src, src2);
208 }
209 */
210protected:
211
212 F binaryFunctor;
213
214};
215
216template <class F>
217void BinaryPixelVectorOp<F>::traverseChannels(const ImageTray<const Channel> & src1, const ImageTray<const Channel> & src2,
218 ImageTray<Channel> & dst) const {
219
220
221 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
222
223 if (src1.empty())
224 mout.error("src1 empty" );
225
226 if (src2.empty())
227 mout.error("src2 empty" );
228
229 if (dst.empty())
230 mout.error("dst empty" );
231
232 Channel & dstChannel = dst.get();
233
234 if (src1.getGeometry() != src2.getGeometry()){
235 mout.warn("src1" , src1.getGeometry() );
236 mout.warn("src2" , src2.getGeometry() );
237 mout.note("dstChannel" , dstChannel );
238 mout.error("src1 and src2 geometry error" );
239 return;
240 }
241
242 const int width = src1.getGeometry().getWidth(); //std::min(src1.getWidth(),src2.getWidth());
243 const int height = src1.getGeometry().getHeight(); //std::min(src1.getHeight(),src2.getHeight());
244 const size_t channels = src1.size(); // std::min(src1.getChannelCount(),src2.getChannelCount());
245
246 double x=0.0, sum=0.0;
247
248 mout.debug3(*this );
249 //mout.debug3("src1: " , src1 );
250 //mout.debug3("src2: " , src2 );
251 //mout.debug3("dst: " , dst );
252
253 FunctorBank & functorBank = getFunctorBank();
254
255 std::string functorName;
256 std::string functorParams;
257
258 drain::StringTools::split2(functorDef, functorName, functorParams, "/");
259
260
261 if (!functorBank.has(functorName)){
262 //functorBank.help(std::cerr);
263 mout.note(functorBank );
264 mout.error("functor '" , functorName , "' not found: " , functorDef );
265 return;
266 }
267
268 UnaryFunctor & scalingFunctor = functorBank.clone(functorName); // consider get? Or static from clone()
269
270 //mout.debug(scalingFunctor.getName() , ':' , scalingFunctor.getDescription() );
271 //scalingFunctor.setScale(dstChannel.scaling.getMax<double>(), 0.0);
272 const std::type_info & t = dstChannel.getType();
273 if (Type::call<drain::typeIsSmallInt>(t)){
274 const double m = Type::call<typeMax, double>(t);
275 scalingFunctor.setScale(m, 0.0); // TODO consider invScale, invOffset?
276 mout.info("small int type, scaling with its maximum (" , m , ')' );
277 }
278
279 //scalingFunctor.setParameters(functorParams);
280 try {
281 scalingFunctor.setParameters(functorParams, '=', '/');
282 } catch (const std::exception & e) {
283 mout.info(scalingFunctor);
284 mout.warn(scalingFunctor.getParameters());
285 mout.error(e.what());
286 }
287
288 mout.debug2(scalingFunctor.getName() , ':' , scalingFunctor );
289
290 const double coeff = (rescale>0.0) ? 1.0/rescale : 1.0/static_cast<double>(channels);
291 const bool USE_POW = (POW != 1.0);
292 const bool USE_INVPOW = (INVPOW != 1.0);
293 mout.debug3("coeff " , coeff );
294 const BinaryFunctor & f = binaryFunctor;
295 size_t a;
296 for (int j = 0; j < height; j++) {
297 for (int i = 0; i < width; i++) {
298
299 sum = 0.0;
300 a = dstChannel.address(i,j);
301 for (size_t k = 0; k < channels; k++){
302 // getValue( src1.get(k).get<double>(a) , src2.get(k).get<double>(a) );
303 x = f(src1.get(k).get<double>(a) , src2.get(k).get<double>(a)) ;
304 if (USE_POW)
305 sum += pow(x, POW);
306 else
307 sum += x;
308 }
309 if (USE_INVPOW)
310 dstChannel.put(a, scalingFunctor(pow(coeff*sum, INVPOW)));
311 else
312 dstChannel.put(a, scalingFunctor(coeff*sum));
313 }
314 }
315
316}
317
318
320
334class DistanceOp : public BinaryPixelVectorOp<SubtractionFunctor> {
335
336public:
337
338 DistanceOp() : BinaryPixelVectorOp<SubtractionFunctor>(__FUNCTION__, "Computes the distance of pixel vectors."){
339 POW = 2.0;
340 INVPOW = 0.5;
341 //functorDef="FuzzyStep/0:200";
342 };
343
344};
345
346
348
363class ProductOp : public BinaryPixelVectorOp<MultiplicationFunctor>
364{
365public:
366
367 ProductOp() : BinaryPixelVectorOp<MultiplicationFunctor>(__FUNCTION__, "Computes the dot product of pixel vectors."){
368 POW = 1.0;
369 INVPOW = 0.5;
370 //functorDef="FuzzyStep/0:200";
371 };
372
373};
374
376
389class MagnitudeOp : public BinaryPixelVectorOp<MultiplicationFunctor> {
390
391public:
392
393 //MagnitudeOp(const std::string & mapping = "linear", double l=2.0) : PixelVectorOp(__FUNCTION__,"Computes the magnitude of a pixel vector."){
394 MagnitudeOp() : BinaryPixelVectorOp<MultiplicationFunctor>(__FUNCTION__, "Computes the magnitude of a pixel vector."){
395 POW = 1.0; // because x*x natively
396 INVPOW = 0.5;
397 //functorDef="FuzzyStep/0:200";
398 };
399
400 virtual
401 inline
402 void process(const ImageFrame &src, Image &dst) const {
403 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"(PixelVectorOp)", __FUNCTION__);
404 mout.debug("delegating to: process(src, src, dst)" );
406 };
407
408 virtual
409 inline
410 void traverseFrame(const ImageFrame &src, ImageFrame & dst) const {
411 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"::PixelVectorOp[src, dst]", __FUNCTION__);
412 mout.warn("delegating to: traverseFrame(src, src, dst)" );
414 }
415
416 virtual
417 inline
418 void traverseChannels(const ImageTray<const Channel> & src, ImageTray<Channel> & dst) const {
419 Logger mout(getImgLog(), __FILE__, __FUNCTION__); //REPL getImgLog(), name+"::PixelVectorOp[src,dst]", __FUNCTION__);
420 mout.debug("delegate to: traverseChannels(src, SRC, dst)" );
422 }
423
424};
425
426
427}
428}
429
430
431#endif /*PixelVectorOP_H_*/
432
433// Drain
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
virtual void clear()
Removes all the elements of the map.
Definition ReferenceMap.h:374
static bool split2(const std::string &s, T1 &first, T2 &second, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
Definition PixelVectorOp.h:127
virtual void process(const ImageFrame &src, Image &dst) const
Main interface. Typically splits processing to each channel.
Definition PixelVectorOp.h:136
Image with static geometry.
Definition ImageChannel.h:60
Computes the distance between intensity vectors.
Definition PixelVectorOp.h:334
Definition PixelVectorOp.h:90
virtual void traverseChannel(const Channel &src, Channel &dst) const
Apply to single channel.
Definition PixelVectorOp.h:113
Struct for image (excluding data)
Definition ImageConf.h:333
Image with static geometry.
Definition ImageFrame.h:67
void copyData(const ImageFrame &src)
Copies data. Does not change encoding, geometry, or coordinate policy.
Definition ImageFrame.cpp:209
bool hasOverlap(const ImageFrame &image) const
Checks if images have a common memory segment.
Definition ImageFrame.h:341
Base class for image processing functions.
Definition ImageOp.h:49
virtual void makeCompatible(const ImageConf &src, Image &dst) const
Depending on the operator, modifies the geometry and type of dst.
Definition ImageOp.cpp:54
Container applicable for Channels and Images, with alpha support.
Definition ImageTray.h:267
Class for multi-channel digital images. Supports dynamic typing with base types (char,...
Definition Image.h:184
void copyDeep(const ImageFrame &src)
Copies the type, geometry, coordinate policy and data of the given image.
Definition Image.h:314
Computes pixel magnitude, that is, euclidean norm of the intensity vector.
Definition PixelVectorOp.h:389
virtual void process(const ImageFrame &src, Image &dst) const
Main interface. Typically splits processing to each channel.
Definition PixelVectorOp.h:402
A base class for operations between of multi-channel pixels (intensity vectors) of two images.
Definition PixelVectorOp.h:62
virtual void getDstConf(const ImageConf &srcConf, ImageConf &dstConf) const
Given source image, determine respective dest image configuration.
Definition PixelVectorOp.cpp:40
Computes dot product of intensities of two images.
Definition PixelVectorOp.h:364
Definition DataSelector.cpp:1277
FunctorBank & getFunctorBank()
Definition FunctorBank.cpp:51