mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-11-04 14:39:42 +08:00
Crop and rotate image in one operation
This commit is contained in:
parent
9620d50ccb
commit
1b961ae477
@ -204,51 +204,83 @@ class EyeProcessor:
|
|||||||
def capture_crop_rotate_image(self):
|
def capture_crop_rotate_image(self):
|
||||||
# Get our current frame
|
# Get our current frame
|
||||||
|
|
||||||
try:
|
|
||||||
# Get frame from capture source, crop to ROI
|
|
||||||
self.current_image = self.current_image[
|
|
||||||
int(self.config.roi_window_y) : int(
|
|
||||||
self.config.roi_window_y + self.config.roi_window_h
|
|
||||||
),
|
|
||||||
int(self.config.roi_window_x) : int(
|
|
||||||
self.config.roi_window_x + self.config.roi_window_w
|
|
||||||
),
|
|
||||||
]
|
|
||||||
self.ibo.change_roi(self.config.dict(include=self.roi_include_set))
|
self.ibo.change_roi(self.config.dict(include=self.roi_include_set))
|
||||||
|
|
||||||
except:
|
roi_x = self.config.roi_window_x
|
||||||
# Failure to process frame, reuse previous frame.
|
roi_y = self.config.roi_window_y
|
||||||
self.current_image = self.previous_image
|
roi_w = self.config.roi_window_w
|
||||||
print("\033[91m[ERROR] Frame capture issue detected.\033[0m")
|
roi_h = self.config.roi_window_h
|
||||||
|
|
||||||
|
img_w, img_h, _ = self.current_image.shape
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Apply rotation to cropped area. For any rotation area outside of the bounds of the image,
|
# Apply rotation to cropped area. For any rotation area outside of the bounds of the image,
|
||||||
# fill with white.
|
# fill with white (self.current_image_white) and average in-bounds color (self.current_image).
|
||||||
try:
|
|
||||||
rows, cols, _ = self.current_image.shape
|
crop_matrix = np.float32([[1, 0, -roi_x],
|
||||||
except:
|
[0, 1, -roi_y],
|
||||||
rows, cols, _ = self.previous_image.shape
|
[0, 0, 1]])
|
||||||
img_center = (cols / 2, rows / 2)
|
img_center = (roi_w / 2, roi_h / 2)
|
||||||
rotation_matrix = cv2.getRotationMatrix2D(
|
rotation_matrix = cv2.getRotationMatrix2D(
|
||||||
img_center, self.config.rotation_angle, 1
|
img_center, self.config.rotation_angle, 1
|
||||||
)
|
)
|
||||||
avg_color_per_row = np.average(self.current_image, axis=0)
|
matrix = np.matmul(rotation_matrix, crop_matrix)
|
||||||
avg_color = np.average(avg_color_per_row, axis=0)
|
|
||||||
ar, ag, ab = avg_color
|
|
||||||
self.current_image = cv2.warpAffine(
|
|
||||||
self.current_image,
|
|
||||||
rotation_matrix,
|
|
||||||
(cols, rows),
|
|
||||||
borderMode=cv2.BORDER_CONSTANT,
|
|
||||||
borderValue=(ar + 10, ag + 10, ab + 10), # (255, 255, 255),
|
|
||||||
)
|
|
||||||
self.current_image_white = cv2.warpAffine(
|
self.current_image_white = cv2.warpAffine(
|
||||||
self.current_image,
|
self.current_image,
|
||||||
rotation_matrix,
|
matrix,
|
||||||
(cols, rows),
|
(roi_w, roi_h),
|
||||||
borderMode=cv2.BORDER_CONSTANT,
|
borderMode=cv2.BORDER_CONSTANT,
|
||||||
borderValue=(255, 255, 255),
|
borderValue=(255, 255, 255),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# calculate position of all four corners of crop, and check if any are out of bounds
|
||||||
|
|
||||||
|
# add w-preserve row to make matrix square, invert, and remove again
|
||||||
|
inv_matrix = np.linalg.inv(np.vstack((matrix, [0, 0, 1])))[:-1]
|
||||||
|
# calculate crop corner locations in original image space
|
||||||
|
corners = np.matmul([[0, 0, 1],
|
||||||
|
[roi_w, 0, 1],
|
||||||
|
[0, roi_h, 1],
|
||||||
|
[roi_w, roi_h, 1]],
|
||||||
|
np.transpose(inv_matrix))
|
||||||
|
fits_in_bounds = all(0 <= x <= img_w and 0 <= y <= img_h
|
||||||
|
for (x, y) in corners)
|
||||||
|
|
||||||
|
if fits_in_bounds:
|
||||||
|
# crop is entirely within original image bounds so average color and white are identical
|
||||||
|
self.current_image = self.current_image_white
|
||||||
|
return True
|
||||||
|
|
||||||
|
# image does not fit in bounds, so warp, calculate average color of covered pixels, and apply that to the outside region.
|
||||||
|
|
||||||
|
# warp image with alpha
|
||||||
|
alpha = np.full(self.current_image.shape[:2], 255, dtype=np.uint8)
|
||||||
|
self.current_image = np.dstack((self.current_image, alpha))
|
||||||
|
|
||||||
|
self.current_image = cv2.warpAffine(
|
||||||
|
self.current_image,
|
||||||
|
matrix,
|
||||||
|
(roi_w, roi_h),
|
||||||
|
borderMode=cv2.BORDER_CONSTANT,
|
||||||
|
borderValue=(0, 0, 0, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
# calculate average color of crop, excluding alpha
|
||||||
|
avg_color_per_row = np.average(self.current_image, axis=0)
|
||||||
|
avg_color = np.average(avg_color_per_row, axis=0)
|
||||||
|
avg_color_norm = avg_color[0:3] / avg_color[3]
|
||||||
|
ar, ag, ab = np.clip(avg_color_norm, 0, 1)
|
||||||
|
|
||||||
|
# add border color to image masked by alpha and discard alpha channel
|
||||||
|
rgb_ch = self.current_image[:, :, :3]
|
||||||
|
inv_alpha_ch = 255 - self.current_image[:, :, 3]
|
||||||
|
self.current_image = rgb_ch + np.stack(
|
||||||
|
np.uint8([inv_alpha_ch * ar,
|
||||||
|
inv_alpha_ch * ag,
|
||||||
|
inv_alpha_ch * ab]),
|
||||||
|
axis=-1)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user