Skip to content

Commit

Permalink
Fix methods in image_util.py
Browse files Browse the repository at this point in the history
  • Loading branch information
ecyoung3 committed May 29, 2024
1 parent 2b3ffd0 commit ab37348
Showing 1 changed file with 35 additions and 16 deletions.
51 changes: 35 additions & 16 deletions src/frheed/image_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@
ImageArray = npt.NDArray[np.generic]


def get_image_shape(image: ImageArray) -> tuple[int, int, int]:
"""Returns the height, width, and number of channels of an image.
Raises:
TypeError if the image has less than 2 dimensions or greater than 3 dimensions.
"""
match image.ndim:
case 2:
height, width = image.shape
channels = 1
case 3:
height, width, channels = image.shape
case _:
raise TypeError(f"Image with shape {image.shape} has unsupported number of dimensions")

return (height, width, channels)


def qimage_to_ndarray(image: QtGui.QImage) -> ImageArray:
"""Converts a QImage to a numpy array."""
if (image_bits := image.bits()) is None:
Expand All @@ -24,32 +42,32 @@ def qimage_to_ndarray(image: QtGui.QImage) -> ImageArray:

def get_rectangle_region(image: ImageArray, x1: int, y1: int, x2: int, y2: int) -> ImageArray:
"""Returns the region of an image bound by a rectangle."""
return np.copy(image[y1:y2, x1:x2])
# The region must have nonzero dimensions
h, w = image.shape[:2]
return np.copy(image[min(y1, h - 2) : max(y2, y1 + 1), min(x1, w - 2) : max(x2, x1 + 1)])


def get_ellipse_region(image: ImageArray, x1: int, y1: int, x2: int, y2: int) -> ImageArray:
"""Returns the region of an image bound by an ellipse."""
# Get the region within the ellipse bounding box
region = get_rectangle_region(image, x1, y1, x2, y2)

# Create an elliptical mask where 1 = pixel to include, 0 = pixel to exclude
height, width = region.shape[:2]
# Mask all pixels outside the ellipse
height, width, channels = get_image_shape(region)
center_x = width // 2
center_y = height // 2
mask = np.zeros((height, width), dtype=np.uint8)
mask = np.ones(region.shape, dtype=np.uint8)
cv2.ellipse(
mask,
center=(center_x, center_y),
axes=(center_x, center_y),
angle=0,
startAngle=0,
endAngle=360,
color=(1,),
color=[0] * channels,
thickness=-1, # negative thickness will draw a filled ellipse
)

# Set all pixels outside the elliptical mask to 0
return cv2.bitwise_and(region, region, mask=mask)
return np.ma.MaskedArray(region, mask=np.ma.make_mask(mask))


def get_line_region(
Expand All @@ -58,11 +76,12 @@ def get_line_region(
"""Returns the region of an image under a line."""
# Get the region within the line bounding box
region = get_rectangle_region(image, x1, y1, x2, y2)

# Create a mask by drawing the line
height, width = region.shape[:2]
mask = np.zeros((height, width), dtype=np.uint8)
cv2.line(region, pt1=(0, 0), pt2=(height, width), color=(1,), thickness=thickness)

# Set all pixels not under the line to 0
return cv2.bitwise_and(region, region, mask=mask)
if x1 == x2 or y1 == y2:
# Region is already a line and does not require masking
return region

# Mask all pixels not under the line
height, width, channels = get_image_shape(region)
mask = np.zeros(region.shape, dtype=np.uint8)
cv2.line(mask, pt1=(0, 0), pt2=(height, width), color=[0] * channels, thickness=thickness)
return np.ma.MaskedArray(region, mask=np.ma.make_mask(mask))

0 comments on commit ab37348

Please sign in to comment.