图像矢量化

python将图像目标区域转换为LineString、Polygon数据格式。

import os
import numpy as np
import cv2
from PIL import Image
import matplotlib.pyplot as plt
from tqdm import tqdm
import sknw
from skimage.morphology import skeletonize, medial_axis
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point, LineString, Polygon
from scipy.signal import savgol_filter
from rdp import rdp
from shapely.wkt import loads
from skimage.measure import find_contours
import scipy.signal as signal
from multiprocessing.dummy import Pool as ThreadPool
import time
from datetime import datetime
import sys
import  warnings
from coord_convert.transform import wgs2gcj, wgs2bd, gcj2wgs, gcj2bd, bd2wgs, bd2gcj
from pyproj import Transformer
import math
from shapely.geometry import Polygon,LineString
import shapely

# warnings.filterwarnings("ignore")

# 图像缩放:https://www.cnblogs.com/lfri/p/10596530.html
def douglas_peucker(l, epsilon=0.00007):
    """ 道格拉斯-普克算法
    """
    try:
        if (type(l) == LineString):
            in_lng_list, in_lat_list = l.xy[0], l.xy[1]
            ins = [[i, j] for i, j in zip(in_lng_list, in_lat_list)]
            outs = rdp(ins, epsilon)

            out_lng_list = [i[0] for i in outs]
            out_lat_list = [i[1] for i in outs]
            new_l = LineString([Point(x, y) for x, y in zip(out_lng_list, out_lat_list)])
            return new_l
        if (type(l) == Polygon):
            in_lng_list, in_lat_list = l.exterior.xy[0], l.exterior.xy[1]
            ins = [[i, j] for i, j in zip(in_lng_list, in_lat_list)]
            outs = rdp(ins, epsilon)

            out_lng_list = [i[0] for i in outs]
            out_lat_list = [i[1] for i in outs]
            #             print(len(out_lng_list))
            if (out_lng_list[0] != out_lng_list[-1] and out_lat_list[0] != out_lat_list[-1]):
                print('处理LinearRing问题。')
                out_lng_list.append(out_lng_list[0])
                out_lat_list.append(out_lat_list[0])
            print('------', out_lng_list, out_lat_list)
            new_l = Polygon([Point(x, y) for x, y in zip(out_lng_list, out_lat_list)])
            return new_l
    except:
        print('douglas_peucker error--->', str(l))

    return None


def sg_filter(l, m=5, n=2):
    """ sg滤波
    """
    # try:
    if (type(l) == LineString):
        x_list, y_list = l.xy[0], l.xy[1]
        if (len(x_list) < m):
            return l
        new_x_list = list(savgol_filter(np.array(x_list), m, n))
        new_y_list = list(savgol_filter(np.array(y_list), m, n))
        new_l = LineString([Point(x, y) for x, y in zip(new_x_list, new_y_list)])
        return new_l
    if (type(l) == Polygon):
        x_list, y_list = l.exterior.xy[0], l.exterior.xy[1]
        if (len(x_list) < m):
            return l
        new_x_list = list(savgol_filter(np.array(x_list), m, n))
        new_y_list = list(savgol_filter(np.array(y_list), m, n))
        new_l = Polygon(list(zip(new_x_list, new_y_list)))
        return new_l
    # except:
    # print(type(l) == Polygon)
    # print('sg_filter error--->', str(l))

    # return None


# === 函数定义 ===

# 时间戳格式转换
def trans_time(timeStamp):
    if (timeStamp == timeStamp):
        timeStamp = float(timeStamp)
        return datetime.fromtimestamp(int(timeStamp))
    else:
        return '-1'


# 计算时间戳秒差
def diff_seconds(timeStamp1, timeStamp2):
    return abs((trans_time(timeStamp1) - trans_time(timeStamp2)).total_seconds())


def b_image(mask):
    """ 二值化彩色图像。
    """
    gray = cv2.cvtColor(mask, cv2.COLOR_RGB2GRAY)
    ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)

    return binary


def add_black_edg(arr):
    """
    find_counters 边缘提取时无法封闭图像边界,需要加一层黑边。
    :param arr:
    :return:
    """
    arr[:, 0] = 0
    arr[:, -1] = 0
    arr[0, :] = 0
    arr[-1, :] = 0
    return arr


