Automatically convert pixels to millimeters in Mathematica - scheduled-tasks

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

Related

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.

Ellipse - Finding the y-coordinate for a specific x co-ordinate

I was wondering if anyone can help me. I'm trying to modal an oval room, and the joists run parallel to one another at 400mm intervals, starting and finishing 200mm from the apexes of the oval. The central joist falls on the centre of the oval at (0,0).
So the oval is positioned at angle = 0, with a centre of (0,0). The major axis is 6000mm long in the x-direction and the minor axis is 3500mm long in the y-direction. The joists run in the y-direction too.
I need to find out the node for each joist along the outside edge of the ellipse. So obviously, I know the x values will be -2800, -2400, ..., 0, ..., 2000, 2400, 2800, and that the central joist will have one node at (0, 1750) and one at (0, -1750), but how can I find the y values for all the other x co-ordinates?
Many thanks.
p.s. In case you can't tell I have exceedinly rudimentary MATLAB skills.
It's convenient to work with semi-axes, denoted a and b below. The equation of ellipse is (x/a)^2+(y/b)^2=1, which gives two values of y, positive b*sqrt(1-(x./a)^2) and negative b*sqrt(1-(x./a)^2).
In MATLAB you can compute them this way:
a = 6000/2;
b = 3500/2;
x = -2800:400:2800;
yP = b.*sqrt(1-(x./a).^2);
yN = - yP;
So, yP contains the positive y-coordinates and yN contains negative y-coordinates.
The dots in front of arithmetic operations mean they are performed on vectors componentwise.

Using rectangle in Matlab. Using Sum()

I have performed rgb2gray on an image and did a sobel edge detection on the image.
then did
faceEdges = faceNoNoise(:,:) > 50; %binary threshold
so it sets the outline of the image (a picture of a face), to black and white. Values 1 is white pixel, and 0 is black pixel. Someone said I could use this,
mouthsquare = rectangle('position',[recX-mouthBoxBuffer, recY-mouthBoxBuffer, recXDiff*2+mouthBoxBuffer/2, recYDiff*2+mouthBoxBuffer/2],... % see the change in coordinates
'edgecolor','r');
numWhite = sum(sum(mouthsquare));
He said to use two sum()'s because it gets the columns and rows of the contained pixels within the rectangle. numWhite always returns 178 and some decimal numbers.
If you have a 2D matrix M (this being -- for exmple -- an image), the way to count how many elements have the value 1 is:
count_1 = sum(M(:)==1)
or
count_1 = sum(reshape(M,1,[])==1)
If the target values are not exactly 1, but have a Δ-threshold of, let's say, +/- 0.02, then one should ask for:
count_1_pm02 = sum((M(:)>=0.98) & (M(:)<=1.02))
or the equivalent using reshape.

OpenCV MATLAB: How to draw a line having a particular Intensity profile?

Below is an arbitrary hand-drawn Intensity profile of a line in an image:
The task is to draw the line. The profile can be approximated to an arc of a circle or ellipse.
This I am doing for camera calibration. Since I do not have the actual industrial camera, I am trying to simulate the correction needed for calibration.
The question can be rephrased as I want pixel values which will follow a plot similar to the above. I want to do this using program (Preferably using opencv) and not manually enter these values because I have thousands of pixels in the line.
An algorithm/pseudo code will suffice. Also please note that I do not have any actual Intensity profile, otherwise I would have read those values.
When will you encounter such situation ?
Suppose you take a picture (assuming complete white) from a Camera, your object being placed on table, and camera just above it in vertical direction. The light coming on the center of the picture vertically downward from the camera will be stronger in intensity as compared to the light reflecting at the edges. You measure pixel values across any line in the Image, you will find intensity curve like shown above. Since I dont have camera for the time being, I want to emulate this situation. How to achieve this?
This is not exactly image processing, rather image generation... but anyways.
Since you want an arc, we still need three points on that arc, lets take the first, middle and last point (key characteristics in my opinion):
N = 100; % number of pixels
x1 = 1;
x2 = floor(N/2);
x3 = N;
y1 = 242;
y2 = 255;
y3 = 242;
and now draw a circle arc that contains these points.
This problem is already discussed here for matlab: http://www.mathworks.nl/matlabcentral/newsreader/view_thread/297070
x21 = x2-x1; y21 = y2-y1;
x31 = x3-x1; y31 = y3-y1;
h21 = x21^2+y21^2; h31 = x31^2+y31^2;
d = 2*(x21*y31-x31*y21);
a = x1+(h21*y31-h31*y21)/d; % circle center x
b = y1-(h21*x31-h31*x21)/d; % circle center y
r = sqrt(h21*h31*((x3-x2)^2+(y3-y2)^2))/abs(d); % circle radius
If you assume the middle value is always larger (and thus it's the upper part of the circle you'll have to plot), you can draw this with:
x = x1:x3;
y = b+sqrt(r^2-(x-a).^ 2);
plot(x,y);
you can adjust the visible window with
xlim([1 N]);
ylim([200 260]);
which gives me the following result:

