Gain information about objects in an image - image-processing

I have a binary image which contains several separated regions. I want to put a threshold on the Area (number of pixels) that these regions occupy, in the way that: a region would be omitted if it has fewer pixels than the threshold. I already have tried these codes (using bwconncomp):
[...]
% let's assume threshold = 50
CC = bwconncomp(my_image);
L = labelmatrix(CC);
A = cell( size(CC.PixelIdxList,1) , size(CC.PixelIdxList,2) );
A = CC.PixelIdxList;
for column = 1 : size(CC.PixelIdxList,2)
if numel(CC.PixelIdxList{column}) < 50, A{column} = 0;
end
end
But at this point I don't know how to convert cell C back to the shape of my image and then show it! Are there any tricks to do that?
Is there any easier and straighter way to gain information about objects in an image than this one I used in here?
I also need to know length and width of these objects. These objects do not necessarily have any specific geometrical shape!
Thanks

Since no one took the effort to answer my question in here, I found it somewhere else. Now I'm coppying it to here, just in case if anyone novice like me might need to know that.
In order to know length and width of objects in an image:
labeledImage = bwlabel(my_image, 8);
regioninfo = regionprops(labeledImage , 'MajorAxisLength', 'MinorAxisLength');
lengths = [regioninfo.MajorAxisLength]; %array
widths = [regioninfo.MinorAxisLength]; %array

Related

Buffer country borders with st_buffer and a SpatialPolygonsDataFrame?

I'm using coordinate_cleaner's country test cc_coun but it's flagging entries with coordinates near to the edges country borders. To try to keep them I wanted to buffer the terrestrial area of countries, essentially expanding their borders a little so that it doesn't flag these entries.
I've tried:
require(rnaturalearth)
world <- ne_countries(scale = "large", returnclass = "sf") %>% st_buffer(dist=.001)
Using st_buffer(dist=.001) does change the geometry, but I noticed whatever I put into dist doesn't matter as it changes it to the same thing regardless (I tried .001, 0.1, 1, 2, and -1, though any minus number removes the geometry altogether).
I found that maybe I need to transform my sf file into something else and then use st_buffer so it's in meters rather than degrees(?). I saw this question/answer but I don't understand it well enough to help my situation: What unit is the `dist` argument in `st_buffer` set to by default?
In the end I'm looking to create a SpatialPolygonsDataFrame reference file to feed into cc_coun. Using the above code I followed on with:
world <- sf:::as_Spatial(world)
coun_test <- cc_coun(x = data,
lon = "Decimal_Long",
lat = "Decimal_Lat",
iso3 = "Country_code",
value = "flagged",
ref = world,
verbose = TRUE)
Which ended up flagging more entries than when I didn't use st_buffer on the reference fine.
In summary, I want to add a buffer to the edge of every country border by around 100 meters in a file I can use as a reference in this test. Is this the best way to go about it or is there a better/easier way? I'd appreciate any advice.
Thank you

Performing an "online" linear interpolation

