Chiefir
Chiefir

Reputation: 2671

How to filter colors from 16-bit values from .las file?

I have a .las file with content, like this:

   array([( 860297,  472942, 67187, 11051, 73, 0, 0, 0, 1, 12079, 11051,  9252),
           ( 859318,  473132, 67336,  8995, 73, 0, 0, 0, 1,  9252,  8995,  9509),
           ( 859941,  473665, 67550, 12079, 73, 0, 0, 0, 1, 12079, 12850, 10023),
           ...,
           (1057593, 1184341, 75212, 19018, 73, 0, 0, 0, 1, 20303, 19275, 16191),
           (1057764, 1184161, 74734, 14906, 73, 0, 0, 0, 1, 15934, 14906, 13878),
           (1057548, 1184058, 74881, 26214, 73, 0, 0, 0, 1, 28784, 25957, 21074)],
          dtype=[('X', '<i4'), ('Y', '<i4'), ('Z', '<i4'), ('intensity', '<u2'), ('bit_fields', 'u1'),
                 ('raw_classification', 'u1'), ('scan_angle_rank', 'i1'), ('user_data', 'u1'),
                 ('point_source_id', '<u2'), ('red', '<u2'), ('green', '<u2'), ('blue', '<u2')])

As I have found in .las files values in RGB are stored in 16-bit colors. I wrote 2 functions - convert colors to 8-bit:

opened_file = open("my.las") #example
colors = opened_file.points[["red", "green", 'blue']]
>>> array([(12079, 11051,  9252), (9252,  8995,  9509), (12079, 12850, 10023), ...])

def eightbitify(colour):
    return colour/256

Next I am trying to convert colors to HSV, so I will have a possibility to filter specific colors:

def to_hsv(rgb: np.ndarray):
    empty_image = np.zeros((1, 1, 3), dtype=np.uint8)
    empty_image[0, 0] = list(reversed(rgb))
    hsv = cv2.cvtColor(empty_image, cv2.COLOR_RGB2HSV)
    return list(reversed(hsv[0, 0]))

I did not manage to find better solution for this, because OpenCV needs image - so I am creating image for 1 pixel and converting it (so ugly :/ ). The problem is that values which I recieve does not match any internet RGB-HSV calculators results. I am using those functions in this way:

def convert_color(rgb_16: np.ndarray)->np.ndarray:
    converted_color = np.array([int(eightbitify(rgb_16[0])), int(eightbitify(rgb_16[1])), int(eightbitify(rgb_16[2]))])
    converted_hsv = to_hsv(converted_color)
    return converted_hsv

for color in colors:
    converted = convert_color(color)

So my questions are:
1. What is the best way to convert RGB values to HSV from my opened_file.points initial array?
2. How can I filter specific colors from my opened_file.points only using numpy? May be I can apply some converting function to RGB values, etc?
Unfortunately, I have a very small experience with numpy, so I need help. Thank you!

Upvotes: 2

Views: 1034

Answers (1)

Mark Setchell
Mark Setchell

Reputation: 207798

I am not familiar with your image type but can hopefully help you with the Numpy and OpenCV aspects.

#!/usr/bin/env python3

import pylas
import cv2
import numpy as np

# Open file
las = pylas.read('W2.las')

# Extract all the red values into a Numpy array, likewise green and blue
R = las.points["red"]
G = las.points["green"]
B = las.points["blue"]

# Make a Numpy image by stacking the RGB values and converting to uint8
BGR = (np.dstack((B,G,R))>>8).astype(np.uint8)

# Convert to HSV
HSV = cv2.cvtColor(BGR, cv2.COLOR_BGR2HSV)

# Define lower and uppper limits of what we call "green"
range_lo = np.array([70,30,30])
range_hi = np.array([90,255,255])

# Mask image to only select greens
mask = cv.inRange(HSV,range_lo,range_hi)

# Change image to red where we found green
image[mask>0]=(0,0,255)

cv.imwrite("result.png",image)

At the moment, I don't know the shape of the image, so it comes out as a long line of 44 million pixels, but it just needs a reshape() to make it correct. Note that each True/False value in mask will be the index into your list of pixels and indicate whether that pixel is green or not.

You may have to work with the lower and upper values of the range parameter - see my answer here.

Stack Overflow user @nathancy made a rather neat HSV colour selector with sliders here.

Upvotes: 2

Related Questions