Draw Camera Range with Postgis

i am working on some camera data. I have some points which consist of azimuth, angle, distance, and of course coordinate field attributes. In postgresql postgis I want to draw shapes like this with functions.
how can i draw this pink range shape?
at first should i draw 360 degree circle then extracting out of my shape... i dont know how?
I would create a circle around the point(x,y) with your radius distance, then use the info below to create a triangle that has a larger height than the radius.
Then using those two polygons do an ST_Intersection between the two geometries.
NOTE: This method only works if the angle is less than 180 degrees.
Note, that if you extend the outer edges and meet it with a 90 degree angle from the midpoint of your arc, you have a an angle, and an adjacent side. Now you can SOH CAH TOA!
Get Points B and C
Let point A = (x,y)
To get the top point:
point B = (x + radius, y + (r * tan(angle)))
to get the bottom point:
point C = (x + radius, y - (r * tan(angle)))
Rotate your triangle to you azimouth
Now that you have the triangle, you need to rotate it to your azimuth, with a pivot point of A. This means you need point A at the origin when you do the rotation. The rotation is the trickiest part. Its used in computer graphics all the time. (Actually, if you know OpenGL you could get it to do the rotation for you.)
NOTE: This method rotates counter-clockwise through an angle (theta) around the origin. You might have to adjust your azimuth accordingly.
First step: translate your triangle so that A (your original x,y) is at 0,0. Whatever you added/subtracted to x and y, do the same for the other two points.
(You need to translate it because you need point A to be at the origin)
Second step: Then rotate points B and C using a rotation matrix. More info here, but I'll give you the formula:
Your new point is (x', y')
Do this for points B and C.
Third step: Translate them back to the original place by adding or subtracting. If you subtracted x last time, add it this time.
Finally, use points {A,B,C} to create a triangle.
And then do a ST_Intersection(geom_circle,geom_triangle);
Because this takes a lot of calculations, it would be best to write a program that does all these calculations and then populates a table.
PostGIS supports curves, so one way to achieve this that might require less math on your behalf would be to do something like:
SELECT ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')
This describes a sector with an origin at 0,0, a radius of 10 degrees (geographic coordinates), and an opening angle of 45°.
Wrapping that with additional functions to convert it from a true curve into a LINESTRING, reduce the coordinate precision, and to transform it into WKT:
SELECT ST_AsText(ST_SnapToGrid(ST_CurveToLine(ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')), 0.01))
Gives:
This requires a few pieces of pre-computed information (the position of the centre, and the two adjacent vertices, and one other point on the edge of the segment) but it has the distinct advantage of actually producing a truly curved geometry. It also works with segments with opening angles greater than 180°.
A tip: the 7.071 x and y positions used in the example can be computed like this:
x = {radius} cos {angle} = 10 cos 45 ≈ 7.0171
y = {radius} sin {angle} = 10 sin 45 ≈ 7.0171
Corner cases: at the antimeridian, and at the poles.