Calculating the width of the YOLO bounding box in pixels - image

I am trying to find the width of the bounding box of the output image in pixels:
In this article, it says YOLO v3 extracts coordinates and dimensions of the bounding box (line 82). YOLO returns bounding box coordinates in the form:
(centerX, centerY, width, and height)
Are these coordinates, width and height, real pixel values? Or do they perform scaling on them?
Can I print out the value of width and consider it as a real pixel value for the width of the aforementioned box?
Please note that my question is about YOLO v3.

Those are what are called normalized coordinates. To get the width in pixels you would need to multiply by the width of the images. For example if your image 640x480 than multiple the width values outputted by Yolo by the width of the image.
If the numbers in your screenshot are the width:
Dog width = .98 * 640 = 627 px
Cat width = .88 * 563 = 563 px

Related

How to scale a rotated rectangle to always fit another rectangle

the background of my question is the following.
I have a picture and a crop rectangle which describes how the picture should be cropped to produce the resulting picture. The crop rectangle is always smaller or at maximum the size of the picture.
Now it should be possible to rotate the crop rectangle.
This means that when rotating the crop regtanle inside the picture, the crop must be scaled in order that its extends does not exceed the photo.
Can anybode help me with a formula of how to compute the scale of the crop rectanlge based on the axis aligned photo regtancle?
My first attempt was to compute a axis aligned bounding box of the crop rectanlge and than make this fit it the photo rectangle. But somehow i get stuck with this approach,
Edited:
One more think to note:
- The crop rectangle can have other dimension and another center point inside the surrounding rectangle. This means the crop rectangle can be much smaller but for example is located at the lower left bound of the picture rectangle. So when rotating the smaller crop it will also exceed its limits
Thanks in advance
Sebastian
When you rotate an axis-aligned rectangle of width w and height h by an angle φ, the width and height of the rotated rectangle's axis-aligned bounding box are:
W = w·|cos φ| + h·|sin φ|
H = w·|sin φ| + h·|cos φ|
(The notation |x| denotes an absolute value.) This is the bounding box of the rotated crop rectangle which you can scale to fit the original rectangle of width wo and height ho with the factor
a = min(wo / W, ho / H)
if a is less than 1, the rotated crop rectangle fits inside the original rectangle and you don't have to scale. Otherwise, reduce the crop rectangle to the scaled dimensions
W′ = a·W
H′ = a·H
You could start checking if the dimension of the cropped rectangle fit in the old rectangle:
bound_x = a * cos(theta) + b * sin(theta)
bound_y = b * cos(theta) + a * sin(theta)
Where a and b are the new dimensions, theta us the angle and bound_x and bound_y should be smaller of the original rectangle.

Find the new position of rectangle for resized image

I have a four element position vector [xmin ymin width hight] that specifies the size and position of crop rectangle from image I. How can i find the new position and size for the resized image I?
It is not entirely clear, what you want, as we don't know your coordinate system. Assuming x is the horizontal axis and y is the vertical axis and your point (1,1) is at the top left corner, you can use the following snippet:
p = [xmin ymin width height];
I = I_orig(p(2):p(2)+p(4)-1,p(1):p(1)+p(3)-1);
The size is of course your specified width and height.
You can convert your original bounding box to relative values (that is assuming the image size is 1x1)
[origH origW] = size( origI(:,:,1) );
relativeBB = [xmin / origW, ymin / origH, width / origW, hight / origH];
Now, no matter how you resized your origI, you can recover the bounding box w.r.t the new size from the relative representation:
[currH currW] = size(I(:,:,1));
currBB = relativeBB .* [currW, currH, currW, currH];
You might need to round things a bit: you might find floor better for xmin and ymin and ceil more suitable for width and height.

object dimensions in image according to camera distance faraway

I have a camera placed 10 meters faraway from a portrait (rectangle) having width = 50cm and height = 15cm, I want to get the dimensions of this portrait inside the image captured. The image captured has width=800 px and height=600 px.
How can I calculate the dimensions of the portrait inside the image? Any help please?
I am assuming the camera is located along the center normal of the portrait, looking straight at the portrait's center.
Let's define some variables.
Horizontal field of view: FOV (you need to specify)
Physical portrait width: PW = 50 cm
Width of portrait plane captured: CW cm (unknown)
Image width: IW = 800 px
Width of portrait in image space: X px (unknown)
Distance from camera to subject: D = 10 m
We know tan(FOV) = (CW cm) / (100 * D cm). Therefore CW = tan(FOV) * 100 * D cm.
We know PW / CW = X / IW. Therefore X = (IW * PW) / (tan(FOV) * 100 * D) px.
I agree with Timothy's answer, in that you need to the know the camera's field of view (FOV). I'm not sure I totally follow/agree with his method however. I think this is similar, but it differs, the FOV needs to be divided by two to split our view into two right-angled triangles. Use tan(x)=opposite/adjacent
tan(FOV/2) = (IW/2) / (Dist * 100)
where IW is the true image width (must divide by two as we are only finding finding half of the width with the right-angled triangle), Dist is the distance from the camera to the portrait (converted to cm).
Rearrange that to find the Width of the entire image (IW):
IW = tand(FOV/2) * (2*Dist*100)
You can now work out the width of each pixel (PW) using the number of pixels in the image width (800 for you).
PW = IW / NumPixels
PW = IW / 800
Now divide the true width by this value to find the number of pixels.
PixelWidth = TrueWidth / PW
The same can be done for the height, but you need your camera's field of view.
Im not sure this is the same a Timothy's answer, but I'm pretty sure this is correct.

