Google Earth Engine Sentinel-2 Level2 set to NaN clouds - masking

I would like to set to NaN or Null all clouds to a cut section of a Sentinel-2 MSI level 2, for one band only if possible (not all RGB) I have used the following code:
/**
* Function to mask clouds using the Sentinel-2 QA band
* #param {ee.Image} image Sentinel-2 image
* #return {ee.Image} cloud masked Sentinel-2 image
*/
function maskS2clouds(image) {
var qa = image.select('QA60');
// Bits 10 and 11 are clouds and cirrus, respectively.
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
// Both flags should be set to zero, indicating clear conditions.
var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
.and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask).divide(10000);
}
var dataset = ee.ImageCollection('COPERNICUS/S2_SR')
.filterDate('2020-01-01', '2020-01-30')
// Pre-filter to get less cloudy granules.
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',20))
.map(maskS2clouds);
var visualization = {
min: 0.0,
max: 0.3,
bands: ['B4', 'B3', 'B2'],
};
Map.setCenter(83.277, 17.7009, 12);
Map.addLayer(dataset.mean(), visualization, 'RGB');
the code used does not completely eliminate the clouds as is seen in the figure:
when I do the same for Landsat I have found out the clouds are well masked with the code:
/**
* Function to mask clouds based on the pixel_qa band of Landsat SR data.
* #param {ee.Image} image Input Landsat SR image
* #return {ee.Image} Cloudmasked Landsat image
*/
var cloudMaskL457 = function(image) {
var qa = image.select('pixel_qa');
// If the cloud bit (5) is set and the cloud confidence (7) is high
// or the cloud shadow bit is set (3), then it's a bad pixel.
var cloud = qa.bitwiseAnd(1 << 5)
.and(qa.bitwiseAnd(1 << 7))
.or(qa.bitwiseAnd(1 << 3));
// Remove edge pixels that don't occur in all bands
var mask2 = image.mask().reduce(ee.Reducer.min());
return image.updateMask(cloud.not()).updateMask(mask2);
};
var dataset = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')
.filterDate('2011-01-01', '2011-12-31')
.map(cloudMaskL457);
var visParams = {
bands: ['B3', 'B2', 'B1'],
min: 0,
max: 3000,
gamma: 1.4,
};
Map.setCenter(34.9774, 32.4916, 8);
Map.addLayer(dataset.median(), visParams);

Related

Find 7 vertices of a box using openCV

