Make strip of nan in a matrice matlab - matlab

I have an image size (m x n x 4) I want to make strip of 0 or NaNon it. I want the strips to be 4 pixels wide and having a space of about 30 pixels between them. That is when I display the image in RGB I have strips of NaN. Can somebody help me out with this, please?

I interpreted you question as "how can I repeatedly draw black lines with a given width and a specified offset over an image".
img = imread('peppers.png');
height = size(img,1);
strip_width = 4;
strip_offset = 30;
line_start_idx = 0:(strip_width+strip_offset):height;
line_idx = ndgrid(line_start_idx,1:strip_width)';
line_idx = line_idx(:);
line_add = repmat(1:strip_width,1,length(line_start_idx))';
line_idx = line_idx + line_add;
img(line_idx,:,:) = 0;
imshow(img)

Related

Fill gaps in binary leaf image occured from segmentation preserving leaf teeth shape

after leaf segmentation i got the following binary image:
Is there a way to fill the gaps caused by the similiarity of the veins with the background? I've tried to use imclose, or imdilate etc but it affects teeth shape. I can't find out how to fill these gaps without affecting teeth shape.
You may try bwfill(I, 'hols'), with out without imclose:
I = imbinarize(rgb2gray(imread('leaf.jpg')));
I = I(3:end-4, 1:end-8); %Remove white frame
J = imclose(I, ones(2)); %Minor affect the teeth shape (result looks better with imclose).
K = bwfill(J, 'hols'); %Fill the black hols
Result:
In case you want to fill the "vein gaps", you can try the following approach:
I = imbinarize(rgb2gray(imread('leaf.jpg')));
I = I(3:end-4, 1:end-8); %Remove white frame
I = bwfill(I, 'hols'); %Fill small black hols.
J = imerode(imdilate(I, strel('disk',5)), strel('disk',10)); %Dilate with radius 5 and erode with 10
T = (I == 0) & (J == 1); %Create mask with 1 where I is black and J is white "vein mask".
K = I;
K(T) = 1; %Fill "vein mask" in I with white.
K = bwfill(K, 'hols'); %Fill small black hols (fill tiny holds left).
Result:

Why can't I colour my segmented region from the original image

I have the following code:
close all;
star = imread('/Users/name/Desktop/folder/pics/OnTheBeach.png');
blrtype = fspecial('average',[3 3]);
blurred = imfilter(star, blrtype);
[rows,cols,planes] = size(star);
R = star(:,:,1); G = star(:,:,2); B = star(:,:,3);
starS = zeros(rows,cols);
ind = find(R > 190 & R < 240 & G > 100 & G < 170 & B > 20 & B < 160);
starS(ind) = 1;
K = imfill(starS,'holes');
stats = regionprops(logical(K), 'Area', 'Solidity');
ind = ([stats.Area] > 250 & [stats.Solidity] > 0.1);
L = bwlabel(K);
result = ismember(L,find(ind));
Up to this point I load an image, blur to filter out some noise, do colour segmentation to find the specific objects which fall in that range, then create a binary image that has value 1 for the object's colour, and 0 for all other stuff. Finally I do region filtering to remove any clutter that was left in the image so I'm only left with the objects I'm looking for.
Now I want to recolour the original image based on the segmentation mask to change the colour of the starfish. I want to create Red,Green,Blue channels, assign value to them then lay the mask over the image. (To have red starfishes for example)
red = star;
red(starS) = starS(:,:,255);
green = star;
green(starS) = starS(:,:,0);
blue = star;
blue(starS) = star(:,:,0);
out = cat(3, red, green, blue);
imshow(out);
This gives me an error: Index exceeds matrix dimensions.
Error in Project4 (line 28)
red(starS) = starS(:,:,255);
What is wrong with my current approach?
Your code is kinda confusing... I don't understand whether the mask you want to use is starS or result since both look like 2d indexers. In your second code snippet you used starS, but the mask you posted in your question is result.
Anyway, no matter what your desired mask is, all you have to do is to use the imoverlay function. Here is a small example based on your code:
out = imoverlay(star,result,[1 0 0]);
imshow(out);
and here is the output:
If the opaque mask of imoverlay suggested by Tommaso is not what you're after, you can modify the RGB values of the input to cast a hue over the selected pixels without saturating them. It is only slightly more involved.
I = find(result);
gives you an index of the pixels in the 2D image. However, star is 3D. Those indices will point at the same pixels, but only at the first 2D slice. That is, if I points at pixel (x,y), it is equivalently pointing to pixel (x,y,1). That is the red component of the pixel. To index (x,y,2) and (x,y,2), the green and blue components, you need to increment I by numel(result) and 2*numel(result). That is, star(I) accesses the red component of the selected pixels, star(I+numel(result)) accesses the green component, and star(I+2*numel(result)) accesses the blue component.
Now that we can access these values, how do we modify their color?
This is what imoverlay does:
I = find(result);
out = star;
out(I) = 255; % red channel
I = I + numel(result);
out(I) = 0; % green channel
I = I + numel(result);
out(I) = 0; % blue channel
Instead, you can increase the brightness of the red proportionally, and decrease the green and blue. This will change the hue, increase saturation, and preserve the changes in intensity within the stars. I suggest the gamma function, because it will not cause strong saturation artefacts:
I = find(result);
out = double(star)/255;
out(I) = out(I).^0.5; % red channel
I = I + numel(result);
out(I) = out(I).^1.5; % green channel
I = I + numel(result);
out(I) = out(I).^1.5; % blue channel
imshow(out)
By increasing the 1.5 and decreasing the 0.5 you can make the effect stronger.

