-
Notifications
You must be signed in to change notification settings - Fork 0
/
derivative.c
137 lines (111 loc) · 2.91 KB
/
derivative.c
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
// Note the weird thing is that the colors are normalized based on the min/max
// derivatives values that actually occur.
// This seems incorrect, but using the real derivative values makes the changes
// tiny and subject to awful compression artifacts.
#include <stdio.h>
#include <stdlib.h>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_PSD
#define STBI_NO_HDR
#define STBI_NO_GIF
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
void add_margin(const unsigned char* src, unsigned char* dst, int cols, int rows, int comp)
{
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < cols; ++c)
{
int src_index = (c + r * cols) * comp;
int dst_index = ((c + 1) + (r + 1) * (cols + 2)) * comp;
dst[dst_index] = src[src_index];
for (int j = -1; j <= 1; ++j)
{
for (int i = -1; i <= 1; ++i)
{
if (i == 0 && j == 0) continue;
int border_index = ((c + i + 1) + (r + j + 1) * (cols + 2)) * comp;
if (c + i == -1 || c + i == cols ||
r + j == -1 || r + j == rows)
{
dst[border_index] = src[src_index];
}
}
}
}
}
}
int main(int argc, const char* argv[])
{
if (argc < 3)
{
fprintf(stderr, "derivative [IN] [OUT].png");
return 1;
}
int cols, rows;
unsigned char* height_data = stbi_load(argv[1], &cols, &rows, NULL, 1);
if (!height_data)
{
fprintf(stderr, "failed to load data");
return 1;
}
unsigned char* height = malloc(sizeof(unsigned char) * (cols + 2) * (rows + 2));
add_margin(height_data, height, cols, rows, 1);
const int comp = 3;
float* data = malloc(sizeof(float) * cols * rows * comp);
// https://en.wikipedia.org/wiki/Sobel_operator
float kernel_x[3][3] = {
{-1.0, 0.0, 1.0},
{-2.0, 0.0, 2.0},
{-1.0, 0.0, 1.0}
};
float kernel_y[3][3] = {
{-1.0, -2.0, -1.0},
{0.0, 0.0, 0.0},
{1.0, 2.0, 1.0}
};
float max_derive = 0.0;
for (int r = 0; r < rows; ++r)
{
for (int c = 0; c < cols; ++c)
{
int row_len = cols + 2;
int src_index = (c + 1) + (r + 1) * row_len;
float dx = 0.0;
float dy = 0.0;
for (int j = 0; j < 3; ++j)
{
for (int i = 0; i < 3; ++i)
{
int index = src_index + (i - 1) + (j - 1) * row_len;
float p = (height[index] / 256.0) * 2.0 - 1.0;
dx += p * kernel_x[j][i];
dy += p * kernel_y[j][i];
}
}
int dst_index = (c + r * cols) * comp;
data[dst_index] = dx;
data[dst_index + 1] = dy;
data[dst_index + 2] = 0.0;
if (fabs(dx) > max_derive) {
max_derive = fabs(dx);
}
if (fabs(dy) > max_derive) {
max_derive = fabs(dy);
}
}
}
unsigned char* pixels = malloc(sizeof(unsigned char) * cols * rows * comp);
size_t len = rows * cols * comp;
for (int i = 0; i < len; ++i)
{
if (i % 3 == 2) {
pixels[i] = 0;
} else {
pixels[i] = (unsigned char)( ((data[i] / max_derive) * 0.5 + 0.5) * 256.0);
}
}
stbi_write_png(argv[2], cols, rows, comp, pixels, 0);
return 0;
}