簡體   English   中英

從點雲創建二維圖像

[英]Create 2d image from point cloud

我正在嘗試將點雲投影到 2d 圖像中,就好像它是衛星圖像一樣。

我有六個要投影的文件,並且點雲很大。 對於最大的一個,我有len(las.X) = 37_763_608max(las.X) - min(las.X) = 122_124max(las.X) - min(las.X) = 273_683 ,所以有時在計算大小時會出現溢出錯誤。

我的第一次嘗試是這樣,但這很慢,運行大約需要 28 分鍾。
在這里,我添加了帶有k_xk_y的循環,因為我得到的圖像大部分是黑色的,我希望到處都有顏色。 我嘗試圍繞每個點/像素循環以使它們大 5 倍,但這是緩慢的部分。

看圖片

帶 k 填充的彩色版本 帶 k 填充的彩色版本黑白版無填充 黑白版無填充

理想情況下,我想讓顏色從一個點/像素轉移到他們鄰居的顏色,以便它們之間存在漸變,並且我沒有任何黑色剩余將圖像初始化為 np.zeros

import laspy
import numpy as np
from PIL import Image
import cv2
from tqdm import tqdm


las = laspy.read("area1.las")

def las_to_rgb(las):
    x, y = las.X, las.Y
    delta_x = max(x) - min(x)
    delta_y = max(y) - min(y)
    re_x = x - min(x)
    re_y = y - min(y)


    # las.red, green and blue are stored as 16bit
    r, g, b = (las.red/256).astype(np.uint8), (las.green/256).astype(np.uint8), (las.blue/256).astype(np.uint8)

    image = np.zeros((delta_y+1, delta_x+1, 3))

    for i, val in enumerate(zip(tqdm(re_x), re_y)):
        for k_x in range(-5, 6):
            for k_y in range(-5, 6):
                if val[0] + k_x < 0 or val[0] + k_x >= delta_x + 1:
                    k_x = 0
                if val[1] + k_y < 0 or val[1] + k_y >= delta_y + 1:
                    k_y = 0
                image[val[1]+k_y, val[0]+k_x] = [b[i], g[i], r[i]]

    cv2.imwrite("test.png", image)
    cv2.waitKey(0)

我發現如何在 numpy 中更快地做到這一點,但它一次只能做一種顏色,所以我決定循環選擇多種顏色,但我認為當我將類型更改為np.unit8時我做錯了,因為 python 占用了到 50GB 的 RAM。

使用 numpy:

一種顏色:

def nu_pro(las):
    x, y = las.X, las.Y
    delta_x = max(x) - min(x)
    delta_y = max(y) - min(y)
    xs = x - min(x)
    ys = y - min(y)

    img_size = (delta_y+1, delta_x+1) # +1 for ravel_multi_index

    bgr = np.array([(las.blue/256).astype(np.uint8), (las.green/256).astype(np.uint8), (las.red/256).astype(np.uint8)])

    coords = np.stack((ys, xs))
    abs_coords = np.ravel_multi_index(coords, img_size)

    image = np.bincount(abs_coords, weights=color, minlength=img_size[1]*img_size[0])
    image = image.reshape(img_size))

    cv2.imwrite("test.png", image)
    cv2.waitKey(0)

對於 RGB

def nu_pro_rgb(las):
    x, y = las.X, las.Y
    delta_x = max(x) - min(x)
    delta_y = max(y) - min(y)
    xs = x - min(x)
    ys = y - min(y)

    img_size = (delta_y+1, delta_x+1) # +1 for ravel_multi_index

    rgb = np.array([(las.red/256).astype(np.uint8), (las.green/256).astype(np.uint8), (las.blue/256).astype(np.uint8)])
    image = []

    coords = np.stack((ys, xs))
    abs_coords = np.ravel_multi_index(coords, img_size)

    for i, color in enumerate(tqdm(rgb)):
        img = np.bincount(abs_coords, weights=color, minlength=img_size[1]*img_size[0])
        image.append(img.reshape(img_size))

    image = np.uint8(np.array(image))
    
    # I am probably messing up this transpose but I'll figure it out eventually
    im = Image.fromarray(image.T, "RGB")
    im.save("pil.png")