I don't know if this question have been repeating in here. If yes then i'm sorry..
I have a box that positioned to see H,W,L view. I understand steps to get vertices however most of the examples in the net only describes how to get 4 vertices from 2D plane. So my question is, how if we want to get 7 vertices (like the pic above) and handle it in numpy? How to differentiate between upper points and lower points?
I will be using Python to determine this.
Here's my attempt to get the 8 corners of the 3d rectangle. I masked on the saturation channel of the HSV color space since that separates out white.
I used findContours to get the contour of the box and then used approxPolyDP to get a six-point approximation (the six visible corners).
From there I approximated the two "hidden" corners via a parallelogram approximation. For each point I looked two points behind and created a fourth point that would make a parallelogram with that side. I then took the centroid of these parallelogram points to guess the corner. I hoped that taking the centroid of the points would help even out the error between the parallelogram assumption and the perspective warping, but it did a poor job.
If you need a better approximation there are probably ways to estimate the perspective warping to get the corners.
import cv2
import numpy as np
import random
def tup(point):
return (int(point[0]), int(point[1]));
# load image
img = cv2.imread("box.jpg");
# reduce size to fit on screen
scale = 0.25;
h,w = img.shape[:2];
h = int(scale*h);
w = int(scale*w);
img = cv2.resize(img, (w,h));
copy = np.copy(img);
# convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV);
h,s,v = cv2.split(hsv);
# make mask
mask = cv2.inRange(s, 30, 255);
# dilate and erode to get rid of small holes
kernel = np.ones((5,5), np.uint8);
mask = cv2.dilate(mask, kernel, iterations = 1);
mask = cv2.erode(mask, kernel, iterations = 1);
# contours # OpenCV 3.4, in OpenCV 2 or 4 it returns (contours, _)
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
contour = contours[0]; # just take the first one
# approx until 6 points
num_points = 999999;
step_size = 0.01;
percent = step_size;
while num_points >= 6:
# get number of points
epsilon = percent * cv2.arcLength(contour, True);
approx = cv2.approxPolyDP(contour, epsilon, True);
num_points = len(approx);
# increment
percent += step_size;
# step back and get the points
# there could be more than 6 points if our step size misses it
percent -= step_size * 2;
epsilon = percent * cv2.arcLength(contour, True);
approx = cv2.approxPolyDP(contour, epsilon, True);
# draw contour
cv2.drawContours(img, [approx], -1, (0,0,200), 2);
# draw points
for point in approx:
point = point[0]; # drop extra layer of brackets
center = (int(point[0]), int(point[1]));
cv2.circle(img, center, 4, (150, 200, 0), -1);
# do parallelogram approx to get the two "hidden" corners to complete our 3d rectangle
proposals = [];
size = len(approx);
for a in range(size):
# get points backwards
two = approx[a - 2][0];
one = approx[a - 1][0];
curr = approx[a][0];
# get vector from one -> two
dx = two[0] - one[0];
dy = two[1] - one[1];
hidden = [curr[0] + dx, curr[1] + dy];
proposals.append([hidden, curr, a, two]);
# debug draw
c = np.copy(copy);
cv2.circle(c, tup(two), 4, (255, 0, 0), -1);
cv2.circle(c, tup(one), 4, (0,255,0), -1);
cv2.circle(c, tup(curr), 4, (0,0,255), -1);
cv2.circle(c, tup(hidden), 4, (255,255,0), -1);
cv2.line(c, tup(two), tup(one), (0,0,200), 1);
cv2.line(c, tup(curr), tup(hidden), (0,0,200), 1);
cv2.imshow("Mark", c);
cv2.waitKey(0);
# draw proposals
for point in proposals:
point = point[0];
center = (point[0], point[1]);
cv2.circle(img, center, 4, (200, 100, 0), -1);
# group points and sum up points
hidden_corners = [[0,0], [0,0]];
for point in proposals:
# get index and update hidden corners
index = point[2] % 2;
pos = point[0];
hidden_corners[index][0] += pos[0];
hidden_corners[index][1] += pos[1];
# divide to get centroid
hidden_corners[0][0] /= 3.0;
hidden_corners[0][1] /= 3.0;
hidden_corners[1][0] /= 3.0;
hidden_corners[1][1] /= 3.0;
# draw new points
for point in proposals:
# unpack
pos = point[0];
parent = point[1];
index = point[2] % 2;
source = point[3];
# draw
color = [random.randint(0, 150) for a in range(3)];
cv2.line(img, tup(hidden_corners[index]), tup(parent), (0,0,200), 2);
cv2.line(img, tup(pos), tup(parent), color, 1);
cv2.line(img, tup(pos), tup(source), color, 1);
cv2.circle(img, tup(hidden_corners[index]), 4, (200, 200, 0), -1);
# show
cv2.imshow("Image", img);
cv2.imshow("Mask", mask);
cv2.waitKey(0);

issue decoding an image using jpeg_js

