35 const float *outer_mask,
41 for (const int64_t y : sub_y_range) {
42 for (const int64_t x : IndexRange(size.x)) {
43 int2 texel = int2(x, y);
45 bool has_inner_non_masked_neighbors = false;
46 bool has_outer_non_masked_neighbors = false;
47 for (int j = -1; j <= 1; j++) {
48 for (int i = -1; i <= 1; i++) {
49 int2 offset = int2(i, j);
51 if (offset == int2(0)) {
55 if (load_mask(inner_mask, texel + offset, size) == 0.0f) {
56 has_inner_non_masked_neighbors = true;
59 float boundary_fallback = include_edges_of_image_ ? 0.0f : 1.0f;
60 if (load_mask(outer_mask, texel + offset, size, boundary_fallback) == 0.0f) {
61 has_outer_non_masked_neighbors = true;
64 if (has_inner_non_masked_neighbors && has_outer_non_masked_neighbors) {
70 bool is_inner_masked = load_mask(inner_mask, texel, size) > 0.0f;
71 bool is_outer_masked = load_mask(outer_mask, texel, size) > 0.0f;
73 bool is_inner_boundary = is_inner_masked && has_inner_non_masked_neighbors &&
74 (is_outer_masked || include_all_inner_edges_);
75 bool is_outer_boundary = is_outer_masked && !is_inner_masked &&
76 has_outer_non_masked_neighbors;
78 int2 inner_jump_flooding_value = initialize_jump_flooding_value(texel, is_inner_boundary);
79 int2 outer_jump_flooding_value = initialize_jump_flooding_value(texel, is_outer_boundary);
81 const size_t output_index = size_t(texel.y) * size.x + texel.x;
82 inner_boundary[output_index] = inner_jump_flooding_value;
83 outer_boundary[output_index] = outer_jump_flooding_value;
89void DoubleEdgeMaskOperation::compute_gradient(
const float *inner_mask_buffer,
90 const float *outer_mask_buffer,
95 const int2 size =
int2(this->get_width(), this->get_height());
97 for (const int64_t y : sub_y_range) {
98 for (const int64_t x : IndexRange(size.x)) {
99 int2 texel = int2(x, y);
100 const size_t index = size_t(texel.y) * size.x + texel.x;
102 float inner_mask = inner_mask_buffer[index];
103 if (inner_mask != 0.0f) {
104 output_mask[index] = 1.0f;
108 float outer_mask = outer_mask_buffer[index];
109 if (outer_mask == 0.0f) {
110 output_mask[index] = 0.0f;
114 int2 inner_boundary_texel = flooded_inner_boundary[index];
115 int2 outer_boundary_texel = flooded_outer_boundary[index];
116 float distance_to_inner = math::distance(float2(texel), float2(inner_boundary_texel));
117 float distance_to_outer = math::distance(float2(texel), float2(outer_boundary_texel));
119 float gradient = distance_to_outer / (distance_to_outer + distance_to_inner);
121 output_mask[index] = gradient;
127void DoubleEdgeMaskOperation::compute_double_edge_mask(
const float *inner_mask,
128 const float *outer_mask,
131 const int2 size =
int2(this->get_width(), this->get_height());
132 Array<int2> inner_boundary(
size_t(size.x) * size.y);
133 Array<int2> outer_boundary(
size_t(size.x) * size.y);
134 compute_boundary(inner_mask, outer_mask, inner_boundary, outer_boundary);
138 inner_mask, outer_mask, flooded_inner_boundary, flooded_outer_boundary, output_mask);
141DoubleEdgeMaskOperation::DoubleEdgeMaskOperation()
143 this->add_input_socket(DataType::Value);
144 this->add_input_socket(DataType::Value);
145 this->add_output_socket(DataType::Value);
146 include_all_inner_edges_ =
false;
147 include_edges_of_image_ =
false;
148 flags_.can_be_constant =
true;
149 is_output_rendered_ =
false;
159void DoubleEdgeMaskOperation::update_memory_buffer(
MemoryBuffer *output,
163 if (!is_output_rendered_) {
168 is_output_rendered_ =
true;
178 BLI_assert(output->get_width() == this->get_width());
179 BLI_assert(output->get_height() == this->get_height());
180 compute_double_edge_mask(
182 is_output_rendered_ =
true;
184 if (inner_mask != input_inner_mask) {
187 if (outer_mask != input_outer_mask) {