loop over array matrix matlab

I am detecting circles in an image. I return circle radii and X,Y of the axis. I know how to crop 1 circle no problem with formula:
X-radius, Y-radius, width=2*r,height=2*r using imcrop.
My problem is when I get returned more than 1 circle.
I get returned circle radii in an array radiiarray.
I get returned circle centers in centarray.
When i disp(centarray), It looks like this:
146.4930 144.4943
610.0317 142.1734
When I check size(centarray) and disp it i get:
2 2
So I understand first column is X and second is Y axis values. So first circle center would be 146,144.
I made a loop that works for only 1 circle. "-------" is where I'm unsure what to use to get:
note: radius = r
1st circle)
X = centarray(1)-r;
Y = centarray(3)-r;
Width =2*r;
Width =2*r;
2nd circle)
X = centarray(2);
Y = centarray(4);
Width =2*r;
Width =2*r;
How would I modify the "------" parts for my code? I also would like that if there are 3+ circles the loop would work as Im getting sometimes up to 9 circles from an image.
B = imread('p5.tif');
centarray = [];
centarray = [centarray,centers];
radiiarray = [];
radiiarray = [radiiarray,radii];
for j=1:length(radiiarray)
x = centarray((------))-radiiarray(j); %X value to crop
y = centarray((------))-radiiarray(j); %Y value to crop
width = 2*radiiarray(j); %WIDTH
height = 2*radiiarray(j); %HEIGHT
K = imcrop(B, [x y width height]);
end
My full code, which doesnt work, as I realized why when i saw the way values are stored...:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DETECT + GET X Y WIDTH HEIGHT OF CIRCLES
I = imread('p5.tif');
subplot(2,2,1);imshow(I);title('Original Image');
%sharpen edges
B = imsharpen(I);
subplot(2,2,2);imshow(B);title('sharpened edges');
%find circles
Img = im2bw(B(:,:,3));
minRad = 20;
maxRad = 90;
[centers, radii] = imfindcircles(Img, [minRad maxRad], ...
'ObjectPolarity','bright','sensitivity',0.84);
imagesc(Img);
viscircles(centers, radii,'Color','green');
%nuber of circles found
%arrays to store values for radii and centers
centarray = [];
centarray = [centarray,centers];
radiiarray = [];
radiiarray = [radiiarray,radii];
sc = size(centarray);
disp(sc)
disp(centarray)
disp(radiiarray)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%CROP USING VALUE FROM ARRAYS NUMBER OF TIMES THERE ARE CENTERS(number of
%circles)
for j=1:length(radiiarray)
x = centarray((2*j)-1)-radiiarray(j); %X value to crop
y = centarray((2*j))-radiiarray(j); %Y value to crop
width = 2*radiiarray(j); %WIDTH
height = 2*radiiarray(j); %HEIGHT
disp(x)
disp(y)
disp(centarray)
%crop using values
K = imcrop(B, [x y width height]);
%togray
gray = rgb2gray(K);
subplot(2,2,3);imshow(K);title('cropped before bw');
Icorrected = imtophat(gray, strel('disk', 15));
%to black and white
black = im2bw(Icorrected);
subplot(2,2,4);imshow(black);title('sharpened edges');
%read
results = ocr(black);
number = results.Text;
%display value
disp(number)
end
Any help on how to create this kind of loop is appreciated as I just have no more ideas or cant find answer to this..
EDIT
SOLUTION
Hi, answer is to treat matrix as 2 dimensional.
for j=1:length(radiiarray)
x=centarray(j,1)
y=centarray(j,2)
width = radiiarray(j)
height = radiiarray(j)
end
as j increases values update correctly now.
answer is to treat matrix as 2 dimensional.
for j=1:length(radiiarray)
x=centarray(j,1)
y=centarray(j,2)
width = radiiarray(j)
height = radiiarray(j)
end
as j increases values update correctly now.
Thanks for #beaker for his comment! Thats why I figured it out

