-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathCppDoFilterOperation.txt
More file actions
executable file
·158 lines (139 loc) · 5.39 KB
/
CppDoFilterOperation.txt
File metadata and controls
executable file
·158 lines (139 loc) · 5.39 KB
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
#include <vector>
#include <cassert>
//Return a y-x-ordered 2D std::vector with the intensitief of grey
//values from range [0,255] (0=black,255=white) after the filter operation
//From http://www.richelbilderbeek.nl/CppDoFilterOperation.htm
const std::vector<std::vector<int> > DoFilterOperation(
const std::vector<std::vector<int> >& source, //y-x-ordered
const std::vector<std::vector<double> >& filter) //y-x-ordered
{
assert(!source.empty());
assert(!filter.empty());
const int width = source[0].size();
const int height = source.size();
std::vector<std::vector<int> > v(height, std::vector<int>(width));
const int maxx = source[0].size();
const int maxy = source.size();
const int midX = filter[0].size() / 2;
const int midY = filter.size() / 2;
const std::pair<double, double> filterRange = GetFilterRange(filter);
assert(filterRange.first < filterRange.second);
for (int y=0; y!=maxy; ++y)
{
const int writeY = y;
assert(writeY >= 0 && writeY < static_cast<int>(v.size()) );
std::vector<int>& vLine = v[writeY];
for (int x=0; x!=maxx; ++x)
{
//The x and y values are the topleft coordinate of where
// the filter will be applied to. This coordinat can be out of
// the range, but at least one pixel of where the filter will be
// applied to will be in range
//The pixel value is normalized to the area the
// filter operation took place on
//The outcome of the filter operation is written to
// (x + midX, y + midY), which HAS to be in range
const double unscaledPixelValue = GetFilterOperationPixel(source,x-midX,y-midY,filter);
//Scale the unscaledPixelValue.
//The maximal value of unscaledPixelValue is the sum of all positive
//values in the filter * 255.
//The minimum value of unscaledPixelValue is the sum of all negative
//values in the filter * 255.
//The scaled pixel value must be obtained by transforming the unscaled
//range [min,max] to [0,256>.
const double relUnscaledRange
= (unscaledPixelValue - filterRange.first)
/ (filterRange.second - filterRange.first);
assert(relUnscaledRange >= 0.0 && relUnscaledRange <= 1.0);
const double scaledRange = relUnscaledRange * 255;
assert(scaledRange >= 0.0 && scaledRange < 256.0);
const int pixel = scaledRange;
const int writeX = x;
assert(writeX >= 0 && writeX < width);
vLine[writeX] = pixel;
}
}
assert(source[0].size()==v[0].size());
assert(source.size()==v.size());
return v;
}
//The sourceX and sourceY values are the topleft coordinate of where
// the filter will be applied to. This coordinat can be out of
// the range, but at least one pixel of where the filter will be
// applied to will be in range. If there are no pixels in range,
// an assertion will fail.
//The pixel value is normalized to the area the
// filter operation took place on. Therefore, this area must be non-zero
//The outcome of this filter operation will be written to
// (x + midX, y + midY), which HAS to be in range
//From http://www.richelbilderbeek.nl/CppDoFilterOperation.htm
const double GetFilterOperationPixel(
const std::vector<std::vector<int> >& source, //y-x-ordered
const int sourceX,
const int sourceY,
const std::vector<std::vector<double> >& filter) //y-x-ordered
{
assert(!source.empty());
assert(!filter.empty());
const int sourceMaxY = source.size();
const int sourceMaxX = source[0].size();
const int filterMaxY = filter.size();
const int filterMaxX = filter[0].size();
double result = 0.0;
int nPixels = 0;
for (int y=0; y!=filterMaxY; ++y)
{
const int readY = sourceY + y;
if ( readY < 0 || readY >= sourceMaxY) continue;
assert(y >= 0);
assert(y < static_cast<int>(filter.size()));
const std::vector<double>& lineFilter = filter[y];
assert(readY >= 0);
assert(readY < static_cast<int>(source.size()));
const std::vector<int>& lineSource = source[readY];
for (int x=0; x!=filterMaxX; ++x)
{
const int readX = sourceX + x;
if ( readX < 0 || readX >= sourceMaxX) continue;
assert(x >= 0);
assert(x < filterMaxX);
assert(readX >= 0);
assert(readX < sourceMaxX);
const double deltaResult = static_cast<double>(lineSource[readX]) * lineFilter[x];
result += deltaResult;
++nPixels;
}
}
assert(nPixels!=0);
const double filteredValue = result / static_cast<double>(nPixels);
return filteredValue;
}
//Obtains the range a filter can have
//Assumes the every element has a maximum value of 255
//From http://www.richelbilderbeek.nl/CppDoFilterOperation.htm
const std::pair<double, double> GetFilterRange(const std::vector<std::vector<double> >& filter)
{
assert(!filter.empty());
const int maxx = filter[0].size();
const int maxy = filter.size();
assert(maxx + maxy > 2 && "Filter size must be bigger then 1x1");
double min = 0.0;
double max = 0.0;
for (int y=0; y!=maxy; ++y)
{
assert(y >= 0);
assert(y < static_cast<int>(filter.size()) );
const std::vector<double>& lineFilter = filter[y];
for (int x=0; x!=maxx; ++x)
{
assert(x >= 0);
assert(x < static_cast<int>(lineFilter.size()) );
const double value = lineFilter[x];
if (value < 0.0) min +=value;
else if (value > 0.0) max +=value;
}
}
const std::pair<double,double> range
= std::make_pair(min * 255.0, max * 255.0);
return range;
}