Piet_interpreter/interpreter/imageWrapper.py
2020-04-29 13:42:12 +02:00

127 lines
4.5 KiB
Python

from typing import Tuple, Union, Set, List
from PIL import Image
import numpy as np
import interpreter.movement as movement
import interpreter.colors as colors
def boundsChecker(image: np.ndarray, position: Tuple[int, int]) -> bool:
# Position 0 = x-axis, while matrix[0] = y-axis. This is why we compare position[0] with matrix[1]
return 0 <= position[0] < image.shape[1] and \
0 <= position[1] < image.shape[0]
def getPixel(image: np.ndarray, position: Tuple[int, int]) -> Union[np.ndarray, bool]:
"""
This function the pixel at a specific location
:param image: np.ndarray of image
:param position: wanted position
:return: either a cell or False, if the cell is not inside the image
"""
if boundsChecker(image, position):
return image[position[1]][position[0]]
else:
return False
def getImage(fileName: str) -> np.ndarray:
"""
Returns an np.ndarray of the image found at the given file location
:param fileName: Complete filename (including extension)
:return: np.ndarray of the image
"""
image = Image.open(fileName)
if fileName.split('.')[-1] == "gif":
image = image.convert("RGB")
return np.array(image)
def getCodel(image: np.ndarray, position: Tuple[int, int], foundPixels: Set[Tuple[int, int]] = None) -> Set[Tuple[int, int]]:
"""
This function finds all adjacent pixels with the same color as the pixel on the given position
If you pass a white pixel, this will return a set with only the white pixel in it.
:param image: The image with all pixel values
:param position: Starting position
:param foundPixels: currently found pixels
:return: A Set with all positions of same-colored pixels (Also known as a codel)
"""
if foundPixels is None:
foundPixels = set()
# If this position is already in the set, it has already been traversed
if position in foundPixels:
return foundPixels
if colors.isWhite(getPixel(image, position)):
foundPixels.add(position)
return foundPixels
x = position[0]
y = position[1]
foundPixels.add(position)
# right
if boundsChecker(image, (x + 1, y)) and np.all(image[y][x + 1] == image[y][x]):
newPosition = (position[0] + 1, position[1])
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
# below
if boundsChecker(image, (x, y - 1)) and np.all(image[y - 1][x] == image[y][x]):
newPosition = (position[0], position[1] - 1)
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
# left
if boundsChecker(image, (x - 1, y)) and np.all(image[y][x - 1] == image[y][x]):
newPosition = (position[0] - 1, position[1])
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
# above
if boundsChecker(image, (x, y + 1)) and np.all(image[y + 1][x] == image[y][x]):
newPosition = (position[0], position[1] + 1)
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
return foundPixels
def getWhiteLine(image: np.ndarray, startPosition: Tuple[int, int], directionPointer: int, foundPixels: List[Tuple[int, int]] = None) -> List[Tuple[int, int]]:
"""
Finds all adjacent white pixels in the same direction
:param image: base image
:param startPosition: Starting position from which the white line starts
:param directionPointer: Direction in which the line goes
:param foundPixels: already found pixels
:return: A list of white pixels found
"""
# Can't give mutable values as default parameter
if foundPixels is None:
foundPixels = []
# If it is already found, skip
if startPosition in foundPixels:
return foundPixels
foundPixels.append(startPosition)
# Get the new position, and check if the colors match
newPos = movement.getNextPosition(startPosition, directionPointer)
if boundsChecker(image, newPos) and colors.isWhite(image[newPos[1]][newPos[0]]):
return getWhiteLine(image, newPos, directionPointer, foundPixels)
else:
return foundPixels
def getNewWhiteDirection(image: np.ndarray, startPosition: Tuple[int, int], directionPointer: int) -> int:
newPosition = movement.getNextPosition(startPosition, directionPointer)
if boundsChecker(image, newPosition) and (not colors.isBlack(getPixel(image, newPosition))):
return directionPointer
else:
return getNewWhiteDirection(image, startPosition, movement.flipDP(directionPointer))