Apply brush to add/erase black mask (vectorized for speed)
(self, x, y, mode="add")
| 520 | self.update_display() |
| 521 | |
| 522 | def apply_brush(self, x, y, mode="add"): |
| 523 | """Apply brush to add/erase black mask (vectorized for speed)""" |
| 524 | if not self.mask_frames: |
| 525 | return |
| 526 | |
| 527 | mask = self.mask_frames[self.current_frame] |
| 528 | height, width = mask.shape |
| 529 | |
| 530 | # Convert to frame coordinates |
| 531 | frame_x = int(x / self.display_scale) |
| 532 | frame_y = int(y / self.display_scale) |
| 533 | |
| 534 | if frame_x < 0 or frame_x >= width or frame_y < 0 or frame_y >= height: |
| 535 | return |
| 536 | |
| 537 | # Create circular brush using vectorized operations |
| 538 | radius = int(self.brush_size / 2) |
| 539 | |
| 540 | y1 = max(0, frame_y - radius) |
| 541 | y2 = min(height, frame_y + radius + 1) |
| 542 | x1 = max(0, frame_x - radius) |
| 543 | x2 = min(width, frame_x + radius + 1) |
| 544 | |
| 545 | # Get the region |
| 546 | region = mask[y1:y2, x1:x2] |
| 547 | |
| 548 | # Create coordinate grids for distance calculation |
| 549 | yy, xx = np.ogrid[y1:y2, x1:x2] |
| 550 | dist = np.sqrt((xx - frame_x)**2 + (yy - frame_y)**2) |
| 551 | brush_mask = dist <= radius |
| 552 | |
| 553 | if mode == "add": |
| 554 | # Add black: 255->0, 127->63 |
| 555 | region[brush_mask & (region == 255)] = 0 |
| 556 | region[brush_mask & (region == 127)] = 63 |
| 557 | else: # erase |
| 558 | # Erase black: 0->255, 63->127 |
| 559 | region[brush_mask & (region == 0)] = 255 |
| 560 | region[brush_mask & (region == 63)] = 127 |
| 561 | |
| 562 | def on_mask_click(self, event): |
| 563 | """Handle click on mask canvas""" |
no outgoing calls
no test coverage detected