I want to calculate the ndvi from a Sentinel-2 image.
import os
import numpy as np
import rasterio as rio
# suppress true divide warning numpy for 0 divide
np.seterr(divide='ignore', invalid='ignore')
red_f = absolute/path/to/band/4
nir_f = absolute/path/to/band/8
def calc_ndvi():
with rio.open(red_f) as src:
red = src.read()
red = red.astype(np.float64)
with rio.open(nir_f) as src:
nir = src.read()
nir = red.astype(np.float64)
ndvi = np.divide((nir - red),(nir + red))
return ndvi
ndvi = calc_ndvi()
The 'red' and 'nir' originally get loaded in as 'Array of uint16' with a shape of (1, 10980, 10980). I convert this to a float before the calculation using astype. As far as I know it's not necessary to flatten the array to a 2d shape. I have tried this but this didn't work.
The result unfortunately is an array completely filled with 0's.
What am I doing wrong?
You have a typo:
nir = red.astype(np.float64)
Should be:
nir = nir.astype(np.float64)
In:
ndvi = np.divide((nir - red),(nir + red))
You are really doing:
ndvi = np.divide((red - red),(red + red))
Which results in array of 0
Related
I just try out the numpy to find the mean for each column and row of the image, but it show up like a lot of number
import cv2
import numpy as np
shape = np.shape(img)
pixels = np.array(img)
column_means = np.mean(pixels, axis=0) //can change axis = 1 for row
column_max = np.max(pixels, axis=0) //can change axis = 1 for row
column_min = np.min(pixels, axis=0) //can change axis = 1 for row
column_subtract = column_max - column_min //can change axis = 1 for row
print(shape)
print(column_means)
print(column_max)
print(column_min)
print(column_subtract)
Here is sample photo I'm working on it
I have a raster from which I want to derive the coordinates of the highest point (elevation) in the raster.
Getting the highest elevation is easy, but I don't know how to get its coordinates.
What I have so far:
# required modules
from osgeo import gdal
from osgeo import osr
import numpy as np
import rasterio
# allow GDAL to use python exceptions
gdal.UseExceptions()
# save paths to the files needed
input_raster = 'data/dem.tif'
# open input raster file with errorcatching
try:
ds = gdal.Open(input_raster)
except RuntimeError as err:
print (err)
exit(keep_kernel=True)
if ds is None:
print ('Unable to open %s' % input_raster)
exit(keep_kernel=True)
#access size of file
cols = ds.RasterXSize
rows = ds.RasterYSize
#access band and data as numpy arrays
band = ds.GetRasterBand(1)
data1 = band.ReadAsArray(0, 0, cols, rows).astype(float)
#set nodata values to Nan
nodata_val = band.GetNoDataValue()
print(nodata_val)
data_masked = np.ma.masked_equal(data1,nodata_val)
#determine highest elevation value und its coordinates
highest_val = data_masked.max()
geotransform = ds.GetGeoTransform()
originX = geotransform[0]
originY = geotransform[3]
pixelWidth = geotransform[1]
pixelHeight = geotransform[5]
I'm stuck and thankful for any advice.
Get the indices of the max value(s):
indices = np.where(data_masked == data_masked.max())
Also decide what to do when there are multiple cells with the maximum value.
Compute the coordinates with the transforms:
x = indices[0][0] * pixelWidth + originX
I have a raster image of shape 9000x10000 that has RGB bands. I use the below code to get the XY coordinates of all pixels in the image. But it is very slow. Is there a faster way to do it?
filename='file.dat'
inDs = gdal.Open(filename)
outDs = gdal.Translate('{}.xyz'.format(filename), inDs, format='XYZ', creationOptions=["ADD_HEADER_LINE=YES"])
I want to save the XY coordinates and the pixel values in a dataframe.
If your raster file has a GeoTransform attribute, you can try this:
import gdal
import pandas as pd
def ix2xy(r,c,gt):
'''Gets x,y from row and column'''
x = gt[0] + r * gt[1]
y = gt[3] + c * gt[5]
return(x,y)
This little function gets the X/Y coordinates from the GeoTransform attribute which is a tuple with (xorigin, xres, 0, yorigin, 0, yres).
ds = gdal.Open('file.dat')
gt = ds.GetGeoTransform()
df = pd.DataFrame.from_records(itertools.product(range(ds.RasterYSize),range(ds.RasterXSize)),columns=['Row','Column'])
ds = None
df['X'], df['Y'] = zip(*df.apply(lambda x: ix2xy(x['Column'],x['Row'],gt),axis=1))
This should give you a tidy dataframe with the columns Row, Column, X and Y.
My program finds the varaince values of an image at each window of a gridded image. The problem is when I print the values they don't match with what is shown in the ouput image. I have included an example image below.
Here is my code:
#import packages
import numpy as np
import cv2
import dateutil
import llist
from matplotlib import pyplot as plt
import argparse
#Read in image as grey-scale
img = cv2.imread('images/0021.jpg', 0)
#Set scale of grid
scale = 6
#Get x and y components of image
y_len,x_len = img.shape
variance = []
for y in range(scale):
for x in range(scale):
#Crop image 9*9 windows
cropped_img=img[(y*y_len)/scale:((y+1)*y_len)/scale,(x*x_len)/scale:((x+1)*x_len)/scale]
(mean,stdv) = cv2.meanStdDev(cropped_img)
var = stdv*stdv
cropped_img[:] = var
#Print mean_values array
variance.append([var])
variance=np.asarray(variance)
np.set_printoptions(suppress=True, precision=3)
print variance.reshape(1,scale,scale)
cv2.imshow('output_var',img)
#cv2.imwrite('images/output_var_300.jpg',img,[int(cv2.IMWRITE_JPEG_QUALITY), 90])
cv2.waitKey(0)
cv2.destroyAllWindows()
Here is the output image of the code above:
From what I can tell the values below don't match the image above. Does anybody have any idea what is happening here?
print variance.reshape(1,scale,scale)
#[[[ 17.208 43.201 215.305 1101.816 1591.606 2453.611]
# [ 46.664 121.162 326.59 809.223 1021.599 5330.989]
# [ 47.754 64.69 705.875 1625.177 3564.494 10148.449]
# [ 19.153 201.864 289.258 632.737 5285.449 4257.597]
# [ 37.621 159.51 271.725 282.291 2239.097 759.007]
# [ 26.108 98.456 32.958 505.609 575.916 70.741]]]
Thank you in advance.
EDIT : Here is a more realistic output image for those who are interested:
Let's take for example, the second row of variance. Since the color values are in range 0-255 per channel, we can try wrapping your values to fit into that range:
>>> row = [46.664, 121.162, 326.59, 809.223, 1021.599, 5330.989]
>>> wrapped = [x % 256 for x in row]
>>> wrapped
[46.66, 121.16, 70.58, 41.22, 253.59, 210.98]
And voila, it makes sense now.
I know that the NDVI equation is
NDVI = (NIR — VIS)/(NIR + VIS)
I'm trying to calculate it using python. I've got this so far:
inRaster = ('Landsat.tif')
out_NDVI_file = ('NDVI.tif')
red = arcpy.Describe(inRaster+'/Band_3')
NIR = arcpy.Describe(inRaster+'/Band_4')
num = arcpy.sa.Float(NIR-red)
denom = arcpy.sa.Foat(NIR+red)
NDVI = arcpy.sa.Divide(num, denom)
NDVI.Save(out_NDVI_file)
but i get this error message,
Traceback (most recent call last):
File "F:\abc\def.py", line 32, in <module>
num = arcpy.sa.Float(NIR-red)
TypeError: unsupported operand type(s) for -: 'geoprocessing describe data object' and 'geoprocessing describe data object'
Any ideas on what I am doing wrong?
If you replace
red = arcpy.Describe(inRaster+'/Band_3')
NIR = arcpy.Describe(inRaster+'/Band_4')
with
red = arcpy.sa.Raster(inRaster+'/Band_3')
NIR = arcpy.sa.Raster(inRaster+'/Band_4')
your script should work as expected.
The following script calculates NDVI from 4-band NAIP imagery, where band 4 = nIR and band 3 = Red. You need the spatial analyst extension for this.
Keep in mind that Landsat TM Band 4 = nIR & Band 3 = Red and Landsat 8 Band 5 = nIR and Band 4 = Red. USGS Reference
# Calculates NDVI from multispectral imagery
import arcpy, string
from arcpy import env
from arcpy.sa import*
arcpy.CheckOutExtension("spatial")
env.workspace = r'C:\Your\workspace'
input = r'C:\Your\raster.tif'
result = "outputName.tif"
# You may need to change the band combinations.
# This is for 4-band NAIP imagery or Landsat TM.
NIR = input + "\Band_4"
Red = input + "\Band_3"
NIR_out = "NIR.tif"
Red_out = "Red.tif"
arcpy.CopyRaster_management(NIR,NIR_out)
arcpy.CopyRaster_management(Red, Red_out)
Num = arcpy.sa.Float(Raster(NIR_out) - Raster(Red_out))
Denom = arcpy.sa.Float(Raster(NIR_out) + Raster(Red_out))
NIR_eq = arcpy.sa.Divide(Num, Denom)
NIR_eq.save(result)