Increase the BBOX size but keep the ratio (Lon/Lat) - postgresql

I have a Bbox that is defined by the following values:
xmin: 11.555333537980914
ymin: 47.76067947037518
xmax: 11.995692579075694
ymax: 48.281587762758136
I would like to increase the size of this Bbox but keep the ratio.
One approach I tried is to calculate the middle point of the Bbox and calculate a new Bbox with the value of radius increased by 50%.
The problem: the ratio gets lost.
How could I increase the size of Bbox to 50% but keep the ratio.

Perhaps ST_Expand is what you're looking for. You could first calculate the area of the input bbox using ST_Area and then use the output as a unit to expand the bbox.
SELECT -- here you can play with different sizes
ST_Expand(geom, ST_Area(geom)/2)
FROM yourtable;
Example:
WITH j (geom) AS (
SELECT ST_MakeEnvelope(11.555333537980914,
47.76067947037518,
11.995692579075694,
48.281587762758136,4326)
)
SELECT
ST_Expand(geom,ST_Area(geom)/2)
FROM j;
The image below represents the result set. The inner bbox is the one you provided and the outer one was created with ST_Expand.
Demo: db<>fiddle

The answer provided by #Jim Jones works perfectly. Is there something PostGIS can not do? :)
I did not wanted to be dependend on PostGIS
so I tried to solve the problem with R. My approach:
I prolong each diagonal of the bbox and calculate the bearing for that diagonal. Based on that data I calculate new edge points of the bbox. It kind of works but the left side of the bbox looks a bit small. I think there is a misstake somwhere but i dont know yet where.
xmin<- 11.555333537980914
ymin<- 47.76067947037518
xmax<- 11.995692579075694
ymax<- 48.281587762758136
###calculate bearing clockwise of diagonal for each corner of the BBOX
######## right bottom, left und top
######## left and bottom, right and top
######## left and top and right and bottom
######## right and top, left and bottom
##bearing(p1, p2, a=6378137, f=1/298.257223563)
bearing1 <- geosphere::bearingRhumb(c(xmax,ymin),c(xmin,ymax))
bearing2 <- geosphere::bearingRhumb(c(xmin,ymin),c(xmax,ymax))
bearing3 <- geosphere::bearingRhumb(c(xmin,ymin),c(xmax,ymin))
bearing4 <- geosphere::bearingRhumb(c(xmax,ymax),c(xmin,ymin))
#new bbox points
########################## left und top
########################## right und top
########################## right und bottom
########################## left und bottom
p1<- geosphere::destPointRhumb(c(xmin,ymax), bearing1, 10000, r = 6378137)
p2<- geosphere::destPointRhumb(c(xmax,ymax), bearing2, 10000, r = 6378137)
p3<- geosphere::destPointRhumb(c(xmax,ymin), bearing3, 10000, r = 6378137)
p4<- geosphere::destPointRhumb(c(xmin,ymin), bearing4, 10000, r = 6378137)
data<-rbind.data.frame(p1,p2,p3,p4)
xmin<-min(data$lon)
ymin<-min(data$lat)
xmax<-max(data$lon)
ymax<-max(data$lat)
cat(xmin,",",ymin,",",xmax,",",ymax)

One solution would be to translate the box so that its center is at the origin, multiply everything with 1.5, and then translate back. This should be possible with a single ST_Affine(), but I'm too lazy to work out the details. :)

Related

Automatically convert pixels to millimeters in Mathematica