How to do bar plot in the same scale and dimension as an image?

I have an image, then I am projecting it on one of it's edges by some aggregation functions like mean. I am getting 1D digitized data this way. How to plot it exactly below source image in exactly the same horizontal or vertical scale?
Sample code:
% loading image
image = imread('..\..\FruitSample_small.png');
%computing gradients
dx=double(image(1:end-1,2:end,:))-double(image(1:end-1,1:end-1,:));
dy=double(image(2:end,1:end-1,:))-double(image(1:end-1,1:end-1,:));
% computing total magnitude
a=sqrt(sum(dx.^2,3)+sum(dy.^2,3));
% projection on bottom
h = mean(a,1);
% drawing
figure;
subplot(2,1,1);
imshow(image);
subplot(2,1,2);
bar(h);
axis image;
I want bar plot here to be of the same width as image above. Also I want histogram to spread exactly to the same horizontal coordinate, as image does.
The challenge here is that "axis image" enforces an aspect ratio on the image axis, which allows the display size of the image to vary from its set dimensions. My suggestion is to forget the auto-sizing capabilities that come from normalized units, and adjust the sizes based on pixel sizing. If you set the size of the image axis to exactly the size of the image in pixels, then it will have the correct aspect ratio, and you can use the same size for the bar plot.
load clown; % use a built-in demo image. Note the image is now in X
%computing gradients
dx=double(X(1:end-1,2:end,:))-double(X(1:end-1,1:end-1,:));
dy=double(X(2:end,1:end-1,:))-double(X(1:end-1,1:end-1,:));
% computing total magnitude
a=sqrt(sum(dx.^2,3)+sum(dy.^2,3));
% projection on bottom
h = mean(a,1);
% drawing
figure;
subplot(2,1,1);
imagesc(X);
size_x = size(X,2);
size_y = size(X,1);
set(gcf, 'Units', 'pixels')
fp=get(gcf, 'Position');
set(gca, 'Units', 'pixels');
set(gca, 'Position', [(fp(3)-size_x) / 2, (fp(4)-size_y) / 2 + 100, ...
size_x, size_y]);
subplot(2,1,2);
bar(h);
set(gca, 'Units', 'pixels');
set(gca, 'Position', [(fp(3)-size_x) / 2, 100, size_x, 100]);
set(gca, 'XLim', [1 size_x]);
I'm computing the offsets automatically from the figure size, to center the results on the figure. This is not resizeable. You'd have to rerun the set('Position') stuff to readjust the locations if you resize the figure itself. If you need it to be dynamically resizeable, you'd have to add a handler for a resize event, and adjust the sizes on every resize.

How to lock image dimensions in MATLAB

So I have this matrix in MATLAB, 200 deep x 600 wide. It represents an image that is 2cm deep x 6cm wide. How can I plot this image so that it is locked into proper dimensions, i.e. 2cm x 6cm? If I use the image or imagesc commands it stretches it all out of shape and shows it the wrong size. Is there a way to lock it into showing an image where the x and y axes are proportional?
Second question, I need to then set this image into a 640x480 frame (20 pixel black margin on left and right, 280 pixel black margin on bottom). Is there a way to do this?
To keep aspect ratio, you can use axis equal or axis image commands.
Quoting the documentation:
axis equal sets the aspect ratio so that the data units are the same in every direction. The aspect ratio of the x-, y-, and z-axis is adjusted automatically according to the range of data units in the x, y, and z directions.
axis image is the same as axis equal except that the plot box fits tightly around the data`
For second question:
third_dimension_size=1; %# for b&w images, use 3 for rgb
framed_image=squeeze(zeros(640,480,third_dimension_size));
framed_image(20:20+600-1,140:140+200-1)= my_600_200_image;
imagesc(framed_image'); axis image;
set(gca,'DataAspectRatio',[1 1 1])
Second question:
new_image = zeros(480,640);
new_image(20:(200+20-1),20:(600+20-1)) = old_image;
As an alternative to the other answers, you might want:
set(gca, 'Units', 'centimeters', 'Position', [1 1 6 2])
Make sure you do this after plotting the image to get the other axis properties correct.
For the second question, take care with the number of colour channels:
new_image = zeros(480,640, size(old_image));
new_image(20:(200+20-1),20:(600+20-1),:) = old_image;

Resources