The supposed value for this would is 15.2 sq cm. however, when annotation is moved, it becomes 0.04 sq cm.
I got this data from my application where area is computed as 9658.6572265625 and its calibration value is 0.00157889 which results in 15.2 value.
when the corresponding coordinates in pdf space are provided (see code below), the area computed is 5433.001953125.
so i compute the calibration value in pdf space like this.
ratio = area / pdfArea
pdfCalibrationValue = 0.00157889 * ratio;
the result is 0.002806911838696635. which if computed
5433.001953125 x 0.002806911838696635 = 15.2
so i am wondering why the result becomes 0.04.
Thoughts?
public class Test {
public static void main(String[] args) throws Exception {
PdfReader reader = new PdfReader("src.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("result.pdf"));
Rectangle location = new Rectangle(426.582f, 514.291f, 559.0f, 613.818f);
float[] floats = new float[] {
427.582f, 582.873f,
493.036f, 515.291f,
558.0f, 554.237f,
527.4f, 612.818f,
464.727f, 564.709f,
427.582f, 582.873f
};
PdfArray pdfVertices= new PdfArray(floats);
float calib = 0.002806911838696635f;
PdfAnnotation stamp = PdfAnnotation.createPolygonPolyline(stamper.getWriter(),
location, "15.2 sq cm", true, new PdfArray(pdfVertices));
stamp.setColor(BaseColor.RED);
stamp.setBorderStyle(new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID));
stamp.put(PdfName.SUBTYPE, PdfName.POLYGON);
stamp.put(new PdfName("IT"), new PdfName("PolygonDimension"));
stamp.put(PdfName.MEASURE, createMeasureDictionary(calib));
stamper.addAnnotation(stamp, 1);
stamper.close();
reader.close();
}
private static PdfDictionary createMeasureDictionary(float pdfCalibrationValue) {
String unit = "cm";
PdfDictionary measureDictionary = new PdfDictionary();
measureDictionary.put(PdfName.TYPE, PdfName.MEASURE);
measureDictionary.put(PdfName.R, new PdfString("1 " + unit + " = 1 " + unit));
PdfDictionary xDictionary = new PdfDictionary();
xDictionary.put(PdfName.TYPE, PdfName.NUMBERFORMAT);
xDictionary.put(PdfName.U, new PdfString(unit));
xDictionary.put(PdfName.C, new PdfNumber(pdfCalibrationValue));
PdfArray xarr = new PdfArray();
xarr.add(xDictionary);
measureDictionary.put(PdfName.X, xarr);
PdfDictionary dDictionary = new PdfDictionary();
dDictionary.put(PdfName.TYPE, PdfName.NUMBERFORMAT);
dDictionary.put(PdfName.U, new PdfString(unit));
dDictionary.put(PdfName.C, new PdfNumber(1));
PdfArray darr = new PdfArray();
darr.add(dDictionary);
measureDictionary.put(PdfName.D, darr);
PdfDictionary aDictionary = new PdfDictionary();
aDictionary.put(PdfName.TYPE, PdfName.NUMBERFORMAT);
aDictionary.put(PdfName.U, new PdfString("sq " + unit));
aDictionary.put(PdfName.C, new PdfNumber(1));
PdfArray aarr = new PdfArray();
aarr.add(aDictionary);
measureDictionary.put(PdfName.A, aarr);
return measureDictionary;
}
}
You have calculated a factor to translate the areas:
the result is 0.002806911838696635. which if computed
5433.001953125 x 0.002806911838696635 = 15.2
But then you use this factor meant for areas unchanged as conversion factor in the X number format array.
The X number format array is the number format array for measurement of change along the x axis and, if Y is not present, along the y axis as well.
Thus, as you don't have a Y entry, your factor for areas must be the conversion factor in X squared!
In other words, use the square root of your area conversion factor as X conversion factor, i.e. replace
float calib = 0.002806911838696635f;
by
float calib = (float)Math.sqrt(0.002806911838696635);
The result now is much better:
But it is not exactly your 15.2 cm². Thus, I checked your numbers, and indeed, your value of 5433.001953125 for the polygone area is slightly off, it should be around 5388.9613.
Using this more correct value I replaced the line above again, this time by:
float calib = (float)Math.sqrt(15.2/5388.96);
and the result:
Related
I am about to calculate Chorophyll-a in the water bodies in one region, as I outlined above. I have created a mask, with water=1, land=0(transparent). And I want to calculate quality formula (NDCI, refer to normalized difference chl-a index) over the mask I created in the last step. Here are my code.
function maskS2clouds(image) {
var qa = image.select('QA60')
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(
qa.bitwiseAnd(cirrusBitMask).eq(0))
return image.updateMask(mask).divide(10000)
.select("B.*")
.copyProperties(image, ["system:time_start"])
}
var tiles = ['29UNV']
var collection = ee.ImageCollection("COPERNICUS/S2_SR")
.filterDate('2020-01-01', '2020-12-31')
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 20))
.filter(ee.Filter.inList('MGRS_TILE', tiles))
print(collection)
var minmin = collection.map(maskS2clouds)
print(minmin)
var calndwi = function(image){
//water mask
var NDWI = image.normalizedDifference(['B3', 'B8']).rename('NDWI');
return image.addBands(NDWI).updateMask(NDWI.gt(0));
};
print(minmin.map(calndwi));
//Add NDWI to the clipped image collection
var withNDWI = minmin.map(calndwi).select('NDWI');
print("NDWI collection", withNDWI);
var bb = withNDWI.first();
Map.addLayer(bb,{},'ss');
var addNDCI = function(image) {
var ndci = image.normalizedDifference(['B5', 'B4']).rename('NDCI');
return image.addBands(ndci);
};
var withNDCI = minmin.map(addNDCI).select('NDCI');
print("NDCI collection", withNDCI);
var MASK = function(image) {
var mask = bb.mask(image);
return image.addBands(mask);
};
var maskk = withNDCI.map(MASK).select('mask');
print(maskk)**
and it give me the bug like ImageCollection (Error)
Error in map(ID=20200106T114451_20200106T114531_T29UNV):Image.select: Pattern 'mask' did not match any bands.what should I do? thanks a million
The maskk object does not contain any bands named mask, because your MASK function does not create or add any bands with that name.
What your code does, as you've currently written it, is this:
var MASK = function(image) {
// Apply a mask over the 'bb' image.
var mask = bb.mask(image);
// return 'image' (which was the 'mask' parameter above),
// with ALL bands from the object 'mask', which is now a 'masked' version of bb.
// since mask = bb.mask(image), all the bands from bb will be added.
return image.addBands(mask);
};
var maskk = withNDCI
// Map the 'MASK' function over the 'withNDCI' collection
.map(MASK)
// Attempt to select a band named 'mask' (which does not exist).
.select('mask');
I'm not sure what you're looking for when you try to select the mask 'band' - I assume what you want is the masked NCDI image. That's essentially what you have already - but the band names of the 'maskk' object are "NDWI" and "NDCI", since it is derived from the bb, and those are the bands that bb contains. There is no band named "mask".
I am working on a land use classification program using the RS algorithm of the GEE platform. The codes are as the following link.
https://code.earthengine.google.com/7e99f1de58c1251bd9bff0ff7af9368b
Specific codes:
var table = ee.FeatureCollection("users/zongxuli/Jing_Jin_Ji");
//Set up bands and corresponding band names
var inBands = ee.List([1,2,3,4,5,7,6,'pixel_qa'])
var outBands = ee.List(['blue','green','red','nir','swir1','temp', 'swir2','pixel_qa'])
// Get Landsat data
var l8s = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR")
.filterDate(2019-01-01,2019-12-31)
.filterBounds(table)
.select(inBands,outBands)
.filter(ee.Filter.lt("CLOUD_COVER",10))
function getIndexes(image){
// Normalized Difference Vegitation Index(NDWI)
var ndvi = image.normalizedDifference(['nir','red']).rename("ndvi");
image = image.addBands(ndvi);
// Normalized Difference Snow Index(NDWI)
var ndsi = image.normalizedDifference(['green','swir1']).rename("ndsi");
image = image.addBands(ndsi);
// Normalized Difference Water Index(NDWI)
var ndwi = image.normalizedDifference(['nir','swir1']).rename("ndwi");
image = image.addBands(ndwi);
// add Enhanced Vegetation Indexes
var evi = image.expression('2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', {
'NIR' : image.select('nir'),
'RED' : image.select('red'),
'BLUE': image.select('blue') }).float();
image = image.addBands(evi.rename('evi'));
// Add Index-Based Built-Up Index (IBI)
var ibiA = image.expression('2 * SWIR1 / (SWIR1 + NIR)', {
'SWIR1': image.select('swir1'),
'NIR' : image.select('nir')}).rename(['IBI_A']);
var ibiB = image.expression('(NIR / (NIR + RED)) + (GREEN / (GREEN + SWIR1))', {
'NIR' : image.select('nir'),
'RED' : image.select('red'),
'GREEN': image.select('green'),
'SWIR1': image.select('swir1')}).rename(['IBI_B']);
var ibiAB = ibiA.addBands(ibiB);
var ibi = ibiAB.normalizedDifference(['IBI_A', 'IBI_B']);
image = image.addBands(ibi.rename('ibi'));
return(image);
}
function getTopography(image,elevation) {
// Calculate slope, aspect and hillshade
var topo = ee.Algorithms.Terrain(elevation);
// From aspect (a), calculate eastness (sin a), northness (cos a)
var deg2rad = ee.Number(Math.PI).divide(180);
var aspect = topo.select(['aspect']);
var aspect_rad = aspect.multiply(deg2rad);
var eastness = aspect_rad.sin().rename(['eastness']).float();
var northness = aspect_rad.cos().rename(['northness']).float();
// Add topography bands to image
topo = topo.select(['elevation','slope','aspect']).addBands(eastness).addBands(northness);
image = image.addBands(topo);
return(image);
}
// Get an image to train and apply classification to.
var image = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')
.filterBounds(table)
.first();
// get bands
var bands=image.bandNames();
print(bands);
// integers starting from zero in the training data.
var label = 'lcode';
// Overlay the points on the imagery to get training.
var trainings = image.select(bands).sampleRegions({
collection: l8s, //.filterDate(2019-01-01,2019-12-31),
properties: [label],
scale: 30
});
// The randomColumn() method will add a column of uniform random
// numbers in a column named 'random' by default.
var sample = trainings.randomColumn();
var split = 0.7; // Roughly 70% training, 30% testing.
var training = sample.filter(ee.Filter.lt('random', split));
print(training.size());
// Random forest
var classifier = (ee.Classifier.smileRandomForest(15)
.train({
features: training,
classProperty: label,
inputProperties: bands
}));
var classified = image.classify(classifier);
print(classified);
So far, I always received the wrong message "Number (Error) Empty date ranges not supported for the current operation." when running the program. What am I doing wrong?
There is a quotation problem in image collection date filtering:
// Get Landsat data
var l8s = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR")
.filterDate(2019-01-01,2019-12-31)
.filterBounds(table)
.select(inBands,outBands)
.filter(ee.Filter.lt("CLOUD_COVER",10))
it must be:
// Get Landsat data
var l8s = ee.ImageCollection("LANDSAT/LC08/C01/T1_SR")
.filterDate('2019-01-01','2019-12-31')
.filterBounds(table)
.select(inBands,outBands)
.filter(ee.Filter.lt("CLOUD_COVER",10))
And in training for classifier section:
// Overlay the points on the imagery to get training.
var trainings = image.select(bands).sampleRegions({
collection: l8s, //.filterDate(2019-01-01,2019-12-31),
properties: [label],
scale: 30 });
it must be :
// Overlay the points on the imagery to get training.
var trainings =
image.select(bands).sampleRegions({
collection: table,
properties: [label],
scale: 30 });
How I can extract index vegetation points over collections by adapting this beautiful code by #Rodrigo E. Principe:
Extract pixel values by points and convert to a table in Google Earth Engine
I try extract all values mas GEE is crashing, so only NDVI or EVI can works fine.
I did it with this tutorial https://developers.google.com/earth-engine/tutorial_api_06
// Dataset do sensor LS8
var dataset = ee.ImageCollection('LANDSAT/LC08/C01/T1_TOA')
.filterDate('2018-04-01', '2019-03-31')
.select('B5', 'B4')
.filterBounds(aoi6010)
.filter(ee.Filter.lt('CLOUD_COVER', 20));
var addNDVI = function(image) {
var ndvi = image.normalizedDifference(['B5', 'B4']).rename('NDVI');
return image.addBands(ndvi);
};
var withNDVI = dataset.map(addNDVI);
print(withNDVI);
// Empty Collection to fill
var ft = ee.FeatureCollection(ee.List([]))
var fill = function(img, ini) {
// type cast
var inift = ee.FeatureCollection(ini)
// gets the values for the points in the current img
var ft2 = img.reduceRegions(p601018, ee.Reducer.first(),30)
// gets the date of the img
var date = img.date().format()
// writes the date in each feature
var ft3 = ft2.map(function(f){return f.set("date", date)})
// merges the FeatureCollections
return inift.merge(ft3)
}
// Iterates over the ImageCollection
var newft = ee.FeatureCollection(withNDVI.iterate(fill, ft))
I have a series of shelves in a warehouse mapped in a database. The shelves themselves contain boxes that are measured by size in cubic feet. I want to perform a query and filter out the locations that have a minimum amount of cubic feet free in their shelves. I am able to run the query that shows the amount of free space, however the WHERE clause to limit the results of the SUM doesn't seem to have any effect.
Here is my query to get all of the shelves with their free space and total space:
Dim shelves As IQueryable(Of Location) = _db.Locations.Include(Function(l) l.Boxes)
.Select(Function(loc) New With
{
.LocationID = loc.LocationID,
.WarehouseID = loc.WarehouseID,
.Warehouse = loc.Warehouse.Name,
.Row = loc.Row,
.Column = loc.Column,
.Bunk = loc.Bunk,
.TotalSpace = loc.Footage,
.FreeSpace = (loc.Footage - loc.Boxes.Select(Function(s) s.Size).DefaultIfEmpty(0).Sum())
}).ToList()
This returns the correct values for each location, including the correct amount of free space. When I introduce the WHERE clause, it has no effect. Here is my query with the WHERE clause included:
Dim shelves As IQueryable(Of Location) = _db.Locations.Include(Function(l) l.Boxes)
.Where(Function(l) (l.Boxes.Select(Function(e) e.Size).DefaultIfEmpty(0).Sum() >= EmptySpace))
.Select(Function(loc) New With
{
.LocationID = loc.LocationID,
.WarehouseID = loc.WarehouseID,
.Warehouse = loc.Warehouse.Name,
.Row = loc.Row,
.Column = loc.Column,
.Bunk = loc.Bunk,
.TotalSpace = loc.Footage,
.FreeSpace = (loc.Footage - loc.Boxes.Select(Function(s) s.Size).DefaultIfEmpty(0).Sum())
}).ToList()
Since .FreeSpace returns the correct values I'm not sure why it can't filter by that same value in my WHERE clause.
Update
You original Where predicate
.Where(Function(l) (l.Boxes.Select(Function(e) e.Size).DefaultIfEmpty(0).Sum() >= EmptySpace))
was not calculating the free space, which is why it had no effect.
You will notice that in your initial select you calculated free space as
(loc.Footage - loc.Boxes.Select(Function(s) s.Size).DefaultIfEmpty(0).Sum())
Notice loc.Footage was missing in the Where predicate.
That would mean that this updated query should work
Dim shelves As IQueryable(Of Location) = _db.Locations.Include(Function(l) l.Boxes)
.Where(Function(loc) (loc.Footage - loc.Boxes.Select(Function(s) s.Size).DefaultIfEmpty(0).Sum()) >= EmptySpace)
.Select(Function(loc) New With
{
.LocationID = loc.LocationID,
.WarehouseID = loc.WarehouseID,
.Warehouse = loc.Warehouse.Name,
.Row = loc.Row,
.Column = loc.Column,
.Bunk = loc.Bunk,
.TotalSpace = loc.Footage,
.FreeSpace = (loc.Footage - loc.Boxes.Select(Function(s) s.Size).DefaultIfEmpty(0).Sum())
}).ToList()
Original Answer
Try applying the filter on the projected objects after the select
Dim shelves As IQueryable(Of Location) = _db.Locations.Include(Function(l) l.Boxes)
.Select(Function(loc) New With
{
.LocationID = loc.LocationID,
.WarehouseID = loc.WarehouseID,
.Warehouse = loc.Warehouse.Name,
.Row = loc.Row,
.Column = loc.Column,
.Bunk = loc.Bunk,
.TotalSpace = loc.Footage,
.FreeSpace = (loc.Footage - loc.Boxes.Select(Function(s) s.Size).DefaultIfEmpty(0).Sum())
})
.Where(Function(loc) loc.FreeSpace >= EmptySpace)
.ToList()
That way the free space is already calculated and included in the anonymous object.
Consider an ASP.NET MVC controller method that builds an ASP.NET Chart image.
public FileStreamResult MakeImg(IEnumerable<MyObj> stats)
{
Chart barchart = BarChart(400, 300);
Series series1 = new Series("Series1");
series1.ChartArea = "ca1";
series1.ChartType = SeriesChartType.Column;
series1.IsValueShownAsLabel = true;
series1.Font = new Font("Verdana", 9f, FontStyle.Regular);
barchart.Series.Add(series1);
// Set chart data source
barchart.DataSource = stats;
// Set series members names for the X and Y values
barchart.Series["Series1"].XValueMember = "FriendlyDate";
barchart.Series["Series1"].YValueMembers = "NumRecords";
// Data bind to the selected data source
barchart.DataBind();
MemoryStream ms = new MemoryStream();
barchart.SaveImage(ms, ChartImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(ms, "image/png");
}
The image is rendered in an unattractive manner:
fugly http://www.imagechicken.com/uploads/1253830647005451400.png
Question: How can I set the font programmatically for the:
X and Y axis labels - i.e. 0 through 35 on Y, and the dates on X
data - i.e. 12, 0, 0, 3, 6 ?
chart.ChartAreas[0].AxisX.LabelStyle.Font
chart.ChartAreas[0].AxisY.LabelStyle.Font
is the property you need to set the font for the Axes.
Chart1.ChartAreas[0].AxisX.LabelStyle.Font = new System.Drawing.Font("Verdana", 8f);
Chart1.ChartAreas[0].AxisY.LabelStyle.ForeColor = System.Drawing.Color.Red;
Another problem I faced was the jaggies on the text. Changing from .png to .jpg did the trick!