I have a problem where I need to do a linear interpolation on some data as it is acquired from a sensor (it's technically position data, but the nature of the data doesn't really matter). I'm doing this now in matlab, but since I will eventually migrate this code to other languages, I want to keep the code as simple as possible and not use any complicated matlab-specific/built-in functions.
My implementation initially seems OK, but when checking my work against matlab's built-in interp1 function, it seems my implementation isn't perfect, and I have no idea why. Below is the code I'm using on a dataset already fully collected, but as I loop through the data, I act as if I only have the current sample and the previous sample, which mirrors the problem I will eventually face.
%make some dummy data
np = 109; %number of data points for x and y
x_data = linspace(3,98,np) + (normrnd(0.4,0.2,[1,np]));
y_data = normrnd(2.5, 1.5, [1,np]);
%define the query points the data will be interpolated over
qp = [1:100];
kk=2; %indexes through the data
cc = 1; %indexes through the query points
qpi = qp(cc); %qpi is the current query point in the loop
y_interp = qp*nan; %this will hold our solution
while kk<=length(x_data)
kk = kk+1; %update the data counter
%perform online interpolation
if cc<length(qp)-1
if qpi>=y_data(kk-1) %the query point, of course, has to be in-between the current value and the next value of x_data
y_interp(cc) = myInterp(x_data(kk-1), x_data(kk), y_data(kk-1), y_data(kk), qpi);
end
if qpi>x_data(kk), %if the current query point is already larger than the current sample, update the sample
kk = kk+1;
else %otherwise, update the query point to ensure its in between the samples for the next iteration
cc = cc + 1;
qpi = qp(cc);
%It is possible that if the change in x_data is greater than the resolution of the query
%points, an update like the above wont work. In this case, we must lag the data
if qpi<x_data(kk),
kk=kk-1;
end
end
end
end
%get the correct interpolation
y_interp_correct = interp1(x_data, y_data, qp);
%plot both solutions to show the difference
figure;
plot(y_interp,'displayname','manual-solution'); hold on;
plot(y_interp_correct,'k--','displayname','matlab solution');
leg1 = legend('show');
set(leg1,'Location','Best');
ylabel('interpolated points');
xlabel('query points');
Note that the "myInterp" function is as follows:
function yi = myInterp(x1, x2, y1, y2, qp)
%linearly interpolate the function value y(x) over the query point qp
yi = y1 + (qp-x1) * ( (y2-y1)/(x2-x1) );
end
And here is the plot showing that my implementation isn't correct :-(
Can anyone help me find where the mistake is? And why? I suspect it has something to do with ensuring that the query point is in-between the previous and current x-samples, but I'm not sure.
The problem in your code is that you at times call myInterp with a value of qpi that is outside of the bounds x_data(kk-1) and x_data(kk). This leads to invalid extrapolation results.
Your logic of looping over kk rather than cc is very confusing to me. I would write a simple for loop over cc, which are the points at which you want to interpolate. For each of these points, advance kk, if necessary, such that qp(cc) is in between x_data(kk) and x_data(kk+1) (you can use kk-1 and kk instead if you prefer, just initialize kk=2 to ensure that kk-1 exists, I just find starting at kk=1 more intuitive).
To simplify the logic here, I'm limiting the values in qp to be inside the limits of x_data, so that we don't need to test to ensure that x_data(kk+1) exists, nor that x_data(1)<pq(cc). You can add those tests in if you wish.
Here's my code:
qp = [ceil(x_data(1)+0.1):floor(x_data(end)-0.1)];
y_interp = qp*nan; % this will hold our solution
kk=1; % indexes through the data
for cc=1:numel(qp)
% advance kk to where we can interpolate
% (this loop is guaranteed to not index out of bounds because x_data(end)>qp(end),
% but needs to be adjusted if this is not ensured prior to the loop)
while x_data(kk+1) < qp(cc)
kk = kk + 1;
end
% perform online interpolation
y_interp(cc) = myInterp(x_data(kk), x_data(kk+1), y_data(kk), y_data(kk+1), qp(cc));
end
As you can see, the logic is a lot simpler this way. The result is identical to y_interp_correct. The inner while x_data... loop serves the same purpose as your outer while loop, and would be the place where you read your data from wherever it's coming from.

Is there any way to resize a Surface by any natural number value in ROBLOX?

