如何在列表中子列出图像的相同值像素(四像素连接)
How to sublist in a list the same value pixels of an image (Four Pixel Connectivity)
我希望在 python 中输出列表列表,其中每个列表包含单一颜色的每个形状的像素坐标。
即看这张图片:
a 128x128 png
我已将其转换为 RGB 值的二维网格。
我想创建一个列表列表,每个列表都包含紫色“形状”(正方形、矩形等)的像素坐标。 “形状”的标准是至少两个相同颜色的像素彼此相邻(仅上、下、左、右)。
我的尝试:
# returns a list of instances of a tile which are all adjacent to each other
# i.e. finds a window's individual tiles and returns them as a list
def coagulateTiles(self, tileType, startX, startY, existingComponents = [], foundTiles = None):
# if the pixel is not the right tile OR if it has already been part of another search
if not self.getTileType(startX, startY) == tileType or not (startX, startY) in foundTiles:
return existingComponents
else:
existingComponents.append((startX, startY))
# a dictionary of the adjacent tiles {"north" = (x, y), etc...}
adjacentCoordDict = self.getAdjacentCoords(startX, startY)
for adjacent in adjacentCoordDict:
if adjacent == tileType:
x, y = adjacentCoordDict[adjacent][0], adjacentCoordDict[adjacent][1]
existingComponents.append(self.coagulateTiles(tileType, x, y, existingComponents))
return existingComponents
def tileSearch(self, tile):
items = []
foundTiles = []
for x in range(self.getSizeX()):
for y in range(self.getSizeY()):
if self.getTileType(x, y) == tile:
if tile in self.getAdjacentTiles(x, y).values():
foundTiles.append((x, y))
listOfTileComponents = self.coagulateTiles(tile, x, y, foundTiles = foundTiles)
items.append(listOfTileComponents)
return items
我最终找到了所有这些像素,但输出的列表将所有像素放在一个列表中,而不是将“形状”分成单独的子列表。
它 returns 类似于 [[(1, 1), (2, 1), (3, 1), (1, 2), (1, 3)]]
而不是 [[(1, 1), (2, 1)], [(3, 1), (1, 2), (1, 3)]]
我的直觉是,在我的尝试中当然存在一个简单的逻辑错误,但我似乎无法找到我可以指定子列表创建的位置以使其工作。
有什么想法吗?
这是将上面的图像转换为我正在使用的网格所需的代码:
import numpy as np
from PIL import Image
# (x=0,y=0) of the grid is in the top left corner
class Grid():
def __init__(self, sizeX, sizeY):
self.sizeX = sizeX
self.sizeY = sizeY
global rgbMap
rgbMap = {
"wall":( 0, 0, 0),
"background": (255,255,255),
"closet": (192,192,224),
"bathroom": (192,255,255), # /washroom
"dining room": (224,255,192), # livingroom/kitchen/dining room
"bedroom": (255,224,128),
"hall": (255,160, 96),
"balcony": (255,224,224),
"opening": (255, 60,128) # door & window
}
global tileMap
tileMap = {v: k for k, v in rgbMap.items()}
# create a 2d numpy array of the given size
self.grid = self.createGrid(sizeX, sizeY)
def createGrid(self, sizeX, sizeY):
return np.empty((sizeX, sizeY), dtype=tuple)
# function to input a colour into the 2d grid
def populate(self, locationX, locationY, rgbTuple):
self.grid[locationX,locationY] = rgbTuple
def get(self):
return self.grid
def getSizeX(self):
return self.sizeX
def getSizeY(self):
return self.sizeY
class MapGenerator:
def __init__(self, finalSize = 128):
# resize the image to be axa size where a = 128
self.workingGridSize = 512
self.finalSize = finalSize
def createFromSaveFile(self):
self.createGrid(fromMemory=True)
print("populating the grid with data")
self.populateGrid(self.finalSize, self.grid, self.floorplan)
self.floorplan.close()
def createGrid(self, fromMemory = False):
if fromMemory == True:
self.floorplan = Image.open('saved.png')
self.grid = Grid(self.finalSize, self.finalSize)
else:
self.floorplan = Image.open('result.png')
self.grid = Grid(self.workingGridSize, self.workingGridSize)
def populateGrid(self, gridsize, givenGrid, image):
for x in range(0, gridsize):
for y in range(0, gridsize):
# print(map.getpixel((x,y)))
givenGrid.populate(x, y, image.getpixel((x,y)))
if __name__ == "__main__":
newMap = MapGenerator()
# newMap.create()
newMap.createFromSaveFile()
openings = newMap.grid.tileSearch("opening")
print(openings)
我想出了一个可行的 DFS 递归解决方案:
def tileSearch(self, tile):
"""returns a 2d list containing all the pixels
of each shape of a searched tile type as a sublist
a shape is defined as at least two pixels
of the same colour touching each other with Four-Pixel Connectivity
(up, down, left, right)
Args:
tile (string): the tile to search as a string (see rgbMap dict for tile list)
Returns:
list: a 2D list containing each shape as a sublist of its pixels
"""
searchGrid = copy.deepcopy(self)
resultList = list()
for x in range(searchGrid.getSizeX()):
for y in range(searchGrid.getSizeY()):
if searchGrid.getTileType(x, y) == tile:
adjacentTiles = list(searchGrid.getAdjacentTiles(x, y).values())
if tile in adjacentTiles:
shapeList = list()
searchGrid.coagulateShape(tile, x, y, shapeList)
resultList.append(shapeList)
return resultList
# returns a list of instances of a tile which are all adjacent to each other
# i.e. finds a window's individual tiles and returns them as a list
def coagulateShape(self, tile, x, y, shapeList = []):
""" Performs a recursive Depth First Search
returns a list of coordinates of a tile which are all adjacent to each other
through Four Pixel connectivity (up, down, left, right)
i.e. finds a shape's individual tiles and returns them as a list
Args:
tile (string): the tile to search for (see rgbMap dict for tile list)
x (int): the x coordinate of the starting pixel
y (int): the y coordinate of the starting pixel
shapeList (list): the list that the shape's coordinates will be appended to recursively
"""
# base case
if not self.getTileType(x, y) == tile:
return
# recursive case
self.populate(x, y, (0, 0, 0, 0))
shapeList.append((x, y))
adjacentPixels = list(self.getAdjacentCoords(x, y).values())
for pixel in adjacentPixels:
self.coagulateShape(tile, pixel[0], pixel[1], shapeList)
我希望在 python 中输出列表列表,其中每个列表包含单一颜色的每个形状的像素坐标。
即看这张图片: a 128x128 png
我已将其转换为 RGB 值的二维网格。
我想创建一个列表列表,每个列表都包含紫色“形状”(正方形、矩形等)的像素坐标。 “形状”的标准是至少两个相同颜色的像素彼此相邻(仅上、下、左、右)。
我的尝试:
# returns a list of instances of a tile which are all adjacent to each other
# i.e. finds a window's individual tiles and returns them as a list
def coagulateTiles(self, tileType, startX, startY, existingComponents = [], foundTiles = None):
# if the pixel is not the right tile OR if it has already been part of another search
if not self.getTileType(startX, startY) == tileType or not (startX, startY) in foundTiles:
return existingComponents
else:
existingComponents.append((startX, startY))
# a dictionary of the adjacent tiles {"north" = (x, y), etc...}
adjacentCoordDict = self.getAdjacentCoords(startX, startY)
for adjacent in adjacentCoordDict:
if adjacent == tileType:
x, y = adjacentCoordDict[adjacent][0], adjacentCoordDict[adjacent][1]
existingComponents.append(self.coagulateTiles(tileType, x, y, existingComponents))
return existingComponents
def tileSearch(self, tile):
items = []
foundTiles = []
for x in range(self.getSizeX()):
for y in range(self.getSizeY()):
if self.getTileType(x, y) == tile:
if tile in self.getAdjacentTiles(x, y).values():
foundTiles.append((x, y))
listOfTileComponents = self.coagulateTiles(tile, x, y, foundTiles = foundTiles)
items.append(listOfTileComponents)
return items
我最终找到了所有这些像素,但输出的列表将所有像素放在一个列表中,而不是将“形状”分成单独的子列表。
它 returns 类似于 [[(1, 1), (2, 1), (3, 1), (1, 2), (1, 3)]]
而不是 [[(1, 1), (2, 1)], [(3, 1), (1, 2), (1, 3)]]
我的直觉是,在我的尝试中当然存在一个简单的逻辑错误,但我似乎无法找到我可以指定子列表创建的位置以使其工作。
有什么想法吗?
这是将上面的图像转换为我正在使用的网格所需的代码:
import numpy as np
from PIL import Image
# (x=0,y=0) of the grid is in the top left corner
class Grid():
def __init__(self, sizeX, sizeY):
self.sizeX = sizeX
self.sizeY = sizeY
global rgbMap
rgbMap = {
"wall":( 0, 0, 0),
"background": (255,255,255),
"closet": (192,192,224),
"bathroom": (192,255,255), # /washroom
"dining room": (224,255,192), # livingroom/kitchen/dining room
"bedroom": (255,224,128),
"hall": (255,160, 96),
"balcony": (255,224,224),
"opening": (255, 60,128) # door & window
}
global tileMap
tileMap = {v: k for k, v in rgbMap.items()}
# create a 2d numpy array of the given size
self.grid = self.createGrid(sizeX, sizeY)
def createGrid(self, sizeX, sizeY):
return np.empty((sizeX, sizeY), dtype=tuple)
# function to input a colour into the 2d grid
def populate(self, locationX, locationY, rgbTuple):
self.grid[locationX,locationY] = rgbTuple
def get(self):
return self.grid
def getSizeX(self):
return self.sizeX
def getSizeY(self):
return self.sizeY
class MapGenerator:
def __init__(self, finalSize = 128):
# resize the image to be axa size where a = 128
self.workingGridSize = 512
self.finalSize = finalSize
def createFromSaveFile(self):
self.createGrid(fromMemory=True)
print("populating the grid with data")
self.populateGrid(self.finalSize, self.grid, self.floorplan)
self.floorplan.close()
def createGrid(self, fromMemory = False):
if fromMemory == True:
self.floorplan = Image.open('saved.png')
self.grid = Grid(self.finalSize, self.finalSize)
else:
self.floorplan = Image.open('result.png')
self.grid = Grid(self.workingGridSize, self.workingGridSize)
def populateGrid(self, gridsize, givenGrid, image):
for x in range(0, gridsize):
for y in range(0, gridsize):
# print(map.getpixel((x,y)))
givenGrid.populate(x, y, image.getpixel((x,y)))
if __name__ == "__main__":
newMap = MapGenerator()
# newMap.create()
newMap.createFromSaveFile()
openings = newMap.grid.tileSearch("opening")
print(openings)
我想出了一个可行的 DFS 递归解决方案:
def tileSearch(self, tile):
"""returns a 2d list containing all the pixels
of each shape of a searched tile type as a sublist
a shape is defined as at least two pixels
of the same colour touching each other with Four-Pixel Connectivity
(up, down, left, right)
Args:
tile (string): the tile to search as a string (see rgbMap dict for tile list)
Returns:
list: a 2D list containing each shape as a sublist of its pixels
"""
searchGrid = copy.deepcopy(self)
resultList = list()
for x in range(searchGrid.getSizeX()):
for y in range(searchGrid.getSizeY()):
if searchGrid.getTileType(x, y) == tile:
adjacentTiles = list(searchGrid.getAdjacentTiles(x, y).values())
if tile in adjacentTiles:
shapeList = list()
searchGrid.coagulateShape(tile, x, y, shapeList)
resultList.append(shapeList)
return resultList
# returns a list of instances of a tile which are all adjacent to each other
# i.e. finds a window's individual tiles and returns them as a list
def coagulateShape(self, tile, x, y, shapeList = []):
""" Performs a recursive Depth First Search
returns a list of coordinates of a tile which are all adjacent to each other
through Four Pixel connectivity (up, down, left, right)
i.e. finds a shape's individual tiles and returns them as a list
Args:
tile (string): the tile to search for (see rgbMap dict for tile list)
x (int): the x coordinate of the starting pixel
y (int): the y coordinate of the starting pixel
shapeList (list): the list that the shape's coordinates will be appended to recursively
"""
# base case
if not self.getTileType(x, y) == tile:
return
# recursive case
self.populate(x, y, (0, 0, 0, 0))
shapeList.append((x, y))
adjacentPixels = list(self.getAdjacentCoords(x, y).values())
for pixel in adjacentPixels:
self.coagulateShape(tile, pixel[0], pixel[1], shapeList)