Stretching an ellipse in an image to form a circle

I want to stretch an elliptical object in an image until it forms a circle. My program currently inputs an image with an elliptical object (eg. coin at an angle), thresholds and binarizes it, isolates the region of interest using edge-detect/bwboundaries(), and performs regionprops() to calculate major/minor axis lengths.
Essentially, I want to use the 'MajorAxisLength' as the diameter and stretch the object on the minor axis to form a circle. Any suggestions on how I should approach this would be greatly appreciated. I have appended some code for your perusal (unfortunately I don't have enough reputation to upload an image, the binarized image looks like a white ellipse on a black background).
EDIT: I'd also like to apply this technique to the gray-scale version of the image, to examine what the stretch looks like.
code snippet:
rgbImage = imread(fullFileName);
redChannel = rgbImage(:, :, 1);
binaryImage = redChannel < 90;
labeledImage = bwlabel(binaryImage);
area_measurements = regionprops(labeledImage,'Area');
allAreas = [area_measurements.Area];
biggestBlobIndex = find(allAreas == max(allAreas));
keeperBlobsImage = ismember(labeledImage, biggestBlobIndex);
measurements = regionprops(keeperBlobsImage,'Area','MajorAxisLength','MinorAxisLength')
You know the diameter of the circle and you know the center is the location where the major and minor axes intersect. Thus, just compute the radius r from the diameter, and for every pixel in your image, check to see if that pixel's Euclidean distance from the cirlce's center is less than r. If so, color the pixel white. Otherwise, leave it alone.
[M,N] = size(redChannel);
new_image = zeros(M,N);
for ii=1:M
for jj=1:N
if( sqrt((jj-center_x)^2 + (ii-center_y)^2) <= radius )
new_image(ii,jj) = 1.0;
end
end
end
This can probably be optimzed by using the meshgrid function combined with logical indices to avoid the loops.
I finally managed to figure out the transform required thanks to a lot of help on the matlab forums. I thought I'd post it here, in case anyone else needed it.
stats = regionprops(keeperBlobsImage, 'MajorAxisLength','MinorAxisLength','Centroid','Orientation');
alpha = pi/180 * stats(1).Orientation;
Q = [cos(alpha), -sin(alpha); sin(alpha), cos(alpha)];
x0 = stats(1).Centroid.';
a = stats(1).MajorAxisLength;
b = stats(1).MinorAxisLength;
S = diag([1, a/b]);
C = Q*S*Q';
d = (eye(2) - C)*x0;
tform = maketform('affine', [C d; 0 0 1]');
Im2 = imtransform(redChannel, tform);
subplot(2, 3, 5);
imshow(Im2);

Matlab fill shapes by white

As you see, I have shapes and their white boundaries. I want to fill the shapes in white color.
The input is:
I would like to get this output:
Can anybody help me please with this code? it doesn't change the black ellipses to white.
Thanks alot :]]
I = imread('untitled4.bmp');
Ibw = im2bw(I);
CC = bwconncomp(Ibw); %Ibw is my binary image
stats = regionprops(CC,'pixellist');
% pass all over the stats
for i=1:length(stats),
size = length(stats(i).PixelList);
% check only the relevant stats (the black ellipses)
if size >150 && size < 600
% fill the black pixel by white
x = round(mean(stats(i).PixelList(:,2)));
y = round(mean(stats(i).PixelList(:,1)));
Ibw = imfill(Ibw, [x, y]);
end;
end;
imshow(Ibw);
Your code can be improved and simplified as follows. First, negating Ibw and using BWCONNCOMP to find 4-connected components will give you indices for each black region. Second, sorting the connected regions by the number of pixels in them and choosing all but the largest two will give you indices for all the smaller circular regions. Finally, the linear indices of these smaller regions can be collected and used to fill in the regions with white. Here's the code (quite a bit shorter and not requiring any loops):
I = imread('untitled4.bmp');
Ibw = im2bw(I);
CC = bwconncomp(~Ibw, 4);
[~, sortIndex] = sort(cellfun('prodofsize', CC.PixelIdxList));
Ifilled = Ibw;
Ifilled(vertcat(CC.PixelIdxList{sortIndex(1:end-2)})) = true;
imshow(Ifilled);
And here's the resulting image:
If your images are all black&white, and you have the image processing toolkit, then this looks like what you need:
http://www.mathworks.co.uk/help/toolbox/images/ref/imfill.html
Something like:
imfill(image, [startX, startY])
where startX, startY is a pixel in the area that you want to fill.