203 lines
7.1 KiB
Python
203 lines
7.1 KiB
Python
|
#!/usr/bin/env python
|
|||
|
# -*- coding: utf-8 -*-
|
|||
|
"""
|
|||
|
@project:
|
|||
|
@File : 从合成里边提取剩余屋顶并计算潜力
|
|||
|
@Author : qiqq
|
|||
|
@create_time : 2023/11/6 15:29
|
|||
|
"""
|
|||
|
import os
|
|||
|
from tqdm import tqdm
|
|||
|
from collections import namedtuple
|
|||
|
from PIL import Image
|
|||
|
import numpy as np
|
|||
|
import cv2
|
|||
|
import random
|
|||
|
|
|||
|
|
|||
|
|
|||
|
def generate_random_colors(n):
|
|||
|
Cls = namedtuple('cls', ['name', 'id', 'color'])
|
|||
|
colors = [
|
|||
|
Cls('backgroud', 0, (0, 0, 0))
|
|||
|
]
|
|||
|
while len(colors) < n:
|
|||
|
# 随机生成一个元组,元组中每个值在 0-255 之间
|
|||
|
color = Cls("roof"+str(len(colors)),len(colors),tuple(random.randint(0, 255) for _ in range(3)))
|
|||
|
colors.append(color)
|
|||
|
return list(colors)
|
|||
|
|
|||
|
|
|||
|
def get_putpalette(Clss, color_other=[0, 0, 0]):
|
|||
|
'''
|
|||
|
灰度图转8bit彩色图
|
|||
|
:param Clss:颜色映射表
|
|||
|
:param color_other:其余颜色设置
|
|||
|
:return:
|
|||
|
'''
|
|||
|
putpalette = []
|
|||
|
for cls in Clss:
|
|||
|
putpalette += list(cls.color)
|
|||
|
putpalette += color_other * (255 - len(Clss))
|
|||
|
return putpalette
|
|||
|
|
|||
|
|
|||
|
|
|||
|
##chatgpt的代码二值图像连通区域分析与标记算法
|
|||
|
def connected_component_analysis(binary_image):
|
|||
|
# 使用findContours函数查找连通区域
|
|||
|
contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) #最合适的一个
|
|||
|
|
|||
|
|
|||
|
# 对每个连通区域进行标记
|
|||
|
labeled_image = np.zeros_like(binary_image, dtype=np.uint16)
|
|||
|
for i, contour in enumerate(contours):
|
|||
|
cv2.drawContours(labeled_image, [contour], -1, i + 1, -1)
|
|||
|
|
|||
|
# 统计连通区域数量
|
|||
|
num_labels = len(contours)
|
|||
|
|
|||
|
return labeled_image, num_labels
|
|||
|
###############################################
|
|||
|
|
|||
|
#1.从合成的多目标图中里边单独提取剩余屋顶形成二值图并保存
|
|||
|
def extract_remainroof():
|
|||
|
savename="remainroof"
|
|||
|
savepath_root=""
|
|||
|
path1=r""#多目标结果图的路径
|
|||
|
savepath=os.path.join(savepath_root,savename)
|
|||
|
|
|||
|
if not os.path.exists(savepath):
|
|||
|
os.makedirs(savepath)
|
|||
|
|
|||
|
imgss=[i for i in os.listdir(path1) if i.endswith("png")]
|
|||
|
for i in tqdm(imgss):
|
|||
|
im=os.path.join(path1,i)
|
|||
|
imm=np.array(Image.open(im))
|
|||
|
imm=(imm==1) * 1 #剩余屋顶在多目标结果图中的索引是1
|
|||
|
result = np.uint8(imm)
|
|||
|
|
|||
|
#可视化保存
|
|||
|
palette = [0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255]
|
|||
|
result = Image.fromarray(result).convert('P') #
|
|||
|
result.putpalette(palette)
|
|||
|
result.save(os.path.join(savepath, i))
|
|||
|
|
|||
|
|
|||
|
#对1提取的剩余屋顶进行实例化
|
|||
|
def remainroof_instanced():
|
|||
|
pathh = r"" #剩余屋顶保存的文件夹
|
|||
|
savepath_root=""
|
|||
|
savename = "r"
|
|||
|
savepath = os.path.join(savepath_root, savename)
|
|||
|
if not os.path.exists(savepath):
|
|||
|
os.makedirs(savepath)
|
|||
|
for i in tqdm(os.listdir(pathh)):
|
|||
|
imgp = os.path.join(pathh, i)
|
|||
|
binary_image = np.array(Image.open(imgp))
|
|||
|
labeled_image, num_labels = connected_component_analysis(binary_image)
|
|||
|
#实例化后只对那些图中小于256个实例的图像进行可视化保存,大于256的可视化不了
|
|||
|
if num_labels<256:
|
|||
|
palette = generate_random_colors(num_labels)
|
|||
|
result = np.uint8(labeled_image)
|
|||
|
result = Image.fromarray(result).convert('P')
|
|||
|
# 原来的
|
|||
|
l = get_putpalette(palette)
|
|||
|
result.putpalette(l)
|
|||
|
result.save(os.path.join(savepath,i))
|
|||
|
|
|||
|
else:
|
|||
|
result = np.uint8(labeled_image)
|
|||
|
result = Image.fromarray(result).convert('P')
|
|||
|
result.save(os.path.join(savepath, i))
|
|||
|
|
|||
|
|
|||
|
|
|||
|
'''
|
|||
|
3.
|
|||
|
取交集
|
|||
|
2步骤的实例化步骤存在缺陷比如 一个圆环,实例化之后会将这个圆环填补成完整的原 导致实例化后的屋顶偏大
|
|||
|
用没实例化之前的 * 实例化后的
|
|||
|
'''
|
|||
|
|
|||
|
def yu():
|
|||
|
path1=r""#没实例化之前的 #也就是过程1的结果
|
|||
|
path2=r""#实例化之后的 #也就是过程2的结果
|
|||
|
savepath_root=""
|
|||
|
savename = ""
|
|||
|
savepath = os.path.join(savepath_root, savename)
|
|||
|
|
|||
|
if not os.path.exists(savepath):
|
|||
|
os.makedirs(savepath)
|
|||
|
|
|||
|
for i in tqdm(os.listdir(path1)):
|
|||
|
img1 = os.path.join(path1, i)
|
|||
|
img2 = os.path.join(path2, i)
|
|||
|
binary_image = np.array(Image.open(img1))
|
|||
|
instanceimage = np.array(Image.open(img2))
|
|||
|
result=binary_image*instanceimage
|
|||
|
num_labels=np.unique(result)
|
|||
|
t=len(num_labels)
|
|||
|
if t< 256:
|
|||
|
palette = generate_random_colors(t)
|
|||
|
result = np.uint8(result)
|
|||
|
result = Image.fromarray(result).convert('P')
|
|||
|
# 原来的
|
|||
|
l = get_putpalette(palette)
|
|||
|
result.putpalette(l)
|
|||
|
result.save(os.path.join(savepath, i))
|
|||
|
# print("1ok")
|
|||
|
else:
|
|||
|
result = np.uint8(result)
|
|||
|
result = Image.fromarray(result).convert('P')
|
|||
|
result.save(os.path.join(savepath, i))
|
|||
|
# print("2ok")
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#4.计算潜力
|
|||
|
def potentialmain():
|
|||
|
pathh = r""#过程3的结果
|
|||
|
gsd=0.26*0.26 #每个像素实际所占的面积
|
|||
|
singlepvare = 1.28 #每块光伏板的面积
|
|||
|
th=296 #阈值,小于这个阈值的屋顶就不计算他的潜力了 296是像素。
|
|||
|
total_pv=0
|
|||
|
total_roof=0
|
|||
|
avalibale=1
|
|||
|
for index,i in enumerate(os.listdir(pathh)):
|
|||
|
imgp = os.path.join(pathh, i)
|
|||
|
_image = np.array(Image.open(imgp))
|
|||
|
liss=np.unique(_image)
|
|||
|
labeled_image=_image
|
|||
|
image_deployedpv=0
|
|||
|
image_roof=0
|
|||
|
|
|||
|
for n in liss:
|
|||
|
nnumbelr = np.sum(labeled_image == n)
|
|||
|
if nnumbelr <th:
|
|||
|
labeled_image[labeled_image==n]=0 ##!!
|
|||
|
newnum_labels = np.unique(labeled_image)
|
|||
|
for k in newnum_labels[1:]: # 注意0是背景
|
|||
|
current_instance_roofpiex = np.sum(labeled_image == k) # 统计当前实例的像素个数
|
|||
|
current_instance_roofare = current_instance_roofpiex * gsd * avalibale ##计算当前实例的面积
|
|||
|
current_instance_deployedpv = current_instance_roofare // singlepvare # 当前实例的可部署的光伏组件的数量
|
|||
|
print(f"当前图{index+1}的处理后的实例{k}的像素为{current_instance_roofpiex},面积为{current_instance_roofare},可安装的光伏组件块数为{current_instance_deployedpv}")
|
|||
|
# pertotal_pv = pertotal_pv + deployedpv
|
|||
|
# pertotal_roof = pertotal_roof + roofare
|
|||
|
image_deployedpv += current_instance_deployedpv
|
|||
|
image_roof += current_instance_roofare
|
|||
|
total_pv += image_deployedpv # 总计可以部署的光伏组件数量
|
|||
|
total_roof += image_roof
|
|||
|
print(f"当前图{i}的,可安装的光伏组件块数为{image_deployedpv}")
|
|||
|
print("++++++++++++++++++++++++++")
|
|||
|
print("总计的图像可安装的光伏面板的块数为:", total_pv)
|
|||
|
print("总计可用的屋顶的面积为:", total_roof)
|
|||
|
|
|||
|
print("200ww总计光伏组件容量:", total_pv * 200)
|
|||
|
return total_pv
|
|||
|
|
|||
|
|
|||
|
potentialmain()
|
|||
|
|
|||
|
|