my environment:
ubuntu 18.04
rtx 2080ti
cuda 10.1
node v12.16.3
tfjs 1.7.4
the saved_model is efficientdet-d0,
and the step of inference is in inference step
for parsing image data with js,i convert img.png to img.jpg,and the result of saved_model is same with saved_model result
the command convert saved_model to tfjs_graph_model is
tensorflowjs_converter --input_format=tf_saved_model /tmp/saved_model ~/DATA/http_models/specDetection/
and my test code is
var tfc = require("#tensorflow/tfjs-converter");
var tf = require("#tensorflow/tfjs-core");
var jpeg_js = require("jpeg-js");
var fs = require("fs");
async function loadModel() {
var modelUrl = "http://localhost:8000/model.json"
var model = await tfc.loadGraphModel(modelUrl);
return model;
}
async function detect() {
var model = await loadModel();
var img = fs.readFileSync("~/SRC/automl_test/efficientdet/img.jpg");
const input = jpeg_js.decode(img,{useTArray:true,formatAsRGBA:false});
const batched = tf.tidy(() => {
const img = tf.browser.fromPixels(input);
// Reshape to a single-element batch so we can pass it to executeAsync.
return img.expandDims(0);
});
const result = await model.executeAsync({'image_arrays:0':batched},['detections:0']);
console.log(result);
}
detect();
when detect object in img.jpg with my test code,nothing detected --- the size of result is 0
what do i do to sovle this problem?
thanks for any cue
edit:
code 1:
var img = fs.readFileSync("~/DATA/http_models/specDetection/test.jpg");
var dataJpegJs = jpeg_js.decode(img,{useTArray:true,formatAsRGBA:false})
var batched = tf.browser.fromPixels({data:dataJpegJs.data, width: dataJpegJs.width, height:dataJpegJs.height},3);
batched = batched.slice([0,0,0],[-1,-1,3]);
var result = await model.executeAsync({'image_arrays:0':batched.expandDims(0)},['detections:0']);
result = tf.slice(result,[0,0,1],[1,-1,4]);
code 2:
var img = fs.readFileSync("~/DATA/http_models/specDetection/test.jpg");
var dataJpegJs = jpeg_js.decode(img,{useTArray:true,formatAsRGBA:true})
var batched = tf.browser.fromPixels({data:dataJpegJs.data, width: dataJpegJs.width, height:dataJpegJs.height},4);
batched = batched.slice([0,0,0],[-1,-1,3]);
var result = await model.executeAsync({'image_arrays:0':batched.expandDims(0)},['detections:0']);
result = tf.slice(result,[0,0,1],[1,-1,4]);
code 1 got a bad result and code 2 got a correct result.
code 2 decode jpg with formatAsRGBA:true,and set numChannels=4 in tf.browser.fromPixels. jpeg-js must decode jpg to RGBA to work correctly.
i think it is a bug of jpeg-js.or i am not familiar with jpg encoding?
The tensor is not well generated. fromPixels is mostly used to get a tensor from an htmlImageElement. Printing a summary of the tensor and compare it with the one generated for python can suffice to tell that.
Is there an issue with jpeg-js ?
First we need to know how the imageData works. An image Data pixel is a 4 numerical values R, G, B, A. When using the data decoded by jpeg_js.decode as argument of tf.browser.fromPixel with 3 channels (formatAsRGBA:false), it is considered as an image data. Let's consider the data [a, b, c, d, e, f] = jpeg_js.decode("path", {formatAsRGBA:false}) and the tensor t created from it
t = tf.browser.fromPixels({data, width: 2, height: 1}). How it is interpreted ? tf.browser.fromPixels, will create an ImageDate of height: 1 and of width: 2. Consequently, the imageData will be of size 1 * 2 * 4 (instead of 1 * 2 * 3) and has all its values set to 0. Then it will copy the data decoded to the imageData. So imageData = [a, b, c, d, e, f, 0, 0].
As a result, the slice (t.slice([0, 0, 0], [-1, -1, 3]) will be [a, b, c, e, f, 0].
Neither is jpeg_js the issue, nor tf.browser.fromPixels. This is how imageData works
What can be done ?
keep the alpha channel of the decoded image formatAsRGBA:true
Instead of using tf.browser.fromPixels, use directly tf.tensor to create the tensor
const img = tf.tensor(input.data, [input.height, input.width, 3])
Another option is to usetensorflow-node. And tf.node.decodeImage can decode an image from a tensor.
const img = fs.readFileSync("path/of/image");
const tensor = tf.node.decodeImage(img)
// use the tensor for prediction
Unlike jpeg-js that works only for image in jpeg encoding format, it can decode a wider range of images

How to calculate the length in mm of a string in a PDF document created with jsPDF library?

I use jsPDF library to create and print a PDF document. This library exposes low level methods which are ok, but i have tons of fields to create, many of which are similar, and i need to create higher level abstractions.
For example i have a createLabel function that i want to call instead of this low level stuff.
var doc = new jsPDF('portrait', 'mm', 'a4');
doc.addFont('Arial', "sans-serif", "normal");
// name
doc.setFontSize(14);
doc.text(10, 19, "name:");
doc.setLineWidth(0.1);
doc.line(25, 19, 100, 19); // meaning x1, y1, x2, y2
// CUI
doc.setFontSize(14);
doc.text(10, 29, "CUI:");
doc.setLineWidth(0.1);
doc.line(21, 29, 100, 29);
// same stuff but use functions instead.
createLabel("name: ", 10,50, 100); // meaning (labelName, x, y, totalWidth)
createLabel("CUI: ", 10,60, 100);
As you can see, the lines for the second group of labels are not placed in the right position. They are too much on the left. Their starting postion is generated based on the length of the labelName, and this length calculation fails. How can i make this work properly? The code so far is:
function createLabel(name, x, y, totalWidth) {
//draw name
doc.setFontSize(14);
doc.text(x, y, name);
// draw line
const nameLength = (measureLength(name)) + 2;
doc.setLineWidth(0.1);
// i want to start the line after the name ends + 2 mm.
// and end the line in such a way that nameLength + lineLength == totalWidth of the compoenent.
doc.line(x + nameLength, y, x + totalWidth, y);
}
function measureLength(str) {
let canvas = document.createElement('canvas'); // in memory canvas.. not rendered anywere..
let ctx = canvas.getContext("2d")
ctx.font = "14px Arial";
let width = ctx.measureText(str).width;
let mm = ( width * 25.4 ) / 149 // meaning (px * 25.4) / screen DPI
console.log (mm);
return mm; // of course, this calculation turns out wrong..
}
How to make this measureLength function work correctly? Most solutions i found involve DOM but this is PDF.
Notice: I use the same font ('14px Arial') for the PDF document and for the canvas. jsPDF live demo.
Any insight is appreciated, thanks :)
This might resolve your problem:
createLabel(name, x, y, totalWidth) {
doc.setFontSize(14);
doc.text(x, y, name);
// draw line
const nameLength = (doc.getTextDimensions(name).w / (72 / 25.6) ) + 2;
console.log('nameLength', nameLength); // todo remove
doc.setLineWidth(0.1);
// i want to start the line after the name ends + 2 mm.
// and end the line in such a way that nameLength + lineLength == totalWidth of the compoenent.
doc.line(x + nameLength, y, x + totalWidth, y);
}
Check how I calculate nameLength - using build in jsPDF function and converting to mm.
Helpful links:
how to calculate text size
why sometimes calculation might be wrong by few pixels
This is the result:
Remember that you use x + totalWidth for line width, so lines are longer by x compared to manual example at the top

