You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python将2D俯视楼层平面图转换为正立面视图的实现问题

提问内容

我需要为2D楼层平面图的外墙映射立面效果,但目前无法基于2D俯视平面图生成对应正视图。
我已尝试使用opencv分割所需区域,虽然可以轻松识别门和窗,但始终找不到分割生成正视图的方法。
左侧为待处理的楼层平面图,右侧为预期效果:高亮显示的平面图正视图,门和窗已标记颜色。
提前感谢各位的帮助。


补充内容

我参考评论区的建议更新了代码:从上到下逐行垂直遍历,识别每行最右侧的黑色或黄色像素,随后反转列表得到从左(底部)到右(顶部)的序列,遍历该序列构建二维数组,其中墙体高度设为255像素,门的高度设为204像素。
但运行后得到的结果不符合预期。
代码如下:

from PIL import Image
import inspect

floorplan_path = 'data/floorplan.png'

class Wall(object):

  colorIdentifier = (79,79,79)

  def __init__(self, x,y):
    self.position = (x,y)
    self.color = (79,79,79)
    self.height = 255
    self.drawColor = (65,105,225)

class Door(object):

  colorIdentifier = (255,255,25)

  def __init__(self, x,y):
    self.position = (x,y)
    self.color = (255,255,25)
    self.height = 204
    self.drawColor = (255, 255, 25)

# 尚未实现
class Window:
  position = None
  color = None # 暂时不确定如何识别
  drawColor = None # 浅蓝色
  height = 204

def main():
  image = Image.open(floorplan_path)
  pixels = list(image.getdata())
  image = image.convert('RGB')
  width, height = image.size

  rowItems = []

  for y in range(0, height):

    blacks = []

    for x in range(0, width):
      pixel = image.getpixel((x,y))
      color = pixel

      if(color == Wall.colorIdentifier):
        blacks.append(Wall(x, y))
      elif (color == Door.colorIdentifier):
        blacks.append(Door(x, y))
    # 取每行最后一个元素,因为我们要生成正视图的是右侧墙面
    if blacks != []:
      rowItems.append(blacks[-1])
  
  # 移除无值的行
  y = [x for x in rowItems if x != []] 

  # 反转列表让墙面从左到右(对应原平面图从上到下)排列
  leftToRight = list(reversed(y))

  # 二维数组存储正视图的行列像素,包含对应颜色和高度信息
  imageArray = []

  for item in leftToRight:

    if isinstance(item, Wall):
      column = [item.drawColor] * item.height
      imageArray.append(column)
    elif isinstance(item, Door):
      column = [item.drawColor] * item.height
      column.append(Wall.drawColor) * (255-item.height)
      imageArray.append(column)  

  img = Image.new('RGB', (255, 255))

  for i in range(len(imageArray)):
    for j in range(len(imageArray[i])):
      img.putpixel((i, j), (imageArray[i][j]))

  img.save('output.png')

if __name__ == '__main__':
  main()

使用左侧的楼层平面图运行代码后,输出结果不符合预期。


回答

问题排查与修正方案

现有代码存在4处核心问题,修正后即可得到符合预期的结果:

  1. 语法错误:门区域补全墙体的代码写法错误,column.append(Wall.drawColor) * (255-item.height) 逻辑无效,append方法返回None,无法进行乘法运算,应改为列表拼接写法
  2. 坐标映射错误:PIL的像素坐标系Y轴从上到下递增,当前直接将列数组的索引作为Y坐标赋值,会导致门出现在立面图顶部,和预期的门在底部的效果相反,需要调整列数组的像素顺序
  3. 输出尺寸固定问题:输出图像宽度写死为255,若原平面图的高度(即立面图的总宽度)不等于255,会出现内容截断或大面积留白,需要动态匹配输出尺寸
  4. 冗余代码:第一次遍历已经过滤了无有效像素的行,后续的空行过滤步骤无作用可删除

修正后代码

from PIL import Image

floorplan_path = 'data/floorplan.png'

class Wall(object):
    colorIdentifier = (79,79,79)
    def __init__(self, x,y):
        self.position = (x,y)
        self.color = (79,79,79)
        self.height = 255
        self.drawColor = (65,105,225)

class Door(object):
    colorIdentifier = (255,255,25)
    def __init__(self, x,y):
        self.position = (x,y)
        self.color = (255,255,25)
        self.height = 204
        self.drawColor = (255, 255, 25)

# 尚未实现
class Window:
    position = None
    color = None # 暂时不确定如何识别
    drawColor = None # 浅蓝色
    height = 204

def main():
    image = Image.open(floorplan_path).convert('RGB')
    width, height = image.size
    rowItems = []

    for y in range(0, height):
        blacks = []
        for x in range(0, width):
            color = image.getpixel((x,y))
            if color == Wall.colorIdentifier:
                blacks.append(Wall(x, y))
            elif color == Door.colorIdentifier:
                blacks.append(Door(x, y))
        if blacks:
            rowItems.append(blacks[-1])
  
    # 反转列表对应立面图从左到右的顺序
    leftToRight = list(reversed(rowItems))
    # 动态设置输出尺寸:宽度为立面图总列数,高度为255像素
    output_width = len(leftToRight)
    img = Image.new('RGB', (output_width, 255))

    for col_idx, item in enumerate(leftToRight):
        if isinstance(item, Wall):
            column = [item.drawColor] * 255
        elif isinstance(item, Door):
            # 门在下方,上方为墙体,匹配PIL坐标从上到下的规则
            column = [Wall.drawColor] * (255 - item.height) + [item.drawColor] * item.height
        # 逐像素写入
        for row_idx, pixel_color in enumerate(column):
            img.putpixel((col_idx, row_idx), pixel_color)

    img.save('output.png')

if __name__ == '__main__':
    main()

优化建议

如果需要适配带转角的外墙,可先做轮廓提取获取外墙的矢量路径,再沿路径方向采样像素生成多段立面图拼接即可。


内容的提问来源于stack exchange,提问作者Luca Jeevanjee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 02:24:04