VapourSynth-llvmexpr
Loading...
Searching...
No Matches
area_filter.expr
Go to the documentation of this file.
1# Copyright (C) 2025 yuygfgg
2#
3# This file is part of Vapoursynth-llvmexpr.
4#
5# Vapoursynth-llvmexpr is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Vapoursynth-llvmexpr is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Vapoursynth-llvmexpr. If not, see <https://www.gnu.org/licenses/>.
17
18@requires std
19
20@ifndef __SINGLEEXPR__
21@error This expr should be used in SingleExpr mode
22@endif
23
24@if __INPUT_NUM__ != 1
25@error This expr requires exactly one input clip
26@endif
27
28@if __INPUT_SAMPLETYPE_0__ == stFloat
29@define FG_VAL_INPUT 1
30@else
31@define FG_VAL_INPUT 2 ** (__INPUT_BITDEPTH_0__ - 1)
32@endif
33
34@if __OUTPUT_SAMPLETYPE__ == stFloat
35@define FG_VAL_OUTPUT 1
36@else
37@define FG_VAL_OUTPUT 2 ** (__OUTPUT_BITDEPTH__ - 1)
38@endif
39
40@define BG_VAL 0
41@define MIN_SIZE_THR 100
42
43@define NUM_PIXELS __WIDTH__ * __HEIGHT__
44
45@define MAX_LABELS (NUM_PIXELS) / 2 + 2
46
47label_map = new(NUM_PIXELS);
48parent = new(MAX_LABELS);
49area = new(MAX_LABELS);
50
51dx = new(4); # Delta X
52dy = new(4); # Delta Y
53dx[0] = -1; dy[0] = 0;
54dx[1] = -1; dy[1] = -1;
55dx[2] = 0; dy[2] = -1;
56dx[3] = 1; dy[3] = -1;
57
58# Initialize
59i = 0;
60while (i < MAX_LABELS) {
61 parent[i] = i;
62 area[i] = 0;
63 i = i + 1;
64}
65i = 0;
66while (i < NUM_PIXELS) {
67 label_map[i] = 0;
68 i = i + 1;
69}
70
71<global<parent>>
72function find_root(Value i) {
73 root = i;
74 while (parent[root] != root) {
75 root = parent[root];
76 }
77 while (parent[i] != root) {
78 next_i = parent[i];
79 parent[i] = root;
80 i = next_i;
81 }
82 return root;
83}
84
85<global<parent>>
86function union_sets(Value i, Value j) {
87 i_root = find_root(i);
88 j_root = find_root(j);
89 if (i_root != j_root) {
90 if (i_root < j_root) {
91 parent[j_root] = i_root;
92 } else {
93 parent[i_root] = j_root;
94 }
95 }
96}
97
98# Labeling and Recording Equivalences
99next_label = 1;
100y = 0;
101while (y < __HEIGHT__) {
102 x = 0;
103 while (x < __WIDTH__) {
104 pixel_val = dyn($x, x, y, 0);
105
106 if (pixel_val != BG_VAL) {
107 neighbor_labels = new(4);
108 n_count = 0;
109
110 k = 0;
111 while (k < 4) {
112 nx = x + dx[k];
113 ny = y + dy[k];
114
115 # Boundary check (ny is always <= y, so only need ny >= 0)
116 if (nx >= 0 && nx < __WIDTH__ && ny >= 0) {
117 if (dyn($x, nx, ny, 0) != BG_VAL) {
118 neighbor_labels[n_count] = label_map[ny * __WIDTH__ + nx];
119 n_count = n_count + 1;
120 }
121 }
122 k = k + 1;
123 }
124
125 if (n_count == 0) {
126 label_map[y * __WIDTH__ + x] = next_label;
127 next_label = next_label + 1;
128 } else {
129 current_label = neighbor_labels[0];
130 k = 1;
131 while(k < n_count) {
132 current_label = min(current_label, neighbor_labels[k]);
133 k = k + 1;
134 }
135
136 label_map[y * __WIDTH__ + x] = current_label;
137
138 k = 0;
139 while(k < n_count) {
140 union_sets(current_label, neighbor_labels[k]);
141 k = k + 1;
142 }
143 }
144 }
145 x = x + 1;
146 }
147 y = y + 1;
148}
149
150# Resolve Labels and Calculate Area
151y = 0;
152while (y < __HEIGHT__) {
153 x = 0;
154 while (x < __WIDTH__) {
155 idx = y * __WIDTH__ + x;
156 if (label_map[idx] > 0) {
157 root = find_root(label_map[idx]);
158 label_map[idx] = root;
159 area[root] = area[root] + 1;
160 }
161 x = x + 1;
162 }
163 y = y + 1;
164}
165
166# Generate Final Output
167y = 0;
168while (y < __HEIGHT__) {
169 x = 0;
170 while (x < __WIDTH__) {
171 final_val = BG_VAL;
172 label = label_map[y * __WIDTH__ + x];
173 if (label > 0) {
174 if (area[label] >= MIN_SIZE_THR) {
175 final_val = FG_VAL_INPUT;
176 }
177 }
178 store(x, y, 0, final_val);
179 x = x + 1;
180 }
181 y = y + 1;
182}