How interpretation MS-EMF Header object properties - Bounds, Frame, Device and Millimeters?

I'm implement rendering MS-EMF to raster image tool.
Parser by specification work's fine. But i have interpretatioin 2.2.9 Header Object properties when rendering problem, not enough information in the specification.
To convert from LOGICAL to DEVICE coordinates use current MapMode. How to interpret them (especially interesting MM_ISOTROPIC and MM_ANISOTROPIC) can look at gdi, for example here.
Now, i'm trying to specify the position and size of the whole image:
var minPoint = new PointF(header.Bounds.Left, header.Bounds.Top);
var maxPoint = new PointF(header.Bounds.Right, header.Bounds.Bottom);
float imageWidth = maxPoint.X - minPoint.X;
float imageHeight = maxPoint.Y - minPoint.Y;
float shiftX = -minPoint.X;
float shiftY = -minPoint.Y;
var globalCanvas = new CanvasClass(options.PageWidth, options.PageHeight);
globalCanvas.RenderTransform = new DrMatrix(1, 0, 0, 1, 0, 0);
float scaleX = options.PageWidth / (maxPoint.X + shiftX);
float scaleY = options.PageHeight / (maxPoint.Y + shiftY);
float minCommonScale = Math.Min(scaleX, scaleY);
if (minCommonScale > Epsilon)
{
globalCanvas.RenderTransform.Scale(minCommonScale, minCommonScale);
}
globalCanvas.RenderTransform.Translate(shiftX, shiftY);
but i don't understand how to use all properties - Bounds, Frame, Device and Millimeters - and the result image is stretched or not correct scaling or position of the image is not correct.
How them interpret?
Example 1.
emf file
header:
Bounds: (0, 0) - (579, 429)
Frame: (0, 0) - (10000, 10000)
Device: 1855, 1034
Millimeters: 320, 240
and total 4 records:
SelectObject(hDC, (HGDIOBJ)GRAY_BRUSH);
Ellipse(hDC, 0, 0, 99, 99);
SelectObject(hDC, (HGDIOBJ)BLACK_BRUSH);
Ellipse(hDC, 480, 330, 579, 429);
result:
but we must see ex1-ethalon
Interestingly, viewers display ehalon incorrect, except the windows standard viewer:
Example 2.
emf file
header:
Bounds: (960, 210) - (3396, 2429)
Frame: (6772, 1481) - (23969, 17143)
Device: 2892, 4125
Millimeters: 204, 291
result (incomplete rendering yet):
but we see ethalon (attention on the image position):

