| from backend.utils import convert_to_css_pixel, get_panel_type, types |
| import math |
|
|
| BUBBLE_WIDTH = 200 |
| BUBBLE_HEIGHT = 94 |
|
|
| def add_bubble_padding(least_roi_x, least_roi_y, crop_coord): |
| left,right,top,bottom = crop_coord |
| panel = get_panel_type(left, right, top, bottom) |
| |
| image_width = types[panel]['width'] |
| image_height = types[panel]['height'] |
|
|
| if least_roi_x == 0: |
| if panel == '1' or panel == '2': |
| least_roi_x += 10 |
| elif panel == '3': |
| least_roi_x += 30 |
| else: |
| least_roi_x += 20 |
|
|
| elif least_roi_x == image_width: |
| least_roi_x -= BUBBLE_WIDTH + 15 |
|
|
| elif least_roi_x >= image_width - BUBBLE_WIDTH: |
| least_roi_x -= BUBBLE_WIDTH - (image_width - least_roi_x) + 15 |
|
|
| if least_roi_y == 0: |
| if panel == '2': |
| least_roi_y += 30 |
| else: |
| least_roi_y += 15 |
|
|
| elif least_roi_y == image_height: |
| least_roi_y -= BUUBLE_HEIGHT + 15 |
|
|
| elif least_roi_y >= image_height - BUUBLE_HEIGHT: |
| least_roi_y -= BUUBLE_HEIGHT - (image_height - least_roi_y) + 15 |
| |
| return least_roi_x, least_roi_y |
|
|
|
|
| def get_bubble_position(image_coords, CAM_data=None, lip_coords=None): |
| """ |
| Redesigned bubble placement for smart resize - positions relative to actual image content |
| """ |
| left, right, top, bottom = image_coords |
| |
| |
| image_width = right - left |
| image_height = bottom - top |
| |
| print(f"Image area: {image_width:.0f}x{image_height:.0f} at ({left:.0f}, {top:.0f})") |
| |
| |
| safe_positions = _get_safe_image_positions(left, right, top, bottom, image_width, image_height) |
| |
| |
| if lip_coords and lip_coords[0] != -1 and lip_coords[1] != -1: |
| lip_x, lip_y = lip_coords |
| |
| print(f"Lip detected at coords: ({lip_x}, {lip_y})") |
| |
| |
| face_exclusion_radius = 60 |
| filtered_positions = [] |
| |
| for pos in safe_positions: |
| distance = math.sqrt((pos[0] - lip_x)**2 + (pos[1] - lip_y)**2) |
| if distance > face_exclusion_radius: |
| filtered_positions.append(pos) |
| |
| if filtered_positions: |
| safe_positions = filtered_positions |
| print(f"Filtered to {len(safe_positions)} face-safe positions") |
| else: |
| print("Warning: No face-safe positions found, using all safe positions") |
| |
| |
| best_position = _select_best_image_position(safe_positions, left, right, top, bottom) |
| |
| print(f"Selected bubble position: {best_position}") |
| return best_position |
|
|
| def _get_safe_image_positions(left, right, top, bottom, image_width, image_height): |
| """ |
| Generate safe bubble positions relative to the actual image content |
| """ |
| positions = [] |
| |
| |
| margin_x = BUBBLE_WIDTH / 2 + 20 |
| margin_y = BUBBLE_HEIGHT / 2 + 20 |
| |
| |
| grid_cols = 4 |
| grid_rows = 4 |
| |
| |
| cell_width = image_width / grid_cols |
| cell_height = image_height / grid_rows |
| |
| |
| for row in range(grid_rows): |
| for col in range(grid_cols): |
| x = left + col * cell_width + cell_width / 2 |
| y = top + row * cell_height + cell_height / 2 |
| |
| |
| if (left + margin_x <= x <= right - margin_x and |
| top + margin_y <= y <= bottom - margin_y): |
| positions.append((x, y)) |
| |
| |
| upper_positions = [] |
| upper_margin = 40 |
| |
| |
| for i in range(1, grid_cols): |
| x = left + i * cell_width |
| y = top + upper_margin |
| if (left + margin_x <= x <= right - margin_x and |
| top + margin_y <= y <= bottom - margin_y): |
| upper_positions.append((x, y)) |
| |
| |
| upper_quarter_y = top + (bottom - top) * 0.25 |
| for i in range(1, grid_cols): |
| x = left + i * cell_width |
| y = upper_quarter_y |
| if (left + margin_x <= x <= right - margin_x and |
| top + margin_y <= y <= bottom - margin_y): |
| upper_positions.append((x, y)) |
| |
| positions.extend(upper_positions) |
| |
| |
| corner_margin = 30 |
| corners = [ |
| (left + corner_margin, top + corner_margin), |
| (right - corner_margin, top + corner_margin), |
| (left + corner_margin, top + (bottom - top) * 0.2), |
| (right - corner_margin, top + (bottom - top) * 0.2), |
| (left + corner_margin, bottom - corner_margin), |
| (right - corner_margin, bottom - corner_margin) |
| ] |
| |
| for corner in corners: |
| if (left + margin_x <= corner[0] <= right - margin_x and |
| top + margin_y <= corner[1] <= bottom - margin_y): |
| positions.append(corner) |
| |
| |
| edge_positions = [] |
| edge_margin = 50 |
| |
| |
| for i in range(1, grid_cols): |
| x = left + i * cell_width |
| y = top + edge_margin |
| if (left + margin_x <= x <= right - margin_x and |
| top + margin_y <= y <= bottom - margin_y): |
| edge_positions.append((x, y)) |
| |
| |
| for i in range(1, grid_rows): |
| x = right - edge_margin |
| y = top + i * cell_height |
| if (left + margin_x <= x <= right - margin_x and |
| top + margin_y <= y <= bottom - margin_y): |
| edge_positions.append((x, y)) |
| |
| positions.extend(edge_positions) |
| |
| |
| if len(positions) == 0: |
| center_x = left + image_width / 2 |
| center_y = top + image_height / 2 |
| positions.append((center_x, center_y)) |
| print(f"Warning: Image too small, using center position only") |
| |
| print(f"Generated {len(positions)} safe positions for image area {image_width:.0f}x{image_height:.0f}") |
| return positions |
|
|
| def _select_best_image_position(positions, left, right, top, bottom): |
| """ |
| Select the best position relative to image content |
| Priority: TOP areas > corners > edges > center |
| """ |
| if not positions: |
| |
| return (left + (right - left) / 2, top + (bottom - top) * 0.2) |
| |
| |
| scored_positions = [] |
| for pos in positions: |
| x, y = pos |
| score = 0 |
| |
| |
| upper_threshold = (bottom - top) * 0.4 |
| if y < top + upper_threshold: |
| score += 200 |
| |
| |
| top_quarter = (bottom - top) * 0.25 |
| if y < top + top_quarter: |
| score += 150 |
| |
| |
| corner_threshold = 50 |
| if (x < left + corner_threshold or x > right - corner_threshold) and \ |
| (y < top + corner_threshold or y > bottom - corner_threshold): |
| score += 100 |
| |
| |
| edge_threshold = 80 |
| if (x < left + edge_threshold or x > right - edge_threshold) or \ |
| (y < top + edge_threshold or y > bottom - edge_threshold): |
| score += 50 |
| |
| |
| if x > left + (right - left) * 0.6: |
| score += 30 |
| |
| |
| lower_threshold = (bottom - top) * 0.7 |
| if y > top + lower_threshold: |
| score -= 50 |
| |
| scored_positions.append((pos, score)) |
| |
| |
| scored_positions.sort(key=lambda x: x[1], reverse=True) |
| best_position = scored_positions[0][0] |
| |
| print(f"Selected position with score {scored_positions[0][1]} at y={best_position[1]:.0f} (top={top:.0f}, bottom={bottom:.0f})") |
| return best_position |