I can get the drop contour through a GetDropProfile command.
However, I can't find the conversion factor from pixels to millimeters. As the contour of the drop is obtained point by point starting from left to right, then the first ordered pair in the list gives the coordinates of the first pixel on the left. Consequently, the last ordered pair gives the value of the last pixel on the right. Since they are opposite each other, they therefore have the same y, so the difference in x of these two points is the diameter of the drop. How can I automate this process of converting pixels into millimeters and viewing the graph in millimeters, smoothing the contour of the discrete curve automatically giving us how many points to the right and left we should take?
It follows the image of the drop and the contour in pixels obtained.
As posted here, assuming the axes are in millimetres, the scale can be obtained from the x-axis ticks, which can be sampled from the row 33 from the bottom. As can be observed by executing the code below, the left- and rightmost ticks occupy one pixel each, coloured RGB {0.4, 0.4, 0.4}. So there are 427 pixels per 80mm.
img = Import["https://i.stack.imgur.com/GIuYq.png"];
{wd, ht} = ImageDimensions[img];
data = ImageData[img];
(* View the left- and rightmost pixel data *)
Take[data[[-33]], 20]
Take[data[[-33]], -20]
p1 = LengthWhile[data[[-33]], # == {1., 1., 1.} &];
p2 = LengthWhile[Reverse[data[[-33]]], # == {1., 1., 1.} &];
p120 = wd - p1 - p2 - 1
427
(* Showing the sampled row in the graphic *)
data[[-33]] = ConstantArray[{1, 0, 0}, wd];
Graphics[Raster[Reverse[data]]]
You might ask about smoothing the curve here https://mathematica.stackexchange.com

Loop to change block position

I have a Matlab script that creates a Model Block for each element i found in a text file.
The problem is that all Models are created on each other in the window. So i'm trying to make a loop like:
for each element in text file
I add a Model block
I place right to the previous one
end
So it can look like this:
As you can see on the left, all models are on each other and I would like to place them like the one on the right.
I tried this:
m = mdlrefCountBlocks(diagrammeName)+500;
add_block('simulink/Ports & Subsystems/Model',[diagrammeName '/' component_NameValue]);
set_param(sprintf('%s/%s',diagrammeName,component_NameValue), 'ModelFile',component_NameValue);
size_blk = get_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position');
X = size_blk(1,1);
Y = size_blk(1,2);
Width = size_blk(1,3);
Height = size_blk(1,4);
set_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position',[X+m Y X+Width Y+Height]);
Inside the loop but it returns an error Invalid definition of rectangle. Width and height should be positive.
Thanks for helping!
The position property of a block does actually not contain its width and height, but the positions of the corners on the canvas (see Common Block Properties):
vector of coordinates, in pixels: [left top right bottom]
The origin is the upper-left corner of the Simulink Editor canvas before any canvas resizing. Supported coordinates are between -1073740824 and 1073740823, inclusive. Positive values are to the right of and down from the origin. Negative values are to the left of and up from the origin.
So change your code to e.g.:
size_blk = get_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position');
set_param(sprintf('%s/%s',diagrammeName,component_NameValue),'Position', size_blk + [m 0 0 0]);

Normalized units for annotations dont add up

I am creating a color map for data of size(7x24) that I have , lets replace it with some random numbers
b = randi(50,7,24);
t = imagesc(b,[min(min(b)) max(max(b))]);
now inorder to add annotations I have to know the exact starting and ending point of my axes so that i can add a rectangle to select each point in the image
xPOSITION = get(gca,'Position')
xPOSITION =
0.1300 0.1100 0.7750 0.8150
annotation('rectangle',[0.13 0.11 (0.7750 - 0.13)/24 (0.8150 -0.11)/7],'FaceColor','blue','FaceAlpha',.2)
ok now when i try to add an annotation to the exact starting point of the data , the starting point seem to be fine but the size of the rectangular which should actually be equal to each point is alot smaller
according to my calculation each box is equal to (0.7750 - 0.13)/24 X(0.8150 -0.11)/7 , because the units are normalized , am I doing any mistake in calculation ? or the annotation works in a different way ? any help would be highly appreciated
UPDATE just to test I added 0.11 to each dimension of the annotation and it seem to be the exact size for the reason i cannot figure out
annotation('rectangle',[0.13 0.11 ((0.7750 - 0.13) +0.11)/24 ((0.8150 -0.11)+0.11)/7],'FaceColor','blue','FaceAlpha',.2)
The Position property is the [left bottom width height] not [left bottom right top] as it seems that you're treating it (since you're subtracting element 1 from 3 and 2 from 4). To correctly compute the rect for displaying you'll just want to divide the width and height components by the number of elements in those dimensions.
annotation('rectangle', [xPOSITION(1), xPOSITION(2), ...
xPOSITION(3)/size(b, 2), xPOSITION(4) / size(b,1)])
Or more simply:
annotation('rectangle', xPOSITION ./ [1 1 fliplr(size(b))])
That being said, if you're simply wanting to draw rectangles on your data, you're likely better off just creating a rectangle object which is automatically in the units of your data
rectangle('Position', [0.5 6.5 1 1], 'LineWidth', 5)

How to detect certain moving points in a video using Matlab

I have a video of moving hose in an experiment and I need to detect certain points in that hose and calculate the amplitude of their movements, I am using the code below and I am able to extract the required point using detectSURFFeatures, the function get many unnecessary points so I am using cuba = ref_pts.selectStrongest(5); to choose only five points, the problem is I can not get a function to put a bounding box about this 5 points and get their pixel values through the video, Kindly advice what functions can be used, thanks :)
clear;
clc;
% Image aquisition from Video and converting into gray scale
vidIn = VideoReader('ItaS.mp4');
%% Load reference image, and compute surf features
ref_img = read(vidIn, 1);
ref_img_gray = rgb2gray(ref_img);
ref_pts = detectSURFFeatures(ref_img_gray);
[ref_features, ref_validPts] = extractFeatures(ref_img_gray, ref_pts);
figure; imshow(ref_img);
hold on; plot(ref_pts.selectStrongest(5));
cuba = ref_pts.selectStrongest(5);
stats1 = round(cuba.Location);
If you want to find the bounding box which covers all the five points you selected: stats1 now contains (x, y) coordinates of the selected 5 points. Find min and max for x and y coordinates. min values of x and y gives you the starting point of the rectangle. Width and height of the bounding box is now the difference of max and min in y and x directions.
If you want to extract the part of the original image inside the bounding box: just copy that part to another variable as you want. Consider the following example.
img2 = img1(y:h, x:w, :)
Here, x and y are the x and y coordinates of the top left corner of the bounding box. w and h are the width and height of the bounding box.

How to select bottom half of picture?

def changeRed():
setMediaPath("/Users/addison/Downloads/Cmpt101_Pics/Learjet31A.jpg")
filename1 = "/Users/addison/Downloads/Cmpt101_Pics/Learjet31A.jpg"
source = makePicture(filename1)
halfHeight = getHeight(source)/2
for x in range(0,getWidth(source)):
for y in range(0, halfHeight):
pixel = getPixel(source, x, y)
value = getRed(pixel)
setRed(pixel, value-127.5)
show(source)
Sooo this is my code right now to select the top half of a picture and decresa the redness by 50%. My program also needs to select the bottom half of the picture and increase the redness by 50%, how do i go about doing this?
Pretty much add another for loop within the x in range loop but not in the for y loop you already have. This new for y in range loop should have a range of halfHeight,getHeight(source). Also subtracting -127.5 from red pixels isnt decreasing the red by 50%. Use value/2 instead.