PyOpenCL reduction Kernel on each pixel of image as array instead of each byte (RGB mode, 24 bits )

I'm trying to calculate the average Luminance of an RGB image. To do this, I find the luminance of each pixel i.e.
L(r,g,b) = X*r + Y*g + Z*b (some linear combination).
And then find the average by summing up luminance of all pixels and dividing by width*height.
To speed this up, I'm using pyopencl.reduction.ReductionKernel
The array I pass to it is a Single Dimension Numpy Array so it works just like the example given.
import Image
import numpy as np
im = Image.open('image_00000001.bmp')
data = np.asarray(im).reshape(-1) # so data is a single dimension list
# data.dtype is uint8, data.shape is (w*h*3, )
I want to incorporate the following code from the example into it . i.e. I would make changes to datatype and the type of arrays I'm passing. This is the example:
a = pyopencl.array.arange(queue, 400, dtype=numpy.float32)
b = pyopencl.array.arange(queue, 400, dtype=numpy.float32)
krnl = ReductionKernel(ctx, numpy.float32, neutral="0",
reduce_expr="a+b", map_expr="x[i]*y[i]",
arguments="__global float *x, __global float *y")
my_dot_prod = krnl(a, b).get()
Except, my map_expr will work on each pixel and convert each pixel to its luminance value.
And reduce expr remains the same.
The problem is, it works on each element in the array, and I need it to work on each pixel which is 3 consecutive elements at a time (RGB ).
One solution is to have three different arrays, one for R, one for G and one for B ,which would work, but is there another way ?
Edit: I changed the program to illustrate the char4 usage instead of float4:
import numpy as np
import pyopencl as cl
import pyopencl.array as cl_array
deviceID = 0
platformID = 0
workGroup=(1,1)
N = 10
testData = np.zeros(N, dtype=cl_array.vec.char4)
dev = cl.get_platforms()[platformID].get_devices()[deviceID]
ctx = cl.Context([dev])
queue = cl.CommandQueue(ctx)
mf = cl.mem_flags
Data_In = cl.Buffer(ctx, mf.READ_WRITE, testData.nbytes)
prg = cl.Program(ctx, """
__kernel void Pack_Cmplx( __global char4* Data_In, int N)
{
int gid = get_global_id(0);
//Data_In[gid] = 1; // This would change all components to one
Data_In[gid].x = 1; // changing single component
Data_In[gid].y = 2;
Data_In[gid].z = 3;
Data_In[gid].w = 4;
}
""").build()
prg.Pack_Cmplx(queue, (N,1), workGroup, Data_In, np.int32(N))
cl.enqueue_copy(queue, testData, Data_In)
print testData
I hope it helps.