我试图限制MATLAB中的栅格处理,使其仅包含shapefile边界内的区域,类似于ArcGIS Spatial Analyst函数使用mask的方式。以下是我正在使用的一些(可重现的)样本数据:
这是我用来计算NDVI:
的MATLAB脚本file = 'C:\path\to\doi1m2011_41111h4nw_usda.tif';
[I R] = geotiffread(file);
outputdir = 'C:\output\'
% Calculate NDVI
NIR = im2single(I(:,:,4));
red = im2single(I(:,:,1));
ndvi = (NIR - red) ./ (NIR + red);
double(ndvi);
imshow(ndvi,'DisplayRange',[-1 1]);
% Stretch to 0 - 255 and convert to 8-bit unsigned integer
ndvi = floor((ndvi + 1) * 128); % [-1 1] -> [0 256]
ndvi(ndvi < 0) = 0; % not really necessary, just in case & for symmetry
ndvi(ndvi > 255) = 255; % in case the original value was exactly 1
ndvi = uint8(ndvi); % change data type from double to uint8
% Write NDVI to .tif file (optional)
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'ndvi_' 'temp' '.tif'];
geotiffwrite(outfilename, ndvi, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag)
下图说明了我想用MATLAB完成的工作。在本例中,我使用ArcGIS raster calculator(Float(Band4-Band1)/ Float(Band4 + Band1))在右侧生成NDVI。我还将研究区域shapefile指定为mask in the environment settings。
问题:
如何使用多边形shapefile作为空间蒙版来限制MATLAB中的栅格处理范围,以复制图中显示的结果?
我的尝试失败:
roipoly和poly2mask,虽然我似乎无法正确应用这些功能(考虑到这些是空间数据)以产生所需的效果。
修改
我尝试了以下方法将shapefile转换为蒙版,但没有成功。不知道我在哪里错了...
s = 'C:\path\to\studyArea.shp'
shp = shaperead(s)
lat = [shp.X];
lon = [shp.Y];
x = shp.BoundingBox(2) - shp.BoundingBox(1)
y = shp.BoundingBox(3) - shp.BoundingBox(1)
x = poly2mask(lat,lon, x, y)
错误讯息:
Error using poly2mask
Expected input number 1, X, to be finite.
Error in poly2mask (line 49)
validateattributes(x,{'double'},{'real','vector','finite'},mfilename,'X',1);
Error in createMask (line 13)
x = poly2mask(lat,lon, x, y)
答案 0 :(得分:1)
这里有三个步骤,我将为此创建3个函数:
ndvi = comp_ndvi(nir, red)
mask = comp_mask(shape)
output = combine_ndvi_mask(ndvi, mask)
您的问题中包含comp_ndvi()
的代码。 combine_ndvi_mask()
的代码取决于您要对遮罩区域执行的操作;如果你想让它们变成白色,它可能看起来像:
function output = combine_ndvi_mask(ndvi, mask)
output = ndvi;
output(~mask) = 255;
end
在comp_mask()
中,您需要使用poly2mask()
将多边形顶点转换为栅格蒙版。为了在这里提供帮助,我需要知道你已经拥有了什么。你有顶点加载到MATLAB?你用poly2mask试过了什么?
答案 1 :(得分:1)
您可以通过以下方式阅读感兴趣的区域:
roi = shaperead('study_area_shapefile/studyArea.shp');
砍掉尾随的NaN:
rx = roi.X(1:end-1);
ry = roi.Y(1:end-1);
如果你的shapefile中有多个多边形,它们会被NaN分开,你必须单独处理它们。
然后使用sat-image空间参考中的worldToIntrinsic方法将多边形点转换为图像坐标:
[ix, iy] = R.worldToIntrinsic(rx,ry);
这假设两个坐标系都相同。
然后你可以通过以下方式制作面具:
mask = poly2mask(ix,iy,R.RasterSize(1),R.RasterSize(2));
您可以在进行任何计算之前使用原始多层图像上的蒙版:
I(repmat(~mask,[1,1,4])) = nan;
或者通过以下方式在单层(即红色)上使用它
red(~mask) = nan;
如果区域非常小,将掩蔽图像转换为稀疏矩阵可能是有益的(对于存储器和计算能力)。我没有尝试,如果这有任何速度差异。
red(~mask) = 0;
sred = sparse(double(red));
不幸的是,稀疏的matrizes只能用双打,所以你的uint8需要在转换之前。
通常,您应该从图像中裁剪ROI。查看对象“roi”和“R”以查找有用的参数和方法。我没有在这里做过。
最后我的脚本版本,稍作其他一些改动:
file = 'doi1m2011_41111h4nw_usda.tif';
[I R] = geotiffread(file);
outputdir = '';
% Read Region of Interest
roi = shaperead('study_area_shapefile/studyArea.shp');
% Remove trailing nan from shapefile
rx = roi.X(1:end-1);
ry = roi.Y(1:end-1);
% convert to image coordinates
[ix, iy] = R.worldToIntrinsic(rx,ry);
% make the mask
mask = poly2mask(ix,iy,R.RasterSize(1),R.RasterSize(2));
% mask sat-image
I(repmat(~mask,[1,1,4])) = 0;
% convert to sparse matrizes
NIR = sparse(double(I(:,:,4)));
red = sparse(double(I(:,:,1)));
% Calculate NDVI
ndvi = (NIR - red) ./ (NIR + red);
% convert back to full matrizes
ndvi = full(ndvi);
imshow(ndvi,'DisplayRange',[-1 1]);
% Stretch to 0 - 255 and convert to 8-bit unsigned integer
ndvi = (ndvi + 1) / 2 * 255; % [-1 1] -> [0 255]
ndvi = uint8(ndvi); % change and round data type from double to uint8
% Write NDVI to .tif file (optional)
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'ndvi_' 'temp' '.tif'];
geotiffwrite(outfilename, ndvi, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag);
mapshow(outfilename);