def split_gray_image(gray):
    """
    gray_level = [["CheDaoXianBaiShiXian",1],
                ["CheDaoXianBaiXuXian",2],
                ["CheDaoXianHuangShiXian",3],
                ["CheDaoXianHuangXuXian",4],
                ["RenXingHengDao",5],
                ["DaoLiuDai",6],
                ["JianTou",7],
                ["DaoLuMian",8]]
    """
    gray = (255 - gray) // 20
    CheDaoXianBaiShiXian = np.where(gray == 1, 1, 0)
    CheDaoXianBaiXuXian = np.where(gray == 2, 1, 0)
    CheDaoXianHuangShiXian = np.where(gray == 3, 1, 0)
    CheDaoXianHuangXuXian = np.where(gray == 4, 1, 0)
    DaoLuMian = add_black_edg(np.where(gray == 8, 1, 0))
    JianTou = np.where(gray == 7, 1, 0)
    RenXing = np.where(gray == 5, 1, 0)
    DaoLiuDai = np.where(gray == 6, 1, 0)
    Back = add_black_edg(np.where(gray == 0, 1, 0))

    LvHuaDai = add_black_edg(np.where(gray == 9, 1, 0))
    ZhaLan = add_black_edg(np.where(gray == 10, 1, 0))

    return CheDaoXianBaiShiXian, CheDaoXianBaiXuXian, CheDaoXianHuangShiXian, CheDaoXianHuangXuXian, JianTou, DaoLuMian, Back, RenXing, DaoLiuDai, LvHuaDai, ZhaLan


def extract_lane_by_sheet(seg_image, filename):
    #     print(filename)
    """ 提取图幅的线拓扑结构。
        input
            image_name 108689_108710-53301_53322.png
        output
            gdf_edges, gdf_nodes 线GeoDataFrame, 点GeoDataFrame

    """

    # 形态学处理
    # seg_image = cv2.medianBlur(seg_image, 3) # 中值滤波
    kernel = np.ones((3, 3), np.uint8)
    seg_image = cv2.dilate(np.uint8(seg_image), kernel, iterations=1)

    # 形态学处理后提取拓扑
    #     skeleton = skeletonize(cv2.cvtColor(seg_image, cv2.COLOR_BGR2GRAY)//255)
    skeleton = skeletonize(seg_image)
    graph = sknw.build_sknw(skeleton)

    # =============================================================================
    # 线,draw edges by pts
    # 包括LineString、少量Point,少量MultiLineString
    # =============================================================================

    gdf_edges_List = []
    # gdf_edges = gpd.GeoDataFrame()
    for (s, e) in graph.edges():
        ps = graph[s][e]['pts']
        edge_x, edge_y = ps[:, 1], ps[:, 0]
        if len(ps) > 1:  # trans to line
            lng_list = [x for x in edge_x]
            lat_list = [y for y in edge_y]
            lst = LineString([Point(x, y) for x, y in zip(lng_list, lat_list)])
            lst = sg_filter(lst)
            lst = douglas_peucker(lst, 5)  # 0.000005)
            gdf_edges_List.append(lst)

    gdf_edges = gpd.GeoDataFrame([], geometry=gdf_edges_List)
    gdf_edges['_id'] = [filename for i in range(len(gdf_edges))]

    if (len(gdf_edges) > 0):
        gdf_edges['length'] = [gdf_edges.iloc[i]['geometry'].length for i in range(len(gdf_edges))]

    return gdf_edges


def extract_arrow_by_sheet(seg_image, filename):
    """ 提取图幅的面拓扑结构。
        input
            image_name 108689_108710-53301_53322.png
        output
            gdf_polygons 面GeoDataFrame

    """

    # 形态学处理
    #     seg_image = cv2.medianBlur(seg_image, 3) # 中值滤波
    # seg_image = cv2.cvtColor(seg_image, cv2.COLOR_BGR2GRAY)
    # 形态学处理后提取拓扑
    contours = find_contours(seg_image, 0.8)
    # # Display the image and plot all contours found
    # fig, ax = plt.subplots()
    # ax.imshow(seg_image, cmap=plt.cm.gray)
    #
    # for n, contour in enumerate(contours):
    #     ax.plot(contour[:, 1], contour[:, 0], linewidth=2, color='red')
    #
    # ax.axis('image')
    # ax.set_xticks([])
    # ax.set_yticks([])
    # plt.show()

    # =============================================================================
    # 面,draw polygon
    # =============================================================================

    gdf_polygons_List = []
    # gdf_polygons = gpd.GeoDataFrame()
    for i in range(len(contours)):
        contour = contours[i]
        polygon_x, polygon_y = contour[:, 1], contour[:, 0]
        lng_list = [x for x in polygon_x]
        lat_list = [y for y in polygon_y]

        pol = Polygon(list(zip(lng_list, lat_list)))
        pol = sg_filter(pol)  # , 21, 3)
        gdf_polygons_List.append(pol)
    gdf_polygons = gpd.GeoDataFrame([], geometry=gdf_polygons_List)
    gdf_polygons['_id'] = [filename for i in range(len(gdf_polygons))]
    if (len(gdf_polygons) > 0):
        gdf_polygons['area'] = [gdf_polygons.iloc[i]['geometry'].area for i in range(len(gdf_polygons))]
    gdf_polygons = gdf_polygons[gdf_polygons["area"] > 20]
    return gdf_polygons


def main(path):
    "img 0/1两灰度值图像"
    img = cv2.imread(path,0)
    filename = "tmp"
    if np.sum(img):
       CD = extract_lane_by_sheet(img, filename)
       if len(CD):
          CD.to_file(filename, driver='GeoJSON')

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值