-
Notifications
You must be signed in to change notification settings - Fork 0
/
image_ops.h
140 lines (101 loc) · 3.57 KB
/
image_ops.h
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
#pragma once
#ifndef IMAGE_OPS_H
#define IMAGE_OPS_H
#include "image.h"
#include <functional>
#include <cmath>
#include <cstdint>
#include <cassert>
extern const float eps;
float clamp(float f, float min, float max);
int clampi(int i, int min, int max);
int clampi(int i, int max);
/**
* References
*
* Kernel, image processing: https://en.wikipedia.org/wiki/Kernel_(image_processing)
* Sobel Operator: https://en.wikipedia.org/wiki/Sobel_operator
*/
template<int N>
struct Kernel {
constexpr Kernel(const std::initializer_list<std::initializer_list<float>>& il) {
// static_assert(il.size() == N); does not work bc the expression that created il is not a constexpr.
int row = 0, col = 0;
for (const std::initializer_list<float>& rowList: il) {
col = 0;
for (float f: rowList) {
data[row][col] = f;
++col;
}
++row;
}
}
float data[N][N];
};
/// Vertical 1D kernel
template<int N>
struct KernelV {
KernelV(const std::initializer_list<float>& il) {
int i = 0;
for (float elem: il) { data[i] = elem; ++i; }
}
float data[N];
};
/// Horizontal 1D kernel
template<int N>
struct KernelH {
KernelH(const std::initializer_list<float>& il) {
int i = 0;
for (float elem: il) { data[i] = elem; ++i; }
}
float data[N];
};
/// Creates a 3x3 gaussian kernel
Kernel<3> create3gauss();
/// Creates a 5x5 gaussian kernel with sigma = 1.
Kernel<5> create5gauss();
KernelV<5> create5gaussV();
/// Note that this is the same because of the symmetry of the Gaussian.
KernelH<5> create5gaussH();
/// Creates a 5x5 gaussian kernel with sigma = 1.4.
Kernel<5> create5gauss1_4();
KernelV<5> create5gauss14V();
KernelH<5> create5gauss14H();
KernelV<5> create5gauss2V();
KernelH<5> create5gauss2H();
/// Creates a flipped Sobel kernel in x direction.
Kernel<3> createSobelX();
/// Creates a flipped Sobel kernel in y direction.
Kernel<3> createSobelY();
KernelV<3> createSobelXV();
KernelH<3> createSobelXH();
KernelV<3> createSobelYV();
KernelH<3> createSobelYH();
float clamp(float f, float min, float max);
/// Convolves image with a kernel, kernel must be flipped.
template<class ImageT, int N>
FloatImage conv(const ImageT& image, const Kernel<N>& kernel);
/// Same as above but with separated kernels.
template<class ImageT, int N>
FloatImage conv(const ImageT& image, const KernelV<N>& kv, const KernelH<N>& kh);
/// Return the channel value which has the maximum absolute value.
float maxAbsChannel(float r, float g, float b);
float meanChannel(float r, float g, float b);
/// Convolves and reduces the channels to 1. Kernel must be flipped.
template<class ImageT, int N>
FloatImage convReduce(const ImageT& image, const Kernel<N>& kernel,
std::function<float(float, float, float)> reduce=maxAbsChannel);
/// Same as above but with separated kernels.
template<class ImageT, int N>
FloatImage convReduce(const ImageT& image, const KernelV<N>& kv, const KernelH<N>& kh,
std::function<float(float, float, float)> reduce=maxAbsChannel);
Image invert(const Image& image);
struct MinMaxf { float min; float max;};
MinMaxf findMinMaxf(const FloatImage& image);
/// Returns a new image with all values in the range [0, 1]
FloatImage normalizeImage(const FloatImage& image);
/// Removes the alpha channel under the assumption that the background is white.
Image removeAlpha(const Image& image);
/// Finds a threshold for the top q quartiles pixels.
float findThreshold(const FloatImage& image, float q = 0.1);
#endif