# How can I make a function that determines width and length of a bwimage ?

6 views (last 30 days)
Mara Pereira on 1 Jul 2020
Answered: Image Analyst on 1 Jul 2020
How can I make a function that determines width and length of a bwimage ?

Adam Danz on 1 Jul 2020
You need some kind of refernce to convert pixels to cm or mm or inches, etc.
For example, if you're scanning the entire page and you know the page is 8.5x11'' and the borders of the entire sheet is within your image, then you can compute the size of the image on the sheet, even if the image does not consume the entire sheet.
If you scan the image with a ruler on the scanner, that's another way to record a reference. The image doesn't even need to be aligned with the ruler as long as it's on the same, flat plane.
If you know the size of one dimension (ie, width) of the image, you can compute the other dimensions.
But without a known reference, you cannot convert pixels to a world-reference because there's no way of knowing the conversion factors between the two. When I scan an image and display it on my monitor, it's rarely the same size as the actual image.
Mara Pereira on 1 Jul 2020
but having a reference, how can i turn it into a function?
Adam Danz on 1 Jul 2020
That depends on what your reference is.
The main idea is to convert the pixel size to some other measurement such as cm or mm or inches.
In the image I shared above, I would measure the number of pixels within an inch on the ruler. That gives you pixels-per-inch and you can use its inverse, inches-per-pixel, to convert the pixels returned by size() to inches.
If your reference is the backgroud sheet and the sheet is 8.5x11" and the borders of the sheet are within the image, you can compute the number of pixels between the sheet edges and then divide by the sheet's width or height to get pixels-per-inch.

Image Analyst on 1 Jul 2020
Get the bounding box like this
binaryImage = grayImage < someThreshold;
props = regionprops(binaryImage, 'BoundingBox');
[xMin, xMax, yMin, yMax] = BoundingBoxFromRegionprops(regionpropsOutput, 1)
maxWidth = xMax - xMin; % Optionally add 1 if you want pixel count instead of pixel center-to-pixel center.
maxHeight = yMax - yMin;
% BoundingBoxFromRegionprops gets the overall bounding box of a collection of objects,
% each of which has had its bounding box measured and returned by regionprops()
% and is contained in regionpropsOutput, which is the input argument for this function.
% BoundingBoxFromRegionprops returns a 1 by 4 array with the min and max X and Y.
% Note that regionprops has the bounding box go through the centers of the pixels,
% that is one "layer" outside the actual binary image blob, so they will all end in .5.
% So, if you want the pixel indexes like you'd get from this code:
% verticalProfile = sum(binaryImage, 2);
% horizontalProfile = sum(binaryImage, 1);
% minX = find(horizontalProfile, 1, 'first')
% maxX = find(horizontalProfile, 1, 'last')
% minY = find(verticalProfile, 1, 'first')
% maxY = find(verticalProfile, 1, 'last')
% then you'll have to do this:
% x1 = ceil(xMin);
% x2 = floor(xMax);
% y1 = ceil(yMin);
% y2 = floor(yMax);
% An easy way to do that is to just specify 1 for the second input argument, varargin.
function [xMin, xMax, yMin, yMax] = BoundingBoxFromRegionprops(regionpropsOutput, varargin)
% Extract all the bounding boxes into one big array.
boundingBox = [regionpropsOutput.BoundingBox];
% Extract all the x1's, y1'x, widths, and heights into separate arrays.
all_the_x1s = boundingBox(1:4:end);
all_the_y1s = boundingBox(2:4:end);
all_the_widths = boundingBox(3:4:end);
all_the_heights = boundingBox(4:4:end);
% Determine the x2's and y2's.
all_the_x2s = all_the_x1s + all_the_widths;
all_the_y2s = all_the_y1s + all_the_heights;
% Find the overall bounding box from all the x1's, x2's, y1's, and y2's.
xMin = min(all_the_x1s);
xMax = max(all_the_x2s);
yMin = min(all_the_y1s);
yMax = max(all_the_y2s);
% Get the pixel indexes if requested.
if nargin > 1
usePixelIndexes = varargin{1};
if usePixelIndexes
xMin = ceil(xMin);
xMax = floor(xMax);
yMin = ceil(yMin);
yMax = floor(yMax);
end
end
end % of function BoundingBoxFromRegionprops()
To do the spatial calibration you'll need to define some number of real world units over the length of the object in pixels. See my attached spatial calibration demo to see how that calibration factor is computed.