1 /*
2 * imagesource_convolution.cpp - Applies a convolution filter to an image.
3 *
4 * Supports Greyscale, RGB and CMYK data
5 * Doesn't (yet) support random access
6 *
7 * Copyright (c) 2008 by Alastair M. Robinson
8 * Distributed under the terms of the GNU General Public License -
9 * see the file named "COPYING" for more details.
10 *
11 */
12
13 #include <iostream>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <math.h>
17
18 #include "imagesource_convolution.h"
19
20 using namespace std;
21
22 #ifndef M_PI
23 #define M_PI 3.14159265358979323846
24 #endif
25
26 // The row cache is just a simplistic ring-buffer type cache which handles
27 // the details of tracking several rows of "support" data.
28
29 class ISConvolution_RowCache
30 {
31 public:
32 ISConvolution_RowCache(ImageSource_Convolution *source);
33 ~ISConvolution_RowCache();
34 float *GetRow(int row);
35 private:
36 ImageSource_Convolution *source;
37 float *cache;
38 int cachewidth,cachehoffset;
39 int bufferrows;
40 int currentrow;
41 };
42
43
~ISConvolution_RowCache()44 ISConvolution_RowCache::~ISConvolution_RowCache()
45 {
46 if(cache)
47 free(cache);
48 }
49
50
ISConvolution_RowCache(ImageSource_Convolution * source)51 ISConvolution_RowCache::ISConvolution_RowCache(ImageSource_Convolution *source)
52 : source(source), currentrow(-1)
53 {
54 cachewidth=source->width+source->hextra*2;
55 cachehoffset=source->hextra;
56 bufferrows=source->vextra*2+1;
57 cache=(float *)malloc(sizeof(float)*source->samplesperpixel*cachewidth*bufferrows);
58 }
59
60
GetRow(int row)61 inline float *ISConvolution_RowCache::GetRow(int row)
62 {
63 if(row<0)
64 row=0;
65 if(row>=source->source->height)
66 row=source->source->height-1;
67 int crow=row%(source->vextra*2+1);
68 float *rowptr=cache+crow*source->samplesperpixel*cachewidth;
69 if(row>currentrow)
70 {
71 currentrow=row;
72 ISDataType *src=source->source->GetRow(row);
73 for(int x=0;x<cachewidth;++x)
74 {
75 int sx=x-cachehoffset;
76 if(sx<0) sx=0;
77 if(sx>=source->width) sx=source->width-1;
78 for(int s=0;s<source->samplesperpixel;++s)
79 {
80 float a=src[sx*source->samplesperpixel+s];
81 rowptr[x*source->samplesperpixel+s]=a;
82 }
83 }
84 }
85 return(rowptr+cachehoffset*source->samplesperpixel);
86 }
87
88
~ImageSource_Convolution()89 ImageSource_Convolution::~ImageSource_Convolution()
90 {
91 if(tmprows)
92 free(tmprows);
93 if(cache)
94 delete cache;
95 if(source)
96 delete source;
97 }
98
99
GetRow(int row)100 ISDataType *ImageSource_Convolution::GetRow(int row)
101 {
102 if(row==currentrow)
103 return(rowbuffer);
104
105 int kw=kernel->GetWidth();
106 int kh=kernel->GetHeight();
107
108 for(int r=0;r<kh;++r)
109 {
110 tmprows[r]=cache->GetRow(row+(r-vextra));
111 }
112
113 for(int x=0;x<width;++x)
114 {
115 float t[5]={0.0,0.0,0.0,0.0,0.0};
116 for(int ky=0;ky<kh;++ky)
117 {
118 for(int kx=0;kx<kw;++kx)
119 {
120 for(int s=0;s<samplesperpixel;++s)
121 {
122 t[s]+=kernel->Kernel(kx,ky) * tmprows[ky][(x+(kx-hextra))*samplesperpixel+s];
123 }
124 }
125 }
126 for(int s=0;s<samplesperpixel;++s)
127 {
128 float a=t[s];
129 if(a<0.0) a=0.0;
130 if(a>IS_SAMPLEMAX) a=IS_SAMPLEMAX;
131 rowbuffer[x*samplesperpixel+s]=ISDataType(a);
132 }
133 }
134
135 currentrow=row;
136
137 return(rowbuffer);
138 }
139
140
ImageSource_Convolution(struct ImageSource * source,ConvKernel * kernel)141 ImageSource_Convolution::ImageSource_Convolution(struct ImageSource *source,ConvKernel *kernel)
142 : ImageSource(source), source(source), kernel(kernel)
143 {
144 hextra=kernel->GetWidth()/2;
145 vextra=kernel->GetHeight()/2;
146 cache=new ISConvolution_RowCache(this);
147 tmprows=(float **)malloc(sizeof(float *)*kernel->GetHeight());
148 MakeRowBuffer();
149 randomaccess=false;
150 }
151