| from typing import Tuple |
| import math |
| import cv2 |
| import numpy as np |
|
|
| def draw_reticle(img, u, v, label_color): |
| """ |
| Draws a reticle (cross-hair) on the image at the given position on top of |
| the original image. |
| @param img (In/Out) uint8 3 channel image |
| @param u X coordinate (width) |
| @param v Y coordinate (height) |
| @param label_color tuple of 3 ints for RGB color used for drawing. |
| """ |
| |
| u = int(u) |
| v = int(v) |
|
|
| white = (255, 255, 255) |
| cv2.circle(img, (u, v), 10, label_color, 1) |
| cv2.circle(img, (u, v), 11, white, 1) |
| cv2.circle(img, (u, v), 12, label_color, 1) |
| cv2.line(img, (u, v + 1), (u, v + 3), white, 1) |
| cv2.line(img, (u + 1, v), (u + 3, v), white, 1) |
| cv2.line(img, (u, v - 1), (u, v - 3), white, 1) |
| cv2.line(img, (u - 1, v), (u - 3, v), white, 1) |
|
|
|
|
| def draw_text( |
| img, |
| *, |
| text, |
| uv_top_left, |
| color=(255, 255, 255), |
| fontScale=0.5, |
| thickness=1, |
| fontFace=cv2.FONT_HERSHEY_SIMPLEX, |
| outline_color=(0, 0, 0), |
| line_spacing=1.5, |
| ): |
| """ |
| Draws multiline with an outline. |
| """ |
| assert isinstance(text, str) |
|
|
| uv_top_left = np.array(uv_top_left, dtype=float) |
| assert uv_top_left.shape == (2,) |
|
|
| for line in text.splitlines(): |
| (w, h), _ = cv2.getTextSize( |
| text=line, |
| fontFace=fontFace, |
| fontScale=fontScale, |
| thickness=thickness, |
| ) |
| uv_bottom_left_i = uv_top_left + [0, h] |
| org = tuple(uv_bottom_left_i.astype(int)) |
|
|
| if outline_color is not None: |
| cv2.putText( |
| img, |
| text=line, |
| org=org, |
| fontFace=fontFace, |
| fontScale=fontScale, |
| color=outline_color, |
| thickness=thickness * 3, |
| lineType=cv2.LINE_AA, |
| ) |
| cv2.putText( |
| img, |
| text=line, |
| org=org, |
| fontFace=fontFace, |
| fontScale=fontScale, |
| color=color, |
| thickness=thickness, |
| lineType=cv2.LINE_AA, |
| ) |
|
|
| uv_top_left += [0, h * line_spacing] |
|
|
|
|
| def get_image_transform( |
| input_res: Tuple[int,int]=(1280,720), |
| output_res: Tuple[int,int]=(640,480), |
| bgr_to_rgb: bool=False): |
|
|
| iw, ih = input_res |
| ow, oh = output_res |
| rw, rh = None, None |
| interp_method = cv2.INTER_AREA |
|
|
| if (iw/ih) >= (ow/oh): |
| |
| rh = oh |
| rw = math.ceil(rh / ih * iw) |
| if oh > ih: |
| interp_method = cv2.INTER_LINEAR |
| else: |
| rw = ow |
| rh = math.ceil(rw / iw * ih) |
| if ow > iw: |
| interp_method = cv2.INTER_LINEAR |
| |
| w_slice_start = (rw - ow) // 2 |
| w_slice = slice(w_slice_start, w_slice_start + ow) |
| h_slice_start = (rh - oh) // 2 |
| h_slice = slice(h_slice_start, h_slice_start + oh) |
| c_slice = slice(None) |
| if bgr_to_rgb: |
| c_slice = slice(None, None, -1) |
|
|
| def transform(img: np.ndarray): |
| assert img.shape == ((ih,iw,3)) |
| |
| img = cv2.resize(img, (rw, rh), interpolation=interp_method) |
| |
| img = img[h_slice, w_slice, c_slice] |
| return img |
| return transform |
|
|
| def optimal_row_cols( |
| n_cameras, |
| in_wh_ratio, |
| max_resolution=(1920, 1080) |
| ): |
| out_w, out_h = max_resolution |
| out_wh_ratio = out_w / out_h |
| |
| n_rows = np.arange(n_cameras,dtype=np.int64) + 1 |
| n_cols = np.ceil(n_cameras / n_rows).astype(np.int64) |
| cat_wh_ratio = in_wh_ratio * (n_cols / n_rows) |
| ratio_diff = np.abs(out_wh_ratio - cat_wh_ratio) |
| best_idx = np.argmin(ratio_diff) |
| best_n_row = n_rows[best_idx] |
| best_n_col = n_cols[best_idx] |
| best_cat_wh_ratio = cat_wh_ratio[best_idx] |
|
|
| rw, rh = None, None |
| if best_cat_wh_ratio >= out_wh_ratio: |
| |
| rw = math.floor(out_w / best_n_col) |
| rh = math.floor(rw / in_wh_ratio) |
| else: |
| rh = math.floor(out_h / best_n_row) |
| rw = math.floor(rh * in_wh_ratio) |
| |
| |
| return rw, rh, best_n_col, best_n_row |
|
|