歡迎任何指示:)

編輯以澄清顏色。

  • 當有重疊時,應該顯示具有最高z坐標的點。

  • 對於着色,在下圖中, AB之間的點應該是從AB的顏色漸變。
    如果它像黃色點,則為相鄰顏色的平均值(如果存在則不包括黑色)
    我希望我有點道理。

着色示例

我無法訪問您使用的格式,所以我向您展示如何在 x,y 坐標處快速 plot 點,並使用 kernel 掩碼和每個點的顏色放大它們

import numpy as np
import cv2

height, width = 256, 256

# generate a random sample of 1000 (x,y) coordinates and colors
x, y, = np.random.randint(0, 256, size=(2, 1000))
color = np.random.randint(0, 256, size=(1000, 3))

# generate a blank image
# int16 to manage overflow colors when convolving
pointsPlotted = np.zeros((height, width, 3), np.uint16)

# plot x,y,color into blankImage
pointsPlotted[y, x] = color


cv2.imshow("points", pointsPlotted.astype(np.uint8))

# convlove the image with a kernel of ones, size k
k = 5
kernel = np.ones((k, k), np.int16)

largerSquares = cv2.filter2D(src=pointsPlotted, ddepth=-1, kernel=kernel)

# limit max color to 255
largerSquares[largerSquares > 255] = 255

# Convert to uint8
largerSquares = largerSquares.astype(np.uint8)

cv2.imshow("Larger Squares", largerSquares)

這是你想要的嗎?

在重疊部分,添加 colors(上限為 255)

在此處輸入圖像描述

插值,有很多庫。

這使用三次插值,但它只適用於凸包內,因此凸包外的點取自最近鄰。

如果您正在對 GIS 數據進行插值,您可以查看克里金插值法,它應該在凸包外部進行插值。

此代碼不會檢查 Z 較低的點是否在 Z 較高的點之下。您必須刪除這些點以避免對它們進行插值。

from scipy.interpolate import griddata
import numpy as np
import matplotlib.pyplot as plt
import cv2

# create data
height, width = 256, 256

# generate a random sample of 1000 (x,y) coordinates and colors
x, y, z = np.random.randint(0, 256, size=(3, 1000))
color = np.random.randint(0, 256, size=(1000, 3))

# sort x,y,z by z in ascending order so the highest z is plotted over the lowest z
zSort = z.argsort()
x, y, z, color = x[zSort], y[zSort], z[zSort], color[zSort]


# interpolation
# generate a grid where the interpolation will be calculated
X, Y = np.meshgrid(np.arange(width), np.arange(height))


R = griddata(np.vstack((x, y)).T, color[:, 0], (X, Y), method='cubic')
Rlinear= griddata(np.vstack((x, y)).T, color[:, 0], (X, Y), method='nearest')
G = griddata(np.vstack((x, y)).T, color[:, 1], (X, Y), method='cubic')
Glinear= griddata(np.vstack((x, y)).T, color[:, 1], (X, Y), method='nearest')
B = griddata(np.vstack((x, y)).T, color[:, 2], (X, Y), method='cubic')
Blinear= griddata(np.vstack((x, y)).T, color[:, 2], (X, Y), method='nearest')

#Fill empty values with nearest neighbor
R[np.isnan(R)] = Rlinear[np.isnan(R)]
G[np.isnan(G)] = Glinear[np.isnan(G)]
B[np.isnan(B)] = Blinear[np.isnan(B)]

R = R/np.max(R)
G = G/np.max(G)
B = B/np.max(B)

interpolated = cv2.merge((R, G, B))

plt.imshow(interpolated)
plt.scatter(x, y, c=color/255, marker="s",s=1)
plt.show()

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM