33 #include "Convolution.hh"
36 #include "Base/Image/ImageIO.hh"
39 #include <Base/Common/BIASpragma.hh>
45 #define KERNCENTER(thesize) ((thesize-1)>>1)
48 template <
class InputStorageType,
class OutputStorageType>
52 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::ConvIntMat_\n");
56 int kern_width=kernel->
GetCols();
57 int kern_height=kernel->
GetRows();
62 int kern_center_x=KERNCENTER(kern_width);
63 int kern_center_y=KERNCENTER(kern_height);
65 signed char rightshift=_fm.GetKernelRightShift();
66 const InputStorageType **srcida = NULL;
67 OutputStorageType **dstida = NULL;
70 const int PixelSpacing = (src.
IsInterleaved())? channelcount : 1;
73 for(
int chloop=0;chloop<channelcount;chloop++) {
81 srcida = srcstart + chloop*img_height;
82 dstida = dststart + chloop*img_height;
85 for(
int img_x=0;img_x<img_width;img_x++)
86 for(
int img_y=0;img_y<img_height;img_y++) {
87 register CONV_INT sum=0;
88 for(
int kern_x=0;kern_x<kern_width;kern_x++)
89 for(
int kern_y=0;kern_y<kern_height;kern_y++) {
91 int img_offset_x=kern_center_x-kern_x;
92 int img_offset_y=kern_center_y-kern_y;
93 if(img_offset_x+img_x<0)
95 if(img_offset_y+img_y<0)
97 if(img_x+img_offset_x>=img_width)
99 if(img_y+img_offset_y>=img_height)
101 sum +=(CONV_INT) (srcida[img_y+img_offset_y][(img_x+img_offset_x)
102 *PixelSpacing+offset]*
103 ((*kernel)[kern_y][kern_x]));
105 dstida[img_y][img_x*PixelSpacing+offset]=
106 (OutputStorageType)((sum)>>rightshift);
113 template <
class InputStorageType,
class OutputStorageType>
117 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::ConvIntHori_\n");
121 int kern_width=kernel->
Size();
126 int kern_center_x=KERNCENTER(kern_width);
128 signed char rightshift=_fm.GetHorizRightShift();
129 const InputStorageType **srcida = NULL;
130 CONV_INT **dstida = NULL;
133 const int PixelSpacing = (src.
IsInterleaved())? channelcount : 1;
135 for(
int chloop=0;chloop<channelcount;chloop++) {
143 srcida = srcstart + chloop*img_height;
144 dstida = dststart + chloop*img_height;
148 for(
int img_y=0;img_y<img_height;img_y++) {
149 for(
int img_x=0;img_x<img_width;img_x++) {
150 int kern_xmax=min((kern_center_x+img_x+1),kern_width);
151 int kern_xmin=max(0,(img_x+kern_center_x-img_width+1));
152 register CONV_INT sum=0;
154 for(
int kern_x=kern_xmin;kern_x<kern_xmax;kern_x++) {
155 int img_offset_x=kern_center_x-kern_x;
157 (CONV_INT)(srcida[img_y][(img_x+img_offset_x)*PixelSpacing+offset])
158 *((*kernel)[kern_x]);
160 dstida[img_y][img_x*PixelSpacing+offset] =
161 (CONV_INT)((sum)>>rightshift);
169 template <
class InputStorageType,
class OutputStorageType>
173 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::ConvIntVert_\n");
177 int kern_height=kernel->
Size();
182 int kern_center_y=KERNCENTER(kern_height);
184 signed char rightshift=_fm.GetVertRightShift();
185 const CONV_INT **srcida = NULL;
186 OutputStorageType **dstida = NULL;
189 const int PixelSpacing = (src.
IsInterleaved())? channelcount : 1;
193 for(
int chloop=0;chloop<channelcount;chloop++) {
201 srcida = srcstart + chloop*img_height;
202 dstida = dststart + chloop*img_height;
206 for(
int img_y=0;img_y<img_height;img_y++) {
207 int kern_ymax=min((kern_center_y+img_y+1),kern_height);
208 int kern_ymin=max(0,(img_y+kern_center_y-img_height+1));
210 for(
int img_x=0;img_x<img_width;img_x++) {
211 register CONV_INT sum=0;
212 for(
int kern_y=kern_ymin;kern_y<kern_ymax;kern_y++) {
213 int img_offset_y=kern_center_y-kern_y;
215 (CONV_INT)(srcida[img_y+img_offset_y][img_x*PixelSpacing+offset])*
218 dstida[img_y][img_x*PixelSpacing+offset]=
219 (OutputStorageType)((sum)>>rightshift);
226 template <
class InputStorageType,
class OutputStorageType>
230 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::ConvFloatMat_\n");
234 const int kern_width = kernel->
GetCols();
235 const int kern_height = kernel->
GetRows();
236 const int img_width = src.
GetWidth();
239 const int kern_center_x = KERNCENTER(kern_width);
240 const int kern_center_y = KERNCENTER(kern_height);
242 const InputStorageType **srcida = NULL;
243 OutputStorageType **dstida = NULL;
246 const int PixelSpacing = (src.
IsInterleaved())? channelcount : 1;
249 for(
int chloop=0;chloop<channelcount;chloop++) {
257 srcida = srcstart + chloop*img_height;
258 dstida = dststart + chloop*img_height;
261 for(
int img_x=0;img_x<img_width;img_x++)
262 for(
int img_y=0;img_y<img_height;img_y++) {
263 register CONV_FLOAT sum=0;
264 for(
int kern_x=0;kern_x<kern_width;kern_x++)
265 for(
int kern_y=0;kern_y<kern_height;kern_y++) {
267 int img_offset_x=kern_center_x-kern_x*PixelSpacing;
268 int img_offset_y=kern_center_y-kern_y;
269 if(img_offset_x+img_x<0)
271 if(img_offset_y+img_y<0)
273 if(img_x+img_offset_x>=img_width)
275 if(img_y+img_offset_y>=img_height)
277 sum += (CONV_FLOAT)srcida[img_y+img_offset_y][(img_x+img_offset_x)*
279 * ((*kernel)[kern_y][kern_x]);
281 dstida[img_y][img_x*PixelSpacing+offset] = (OutputStorageType)sum;
288 template <
class InputStorageType,
class OutputStorageType>
292 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::ConvFloatHori_\n");
296 int kern_width=kernel->
Size();
301 int kern_center_x=KERNCENTER(kern_width);
302 const InputStorageType **srcida = NULL;
303 CONV_FLOAT **dstida = NULL;
306 const int PixelSpacing = (src.
IsInterleaved())? channelcount : 1;
309 for(
int chloop=0;chloop<channelcount;chloop++) {
317 srcida = srcstart + chloop*img_height;
318 dstida = dststart + chloop*img_height;
323 for(
int img_y=0;img_y<img_height;img_y++){
324 for(
int img_x=0;img_x<img_width;img_x++) {
325 int kern_xmax=min((kern_center_x+img_x+1),kern_width);
326 int kern_xmin=max(0,(img_x+kern_center_x-img_width+1));
327 register CONV_FLOAT sum=0;
328 for(
int kern_x=kern_xmin;kern_x<kern_xmax;kern_x++) {
329 int img_offset_x=kern_center_x-kern_x;
330 sum+=CONV_FLOAT(srcida[img_y]
331 [(img_x+img_offset_x)*PixelSpacing+offset])*
334 dstida[img_y][img_x*PixelSpacing+offset]=(CONV_FLOAT)sum;
342 template <
class InputStorageType,
class OutputStorageType>
346 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::ConvFloatVert_\n");
350 int kern_height=kernel->
Size();
355 int kern_center_y=KERNCENTER(kern_height);
356 const CONV_FLOAT **srcida = NULL;
357 OutputStorageType **dstida = NULL;
360 const int PixelSpacing = (src.
IsInterleaved())? channelcount : 1;
361 for(
int chloop=0;chloop<channelcount;chloop++) {
369 srcida = srcstart + chloop*img_height;
370 dstida = dststart + chloop*img_height;
373 for(
int img_y=0;img_y<img_height;img_y++) {
374 int kern_ymax=min((kern_center_y+img_y+1),kern_height);
375 int kern_ymin=max(0,(img_y+kern_center_y-img_height+1));
376 for(
int img_x=0;img_x<img_width;img_x++) {
377 register CONV_FLOAT sum=0;
378 for(
int kern_y=kern_ymin;kern_y<kern_ymax;kern_y++) {
380 int img_offset_y=kern_center_y-kern_y;
383 (CONV_FLOAT)(srcida[img_y+img_offset_y][img_x*PixelSpacing+offset])
384 * ((*kernel)[kern_y]);
387 dstida[img_y][img_x*PixelSpacing+offset] = (OutputStorageType)sum;
394 template <
class InputStorageType,
class OutputStorageType>
397 :
FilterNToN<InputStorageType,OutputStorageType>()
402 template <
class InputStorageType,
class OutputStorageType>
405 :
FilterNToN<InputStorageType, OutputStorageType>(other), _fm(other._fm)
409 template <
class InputStorageType,
class OutputStorageType>
415 template <
class InputStorageType,
class OutputStorageType>
419 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::Filter\n");
421 if (
typeid(InputStorageType)!=
typeid(OutputStorageType)) {
422 BIASDOUT(D_CONV_TYPES,
"Implicit storage type conversion during filtering."
423 <<
" input=" << PRINTTYPE(InputStorageType)
424 <<
", output=" << PRINTTYPE(OutputStorageType));
426 BIASDOUT(D_CONV_TYPES,
"filtering same storage type: "
427 <<PRINTTYPE(InputStorageType));
433 if (CalculationInFloat()) {
434 BIASDOUT(D_CONV_TYPES,
"Convolution is done with floating point numbers.");
438 BIASDOUT(D_CONV_TYPES,
"Convolution is done with integer arithmetic.");
442 template <
class InputStorageType,
class OutputStorageType>
446 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::FilterInt\n");
447 BIASDOUT(D_CONV_KERNEL,
"Kernel is "<<_fm);
455 BIASERR(
"BorderHandling TBH_full not implemented");
459 if(_fm.IsSeparable()) {
460 if(!_tmpInt.SamePixelAndChannelCount(src)) {
465 ConvIntHori_(src, _tmpInt);
466 ConvIntVert_(_tmpInt, dst);
468 if (this->DebugLevelIsSet(D_WRITE_IMAGES)) {
473 }
else ConvIntMat_(src,dst);
475 unsigned int ulx,uly,lrx,lry;
481 if(_fm.IsSeparable()) {
482 kwidth = _fm.GetSepih()->Size();
483 kheight = _fm.GetSepiv()->Size();
485 kwidth = _fm.GetKerneli()->GetCols();
486 kheight = _fm.GetKerneli()->GetRows();
488 dst.
SetROICorners(ulx+KERNCENTER(kwidth),uly+KERNCENTER(kheight),
489 lrx-KERNCENTER(kwidth),lry-KERNCENTER(kheight));
492 if (this->DebugLevelIsSet(D_WRITE_IMAGES)) {
500 template <
class InputStorageType,
class OutputStorageType>
505 if (this->DebugLevelIsSet(D_WRITE_IMAGES)) {
511 BIASCDOUT(D_FILTERBASE_CALLSTACK,
"Convolution::FilterFloat\n");
512 BIASDOUT(D_CONV_KERNEL,
"Kernel is "<<_fm);
519 BIASERR(
"BorderHandling TBH_full not implemented");
523 if(_fm.IsSeparable()) {
524 if(!_tmpFloat.SamePixelAndChannelCount(src)) {
529 ConvFloatHori_(src, _tmpFloat);
531 if (this->DebugLevelIsSet(D_WRITE_IMAGES)) {
533 ImageIO::Save(
"FilterFloat_Separated_AfterHorizontal",_tmpFloat);
536 ConvFloatVert_(_tmpFloat, dst);
538 if (this->DebugLevelIsSet(D_WRITE_IMAGES)) {
544 ConvFloatMat_(src, dst);
546 if (this->DebugLevelIsSet(D_WRITE_IMAGES)) {
553 unsigned int ulx,uly,lrx,lry;
560 if(_fm.IsSeparable()) {
561 kwidth=_fm.GetSepfh()->Size();
562 kheight=_fm.GetSepfv()->Size();
564 kwidth=_fm.GetKernelf()->GetCols();
565 kheight=_fm.GetKernelf()->GetRows();
569 const unsigned int hwsx = KERNCENTER(kwidth);
571 if (lrx>ulx+hwsx) lrx -= hwsx;
else lrx = ulx;
572 const unsigned int hwsy = KERNCENTER(kheight);
574 if (lry>uly+hwsy) lry -= hwsy;
else lry = uly;
581 template <
class InputStorageType,
class OutputStorageType>
585 if (CalculationInFloat()) {
587 if (_fm.IsSeparable()){
588 cout <<
"sep horiz: "<< *_fm.GetSepfh()<<
" vert: "<<*_fm.GetSepfv();
590 cout <<
"kernel: "<<*_fm.GetKernelf();
594 if (_fm.IsSeparable()){
595 cout <<
"sep horiz: "<< *_fm.GetSepih()<<
" vert: "<<*_fm.GetSepiv();
597 cout <<
"kernel: "<<*_fm.GetKerneli();
604 #define FILTER_INSTANTIATION_CLASS Convolution
605 #include "Filterinst.hh"
void Release()
reimplemented from ImageBase
FilterMask _fm
the kernel data used for convolution
int ConvFloatHori_(const Image< InputStorageType > &src, Image< CONV_FLOAT > &dst)
worker function for float separated (horizontal) convolution
generic convolution class.
int SetCorners(unsigned UpperLeftX, unsigned UpperLeftY, unsigned LowerRightX, unsigned LowerRightY)
Sets a rectangular region of interest.
virtual int FilterFloat(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
do the convolution using floating point calculations
bool IsInterleaved() const
virtual int Filter(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
decides on the image types which FilterFunction should be called
unsigned int Size() const
length of the vector
unsigned int GetWidth() const
int ConvFloatMat_(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
worker function for float matrix convolution
void GetROICorners(unsigned int &UpperLeftX, unsigned int &UpperLeftY, unsigned int &LowerRightX, unsigned int &LowerRightY) const
access region of interest rectangle JW
ROI * GetROI()
Returns a pointer to the roi object.
int ConvFloatVert_(const Image< CONV_FLOAT > &src, Image< OutputStorageType > &dst)
worker function for float separated (vertical) convolution
unsigned int GetRows() const
void PrintKernel() const
prints the used filter mask, for debugging
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
base class for simple n->n filter implementations
unsigned int GetHeight() const
bool SamePixelAndChannelCount(const ImageBase &Image) const
checks if data area has same "size" as Image of other type
static int Save(const std::string &filename, const ImageBase &img, const enum TFileFormat FileFormat=FF_auto, const bool sync=BIAS_DEFAULT_SYNC, const int c_jpeg_quality=BIAS_DEFAULT_IMAGE_QUALITY, const bool forceNewID=BIAS_DEFAULT_FORCENEWID, const bool &writeMetaData=true)
Export image as file using extrnal libs.
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
unsigned int GetCols() const
int ConvIntMat_(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
worker function for int matrix convolution
int ConvIntVert_(const Image< CONV_INT > &src, Image< OutputStorageType > &dst)
worker function for int separated (vertical) convolution
int ConvIntHori_(const Image< InputStorageType > &src, Image< CONV_INT > &dst)
worker function for int separated (horizontal) convolution
enum EStorageType GetStorageType() const
void SetZero()
reset data, all kernel to zero, separable to false
int SetROICorners(unsigned int UpperLeftX, unsigned int UpperLeftY, unsigned int LowerRightX, unsigned int LowerRightY)
virtual int FilterInt(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
do the convolution using integer arithmetics and shifts
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase