Recognizing and Replacing values matlab - matlab

So I have a certain grayscale image as a binary file. After I red in the image, I tried to create a series of "if" loops in order to replace a range of values with one value, and leave the rest of the matrix untouched.
I used this code
if myimage < 20
myimage = 0;
else if 20 < myimage <40
myimage = 20;
else if 40 < myimage < 60
myimage = 40;
else if 60<myimage<80
myimage = 60;
end
end
end
end
but for some reason it failed to load an image. After some debugging I figured out that the file was becoming a 1 x 1 matrix with the value "20" after the "else if 20...." line. Can anyone help me figure out why exactly this is happening? thanks.

You need to change the specific indices in myimage that have a specific value. The way your currently calling it, you're overwriting the myimage variable with a specific value. One way to find all the relevant indices is with find:
find(myimage==20)
in order to find and replace all the values with a one liner, reference the indices of interest in myimage:
myimage(find(myimage<20))=0;
and to combine multiple sets of indices (eg values >20 AND <40), use intersect:
myimage(intersect(find(myimage>20),find(myimage<40)))=20;

Related

How to create an array with logical variables and iterate through those variables in a for loop?

I have 16 binary images of logic type, and I want to put those images (variable names) into an array and iterate through them in a for loop doing image processing.
Below is an example of my binary image names, and my current for loop (does not work).
bin_RD1 = imbinarize(rightDam1, T_RD1); %these are my binary images
bin_RD2 = imbinarize(rightDam2, T_RD2);
bin_RD3 = imbinarize(rightDam3, T_RD3);
bin_RD4 = imbinarize(rightDam4, T_RD4);
i = who('bin*'); %says of type 16x1 cell
for j = 1:length(i) %j is listed as just a number
k = i{j}; %char type: 'bin_RD1'
% logical k; did not work
roi = bwareaopen(k, 25);
graindata = regionprops('table',roi,'Area','EquivDiameter','MajorAxisLength','MinorAxisLength','Centroid','Orientation');
end
Your wording is confusing and I don't know if this is what you're looking for. Try assigning your variables in matrix form (please keep in mind I've never worked with image manipulation so my indexing could be very wrong):
for i=1:16
bin_RD(:,:,i) = imbinarize(rightDam(:,:,i),T_RD(i));
end
You can use an operation like this to process your bin_RD variable as well. You wouldn't even have to leave the loop.
for i=1:16
bin_RD(:,:,i) = imbinarize(rightDam(:,:,i),T_RD(i));
roi(:,:,i) = bwareaopen(bin_RD(:,:,i), 25);
graindata = regionprops('table',roi(:,:,i),'Area','EquivDiameter','MajorAxisLength','MinorAxisLength','Centroid','Orientation');
end
One last piece of advice: I used i=1:16, but if you ever want to use this code again on a situation where you might have 5, 22, 100, etc images, use for i=1:length(T_RD) or something like that and you won't have to change it every time.

regionprops returning single result

I do not understand the function 'regionprops' properly. For example if I create a binary matrix with three different areas, it only gives me a single centerpoint as output:
a = zeros(100,100);
a(1:49,1:49) = 1;
a(1:25,75:100) = 1;
a(51:100,51:100)= 1;
spy(a)
regionprops(a,'Centroid')
But if I add the line
a=bwmorph(a,'erode',0);
which does absolutely nothing, I get three different center points as output, one for each area. Why do they give different outputs and is it really necesarry to add a useless line of code?
The input to regionprops should be a logical array. If it's not, then it's assumed that the input is a labels matrix, as such it's processed as if all of the 1 values are part of the same object.
You can fix this by explicitly converting it to a logical matrix
regionprops(logical(a), 'Centroid') % or regionprops(a == 1, 'Centroid')
The better option may be to make a a logical to begin with by using false rather than zeros to construct a.
a = false(100, 100);
a(1:49,1:49) = 1;
a(1:25,75:100) = 1;
a(51:100,51:100)= 1;
The reason why the no-op erode causes it to work, is that the output of bwmorph is a logical matrix.

In an assignment A(I) = B, the number of elements in B and I must be the same

This is my code in Matlab: How could I get all values of all 5 images saved? This code only returns the last image! I tried using IM(l) but it gives me an error: In an assignment A(I) = B, the number of elements in B and I must be the same.
Amount_measurements = 5;
IM=zeros(2097152,1);
l=1;
for l=(1:Amount_measurements)
if l < 9
%index = double(0)+double(0)+double(l+1);
index = strcat(num2str(double(0)),num2str(double(0)),num2str(double(l+1)));
elseif l < 99
index = double(0)+double(l+1);
else
index = double(l+1);
end
file_name1='trial.nii.gz';
%disp(file_name1);
jesu=load_nii(file_name1);
[x,y,z] = meshgrid(1:256,1:256,1:256);
[lx,ly,lz] = meshgrid(1:2:256,1:2:256,1:2:256);
newImage = interp3(x,y,z,jesu.img,lx,ly,lz);
IM= newImage(:);
end
I want the values newImage(:) to be stored as IM1=newImage(:) IM2=newImage(:) IM3=newImage(:) IM4=newImage(:) so on... How could I go about with it?
Since you mentioned wanting a variable-length version of IM1=newImage(:) IM2=newImage(:) IM3=newImage(:) IM4=newImage(:), you're looking for a cell array. Try
IM{l} = newImage;
instead of
IM(l) = newImage(:);
The important difference is the use of braces rather than parentheses. Use a right-hand side ofnewImage(:) if you want to reshape into a vector, just newImage if you want to preserve it as a matrix.
By using IM(l) you're trying to add an entire column vector (newImage(:)) to a single element (the l-th element) in the array IM, that's why Matlab throws the error.
You should consider concatenation: since newImage(:) is a column-vector, replace
IM= newImage(:);
with
IM=[IM newImage(:)];
but at the top of the script you should also initialize IM as
IM=[];
At the end of the loop, the resulting IM will have Amount_measurements columns where 1 column = 1 newImage(:).
Note #1: this will only work if newImage(:) always has the same length.
Note #2: if you know a priori how long the vector newImage(:) is and, again, by assuming that its length never changes, you should consider preallocating the IM matrix by replacing IM=[]; with IM=zeros(X,Amount_measurements); where X is the number of elements in newImage(:). Finally, regarding the concatenation stage, you should replace IM=[IM newImage(:)]; with IM(:,l)=newImage(:).
Note #3: as instead, if the size of newImage(:) can change you cannot rely on preallocation and matrices, but you must use cell arrays: the last instruction in your loop should be IM{l}=newImage(:);.

Matlab get vector of specific pixels

I am pretty new to Matlab and encountered a problem when working with images.
I want to get a pixel that is in a specific colour (blue) in the following image:
image
My current code looks something like this:
function p = mark(image)
%// display image I in figure
imshow(image);
%// first detect all blue values higher 60
high_blue = find(image(:,:,3)>60);
%cross elements is needed as an array later on, have to initialize it with 0
cross_elements = 0;
%// in this iteration the marked values are reduced to the ones
%where the statement R+G < B+70 applies
for i = 1:length(high_blue)
%// my image has the size 1024*768, so to access the red/green/blue values
%// i have to call the i-th, i+1024*768-th or i+1024*768*2-th position of the "array"
if ((image(high_blue(i))+image(high_blue(i)+768*1024))<...
image(high_blue(i)+2*768*1024)+70)
%add it to the array
cross_elements(end+1) = high_blue(i);
end
end
%// delete the zero element, it was only needed as a filler
cross_elements = cross_elements(cross_elements~=0);
high_vector = zeros(length(cross_elements),2);
for i = 1:length(cross_elements)
high_vector(i,1) = ceil(cross_elements(i)/768);
high_vector(i,2) = mod(cross_elements(i), 768);
end
black = zeros(768 ,1024);
for i = 1:length(high_vector)
black(high_vector(i,2), high_vector(i,1)) = 1;
end
cc = bwconncomp(black);
a = regionprops(cc, 'Centroid');
p = cat(1, a.Centroid);
%// considering the detection of the crosses:
%// RGB with B>100, R+G < 100 for B<150
%// consider detection in HSV?
%// close the figure
%// find(I(:,:,3)>150)
close;
end
but it is not optimized for Matlab, obviously.
So i was wondering if there was a way to search for pixels with specific values,
where the blue value is larger than 60 (not hard with the find command,
but at the same time the values in the red and green area not too high.
Is there a command I am missing?
Since English isn't my native language, it might even help if you gave me some suitable keywords for googling ;)
Thanks in advance
Based on your question at the end of the code, you could get what you want in a single line:
NewImage = OldImage(:,:,1) < SomeValue & OldImage(:,:,2) < SomeValue & OldImage(:,:,3) > 60;
imshow(NewImage);
for example, where as you see you provide a restriction for each channel using logical operators, that you can customize of course (eg. using | as logical OR). Is this what you are looking for? According to your code you seem to be looking for specific regions in the image like crosses or coins is that the case? Please provide more details if the code I gave you is completely off the track :)
Simple example:
A = imread('peppers.png');
B = A(:,:,3)>60 & A(:,:,2)<150 & A(:,:,1) < 100;
figure;
subplot(1,2,1);
imshow(A);
subplot(1,2,2)
imshow(B);
Giving this:

Different function returns from command line and within function

I have an extremely bizzare situation: I have a function in MATLAB which calls three other main functions and produces two figures for me. The function reads in an input jpeg image, crops it, segments it using kmeans clustering, and outputs 2 figures to the screen - the original image and the clustered image with the cluster centers indicated. Here is the function in MATLAB:
function [textured_avg_x photo_avg_x] = process_database_images()
clear all
warning off %#ok
type_num_max = 3; % type is 1='texture', 2='graph', or 3='photo'
type_num_max = 1;
img_max_num_photo = 100; % 400 photo images
img_max_num_other = 100; % 100 textured, and graph images
for type_num = 1:2:type_num_max
if(type_num == 3)
img_num_max = img_max_num_photo;
else
img_num_max = img_max_num_other;
end
img_num_max = 1;
for img_num = 1:img_num_max
[type img] = load_image(type_num, img_num);
%img = imread('..\images\445.jpg');
img = crop_image(img);
[IDX k block_bounds features] = segment_image(img);
end
end
end
The function segment_image first shows me the color image that was passed in, performs kmeans clustering, and outputs the clustered image. When I run this function on a particular image, I get 3 clusters (which is not what I expect to get).
When I run the following commands from the MATLAB command prompt:
>> img = imread('..\images\texture\1.jpg');
>> img = crop_image(img);
>> segment_image(img);
then the first image that is displayed by segment_image is the same as when I run the function (so I know that the clustering is done on the same image) but the number of clusters is 16 (which is what I expect).
In fact, when I run my process_database_images() function on my entire image database, EVERY image is evaluated to have 3 clusters (this is a problem), whereas when I test some images individually, I get in the range of 12-16 clusters, which is what I prefer and expect.
Why is there such a discrepancy? Am I having some syntax bug in my process_database_images() function? If more code is required from me (i.e. segment_images function, or crop_image function), please let me know.
Thanks.
EDIT:
I found the source of the problem. In my load_image function, after I call img = imread(filename), I convert the image to double: `img = im2double(img);'. When I comment this line out, I get the desired result. Anyone know why this happens? (and also how I can 'close' this question since I have located the problem).
clear all at the top of your function is unnecessary and may be the source of your trouble.
Also, turning off all warnings is a bad idea since it may mask other problems.
Let's look at this code, simplified by removing redundant code or unused code:
function [textured_avg_x photo_avg_x] = process_database_images()
type_num_max = 1;
img_max_num_photo = 100; % 400 photo images
img_max_num_other = 100; % 100 textured, and graph images
for type_num = 1:2:type_num_max %% 1:2:1 => 1
img_num_max = 1; %This nullfiies everything in the if block above anyways
for img_num = 1:img_num_max %% 1:1 => 1
[type img] = load_image(type_num, img_num); %% Input (1,1)
img = crop_image(img);
[IDX k block_bounds features] = segment_image(img);
end
end
end
It looks like this code runs through the double nested for loop exactly once, maybe that is why you get only one answer, three clusters.
Try calling your function on the command line with the same amount of return values as in the function you wrote. Instead of
>> segment_image(img);
Try:
>> [IDX k block_bounds features] = segment_image(img);
Functions in Matlab check how many return values are expected, and may behave differently depending on that.