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
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
USAGE("[-a min-area] [-h min-height] [-w min-width] X Y Z [alpha]")
struct pair {
size_t x;
size_t w;
};
static struct stream stream;
static double X, Y, Z, alpha = 1;
static size_t min_width = 1;
static size_t min_height = 1;
static size_t min_area = 1;
static struct pair *stack = NULL;
static size_t *cache = NULL;
static char *buf = NULL;
static void
process(const void *colour)
{
size_t y, x, x0, w, w0, h, top, area;
size_t best_area, x1, x2, y1, y2;
for (;;) {
top = x1 = x2 = y1 = y2 = best_area = 0;
memset(cache, 0, (stream.width + 1) * sizeof(*cache));
for (y = 0; eread_row(&stream, buf); y++) {
w = 0;
for (x = 0; x <= stream.width; x++) {
if (x != stream.width) {
if (!memcmp(buf + x * stream.pixel_size, colour, stream.pixel_size))
cache[x] += 1;
else
cache[x] = 0;
}
if (cache[x] > w) {
stack[top].x = x;
stack[top++].w = w;
w = cache[x];
} else if (cache[x] < w) {
do {
x0 = stack[--top].x;
w0 = stack[top].w;
area = w * (x - x0);
if (area > best_area) {
best_area = area;
x1 = x0;
x2 = x - 1;
y1 = y - w + 1;
y2 = y;
}
w = w0;
} while (cache[x] < w);
if ((w = cache[x])) {
stack[top].x = x0;
stack[top++].w = w0;
}
}
}
fprintf(stderr, "%zu\n", y);
}
if (!y)
break;
w = x2 - x1 + 1;
h = y2 - y1 + 1;
if (best_area < min_area || w < min_width || h < min_height)
printf("0 0 0 0\n");
else
printf("%zu %zu %zu %zu\n", x1, y1, w, h);
}
}
int
main(int argc, char *argv[])
{
double colour_lf[4];
float colour_f[4];
ARGBEGIN {
case 'a':
min_area = etozu_flag('a', UARGF(), 1, SIZE_MAX);
break;
case 'h':
min_height = etozu_flag('h', UARGF(), 1, SIZE_MAX);
break;
case 'w':
min_width = etozu_flag('w', UARGF(), 1, SIZE_MAX);
break;
default:
usage();
} ARGEND;
if (argc != 3 && argc != 4)
usage();
X = etolf_arg("the X value", argv[0]);
Y = etolf_arg("the Y value", argv[1]);
Z = etolf_arg("the Z value", argv[2]);
if (argc > 3)
alpha = etolf_arg("the alpha value", argv[3]);
eopen_stream(&stream, NULL);
echeck_dimensions(&stream, WIDTH, NULL);
if (stream.width == SIZE_MAX)
eprintf("video is too wide\n");
if (stream.width > SIZE_MAX / stream.height)
eprintf("video is too large\n");
stack = emalloc2(stream.width + 1, sizeof(*stack));
cache = emalloc2(stream.width + 1, sizeof(*cache));
buf = emalloc(stream.row_size);
if (stream.encoding == DOUBLE) {
colour_lf[0] = X;
colour_lf[1] = Y;
colour_lf[2] = Z;
colour_lf[3] = alpha;
process(colour_lf);
} else if (stream.encoding == FLOAT) {
colour_f[0] = (float)X;
colour_f[1] = (float)Y;
colour_f[2] = (float)Z;
colour_f[3] = (float)alpha;
process(colour_f);
} else {
eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
}
fshut(stdout, "<stdout>");
free(stack);
free(cache);
free(buf);
return 0;
}
|