I've been working with the built-in Resize function in Roblox Studio and have been using it to expand the Top Surface of multiple Parts in order to form a wall-like structure.
The only problem that has arisen when using this method is that the surface of the wall created is not even: Some Parts are higher than others.
I later discovered that this problem is due to the fact that the built-in Resize function only takes integers as it's second parameter (or "expand-by" value). Ideally I need the Parts to have the ability expand by any Real Number.
Are there any alternatives to the built-in Resize function that allow one to resize a Surface by any Real Number?
Yes, this is possible, but it actually requires a custom function to do so. With some fairly basic math we can write a simple function to accomplish such a task:
local Resize
do
local directions = {
[Enum.NormalId.Top] = {Scale=Vector3.new(0,1,0),Position=Vector3.new(0,1,0)},
[Enum.NormalId.Bottom] = {Scale=Vector3.new(0,1,0),Position=Vector3.new(0,-1,0)},
[Enum.NormalId.Right] = {Scale=Vector3.new(1,0,0),Position=Vector3.new(1,0,0)},
[Enum.NormalId.Left] = {Scale=Vector3.new(1,0,0),Position=Vector3.new(-1,0,0)},
[Enum.NormalId.Front] = {Scale=Vector3.new(0,0,1),Position=Vector3.new(0,0,1)},
[Enum.NormalId.Back] = {Scale=Vector3.new(0,0,1),Position=Vector3.new(0,0,-1)},
}
function Resize(p, d, n, c)
local prop = c and 'Position' or 'CFrame'
p.Size = p.Size + directions[d].Scale*n
p[prop] = p[prop] + directions[d].Position*(n/2)
return p.Size, p[prop]
end
end
Resize(workspace.Part, Enum.NormalId.Bottom, 10, false) --Resize workspace.Part downards by 10 studs, ignoring collisions
If you're interested more on how and why this code works the way it does, here's a link to a pastebin that's loaded with comments, which I felt would be rather ugly for the answer here: http://pastebin.com/LYKDWZnt

randomly selection of images from File

I have a file that contains a 400 images. What I want is to separate this file into two files: train_images and test_images.
The train_images should contains 150 images selected randomly, and all these images must be different from each other. Then, the test_images should also contains 150 images selected randomly, and should be different from each other, even from the images selected in the file train_images.
I begin by writing a code that aims to select a random number of images from a Faces file and put them on train_images file. I need your help in order to respond to my behavior described above.
clear all;
close all;
clc;
Train_images='train_faces';
mkdir(Train_images);
ImageFiles = dir('Faces');
totalNumberOfImages = length(ImageFiles)-1;
scrambledList = randperm(totalNumberOfImages);
numberIWantToUse = 150;
loop_counter = 1;
for index = scrambledList(1:numberIWantToUse)
baseFileName = ImageFiles(index).name;
str = fullfile('faces', baseFileName); % Better than STRCAT
face = imread(str);
imwrite( face, fullfile(Train_images, ['hello' num2str(index) '.jpg']));
loop_counter = loop_counter + 1;
end
Any help will be very appreciated.
Your code looks good to me. When you implement the test, you can re-run the scrambledList = randperm(totalNumberOfImages); then select the first 150 elements in scrambledList as you did in training process.
You can also directly re-initialize the loop:
for index = scrambledList(numberIWantToUse+1 : 2*numberIWantToUse)
... % same thing you wrote in your training loop
end
with this approach, your test sample will be completely different from the training sample.
Supposing that you have the Bioinformatics Toolbox, you can use crossvalind using the parameter HoldOut:
This is an example. trainand test are logical arrays, so you can use findto get the actual indexes:
ImageFiles = dir('Faces');
ImageFilesIndexes = ones(1,length(ImageFiles )) %Use a numeric array instead the char array
proportion = 150/400; %Testing set
[train,test] = crossvalind('holdout',ImageFilesIndexes,proportion );
training_files = ImageFiles(train); %250 files: It is better to use more data to train
testing_files = ImageFiles(test); %150 files
%Then do whatever you like with the files
Other possibilities are dividerand ( Neural Network Toolbox) and cvpartition (Statistics Toolbox)

Reading Pixel Value Method?

I'm having a problem regarding reading the pixel values (w=30, h=10). Suppose I'm using
int readValue = cvGetReal2D(img,y,x); and
int readValue = data[y*step+x];
Lets say I am trying to access pixel values at w=35, h=5 using the (1) and (2) method.
The (1) will output an error of index out of range. But why (2) does not output an error of index out of range?
After that, I'm trying to use try...catch()...
You have a continuous block of memory of
size = w*h = 300
At w = 35 and h = 5 your equation gives
data[5*30+35] = data[190] < data[300]
so there is no error. If this is c++ then even if your index in data was larger than 299 it wouldn't throw an error. In that case you would be accessing the data beyond its bounds which results in undefined behavior.
I assume cvGetReal2D(img,y,x) is smart enough to tell you that one of your indices is larger than the defined size of that dimension even though it could be resolved to a valid address.

Resources