How do I create a 16-bit grayscale image from my array dataset
Question:
I want to convert a height map from NASA database into an image file. There is already a bit about this on the net and that helped me to read the file into an array and it looks like this:
data = [(113.0, 39.0, 1242), (113.00027777777778, 39.0, 1231), (113.00055555555555, 39.0, 1232), (113.00083333333333, 39.0, 1239), (113.00111111111111, 39.0, 1244), ...]
So I have an array with all the data according to the data pattern
data[width][height][tupel]
tupel = [longitude, latitude, height]
the width and height are both 3601 long.
print (data[1800][1800])
returns the tupel: (113.5, 39.5, 2032)
and that’s fine. It is exactly the center of the dataset which goes from longitude 39 to 40 and from latitude 113 to 114. I don’t think I will need longitude and latitude because I know that the data set is 3601 x 3601 in size. The valuable information is in the last value, the height. In my example here the 2032.
My question now is: How do i get the data set data = [rows, columns, [longitude, latitude, height] ] to a 16 bit grayscale image. As mentioned, longitude and latitude are not relevant. Do I have to first make the dataset something like data = [rows, columns, heights] so filter out longitude and latitude? before I can further process the image file?
And how exactly do I create a 16-bit grayscale image file in png from this?
Answers:
We may convert the data to NumPy array, and use few NumPy data operation:
-
Convert data
to NumPy array
array shape is supposed to be 3601*3601 rows by 3 columns:
arr = np.array(data)
-
Keep only the altitude (height) data:
alt = arr[:, 2]
-
Reshape the long column to 3601 x 3601:
alt = alt.reshape(height, width)
-
Clip alt to range [0, 65535], round and convert to np.uint16
:
alt = alt.clip(0, np.iinfo(np.uint16).max).round().astype(np.uint16)
Here is a code sample with 4×4 image instead of 3601×3601:
import numpy as np
import cv2
width, height = 4, 4 # Test 4x4 image instead of 3601x3601
data = [(113.0, 39.0, 1242), (113.00027777777778, 39.0, 1231), (113.00055555555555, 39.0, 1232), (113.00083333333333, 39.0, 1239), (113.00111111111111, 39.0, 1244),
(1113.0, 139.0, 11242), (1113.00027777777778, 139.0, 11231), (1113.00055555555555, 139.0, 11232), (1113.00083333333333, 139.0, 1239), (1113.00111111111111, 139.0, 11244),
(2113.0, 239.0, 21242), (2113.00027777777778, 239.0, 21231), (2113.00055555555555, 239.0, 21232), (2113.00083333333333, 239.0, 21239), (2113.00111111111111, 39.0, 1244), (2113.00111111111111, 239.0, 21244)]
arr = np.array(data) # arr shape is 16 rows by 3 columns.
alt = arr[:, 2] # Keep only the altitude (height) data (16 rows).
assert alt.size == width*height # Make sure the number of elements is correct.
alt = alt.reshape(height, width) # Reshape alt to 4x4.
alt = alt.clip(0, np.iinfo(np.uint16).max).round().astype(np.uint16) # Clip alt to range [0, 65535], round and convert to uint16
cv2.imwrite('alt.png', alt) # Save alt as 16-bit grayscale image file in PNG format.
Note:
The above code is based on your description of the dataset.
The solution may require minor adjustments to work with the actual dataset.
I want to convert a height map from NASA database into an image file. There is already a bit about this on the net and that helped me to read the file into an array and it looks like this:
data = [(113.0, 39.0, 1242), (113.00027777777778, 39.0, 1231), (113.00055555555555, 39.0, 1232), (113.00083333333333, 39.0, 1239), (113.00111111111111, 39.0, 1244), ...]
So I have an array with all the data according to the data pattern
data[width][height][tupel]
tupel = [longitude, latitude, height]
the width and height are both 3601 long.
print (data[1800][1800])
returns the tupel: (113.5, 39.5, 2032)
and that’s fine. It is exactly the center of the dataset which goes from longitude 39 to 40 and from latitude 113 to 114. I don’t think I will need longitude and latitude because I know that the data set is 3601 x 3601 in size. The valuable information is in the last value, the height. In my example here the 2032.
My question now is: How do i get the data set data = [rows, columns, [longitude, latitude, height] ] to a 16 bit grayscale image. As mentioned, longitude and latitude are not relevant. Do I have to first make the dataset something like data = [rows, columns, heights] so filter out longitude and latitude? before I can further process the image file?
And how exactly do I create a 16-bit grayscale image file in png from this?
We may convert the data to NumPy array, and use few NumPy data operation:
-
Convert
data
to NumPy array
array shape is supposed to be 3601*3601 rows by 3 columns:arr = np.array(data)
-
Keep only the altitude (height) data:
alt = arr[:, 2]
-
Reshape the long column to 3601 x 3601:
alt = alt.reshape(height, width)
-
Clip alt to range [0, 65535], round and convert to
np.uint16
:alt = alt.clip(0, np.iinfo(np.uint16).max).round().astype(np.uint16)
Here is a code sample with 4×4 image instead of 3601×3601:
import numpy as np
import cv2
width, height = 4, 4 # Test 4x4 image instead of 3601x3601
data = [(113.0, 39.0, 1242), (113.00027777777778, 39.0, 1231), (113.00055555555555, 39.0, 1232), (113.00083333333333, 39.0, 1239), (113.00111111111111, 39.0, 1244),
(1113.0, 139.0, 11242), (1113.00027777777778, 139.0, 11231), (1113.00055555555555, 139.0, 11232), (1113.00083333333333, 139.0, 1239), (1113.00111111111111, 139.0, 11244),
(2113.0, 239.0, 21242), (2113.00027777777778, 239.0, 21231), (2113.00055555555555, 239.0, 21232), (2113.00083333333333, 239.0, 21239), (2113.00111111111111, 39.0, 1244), (2113.00111111111111, 239.0, 21244)]
arr = np.array(data) # arr shape is 16 rows by 3 columns.
alt = arr[:, 2] # Keep only the altitude (height) data (16 rows).
assert alt.size == width*height # Make sure the number of elements is correct.
alt = alt.reshape(height, width) # Reshape alt to 4x4.
alt = alt.clip(0, np.iinfo(np.uint16).max).round().astype(np.uint16) # Clip alt to range [0, 65535], round and convert to uint16
cv2.imwrite('alt.png', alt) # Save alt as 16-bit grayscale image file in PNG format.
Note:
The above code is based on your description of the dataset.
The solution may require minor adjustments to work with the actual dataset.