-
Notifications
You must be signed in to change notification settings - Fork 0
/
ConvolutionalFilter.cs
98 lines (76 loc) · 2.45 KB
/
ConvolutionalFilter.cs
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace cg_proj_1 {
abstract class ConvolutionalFilter : IImageFilter {
private float [] coefficients;
private int width, height;
private Point anchor;
public int Width {
get { return width; }
}
public int Height {
get { return height; }
}
public Point Anchor {
get { return anchor; }
}
public float [] Coefficients {
get { return coefficients; }
protected set {
if (value.Length != width * height) {
throw new ArgumentException ("convolutional filter requires " + width * height + " coefficients");
}
Array.Copy (value, coefficients, width * height);
}
}
public abstract string Name { get; }
public ConvolutionalFilter (int width, int height, Point anchor, float [] coefficients) {
this.create (width, height, anchor, coefficients);
}
protected void create (int width, int height, Point anchor, float [] coefficients) {
this.width = width;
this.height = height;
this.anchor = anchor;
// with validation
this.coefficients = new float [this.width * this.height];
Coefficients = coefficients;
}
public byte [] apply (byte [] bitmap, int imageWidth, int imageHeight, int stride) {
int channels = stride / imageWidth;
float divisor = coefficients.Sum ();
int padding = (4 - (imageWidth * channels % 4)) % 4;
int scanlineWidth = imageWidth * channels + padding;
if (divisor == 0) {
divisor = 1.0f;
}
byte [] output = new byte [bitmap.Length];
unsafe {
Parallel.For (0, channels, (int channel) => {
int cx, cy, fx, fy, offsetX, offsetY;
float sum;
for (int i = 0; i < imageWidth * imageHeight; ++i) {
cx = i % imageWidth;
cy = i / imageWidth;
// apply filter to fragment at (cx, cy)
sum = 0.0f;
for (int j = 0; j < width * height; ++j) {
fx = j % width;
fy = j / width;
offsetX = fx - anchor.X;
offsetY = fy - anchor.Y;
fx = Math.Min (Math.Max (cx + offsetX, 0), imageWidth - 1);
fy = Math.Min (Math.Max (cy + offsetY, 0), imageHeight - 1);
sum += Coefficients [j] * ((float) bitmap [fy * scanlineWidth + fx * channels + channel] / 255.0f);
}
output [cy * scanlineWidth + cx * channels + channel] = (byte) Math.Min (255, Math.Max (0, Math.Round ((255 * sum) / divisor)));
}
});
}
return output;
}
}
}