extract colored region - matlab

I want to extract each colored region in MATLAB after applying SRM segmentation method on a particular image.
I tried the following, but it seems that it extracts regions with different color (not the same color degree only), and with the largest area.
I = imread('./img/bfly.jpg');
imshow(I)
bw = im2bw(I);
imshow(bw)
L = bwlabel(bw);
imshow(L == 0)
props = regionprops(L);
[~,ind] = max([props.Area]);
imshow(L == ind);
Is there a way to extract each color separately?
This is an example image. I want to extract the brown color alone, the green color alone, and so on ...

Since your image appears to have no smooth variations of color, it should be straightforward to separate the colors into different images with unique to convert the image to label matrix (you could do this with rgb2ind also) followed by accumarray:
[Iu,ia,iu] = unique(reshape(I,[],3),'rows');
counts = accumarray(iu,1);
[counts,sortinds] = sort(counts,'descend');
Now say you want the N largest components:
N = 10;
largestLabels = sortinds(1:N);
Then the image for color ii:
mapi = reshape(iu == largestLabels(ii),size(I,1),size(I,2));
numeli = counts(ii)
The corresponding RGB values and the number of pixels of each color:
>> colorRegionSummary = [uint32(Iu(largestLabels,:)) counts(1:N)]
colorRegionSummary =
89 120 23 8206 % green
73 59 42 4370 % dark brown (wing)
64 128 184 2723 % blue (right shade)
105 136 25 2143 % green (bottom right shade)
64 127 178 1667 % blue (top left shade)
170 151 191 1380 % purple
58 132 201 1372 % blue (left shade)
177 130 45 1242 % orange (bottom wing shade)
184 123 50 1193 % orange (top wing shade)
118 114 56 586 % tan (top right)
Note that these are not connected components, just components with the same color. For a given mapi, you can then apply bwlabel to get the connected components for that color.

You could start with encoding the three color arrays (RGB) in a way so that you can merge them into one, two-dimensional array, e.g.
2Dimage = I(:,:,1) + 1e3*I(:,:,2) + 1e6*I(:,:,3)
that way, you get a unique number for each color: R + 1e3*G + 1e6*B. Note that each channel is encoded with a number in the interval [0, 255].
Now you can go and extract the different color regions from the image using
C = unique(2Dimage)
to obtain the unique colors you need to look for and then
for idx = 1:length(C)
find(C(idx)==2Dimage)
end
to locate the different parts of the image. The color can be readily obtained from the original image I at the corresponding locations/indices.

Related

How to set the linewidth for the subgraphs border

As shown in the figure, when I set the linewidth for these subgraphs border
set(gca,'linewidth',1.5)
The linewidth of the lines in the red circle is not consistent
The original code is as follows
clc;clear
nlon = [100:140];
nlat = [20:60];
data = ones(length(nlon),length(nlat));
figure
for k =1:4
subplot(2,2,k)
p=pcolor(nlon,nlat,data');hold on
set(p,'linestyle','none');
fun_fill_AA; % **mask**
axis equal
axis([110 135 30 55])
set(gca,'linewidth',1.5)
end
function fun_fill_AA()
data0=[50 10
140 10
140 60
50 60]
data_lon=data0(:,1);
data_lat=data0(:,2);
fil=fill(data_lon,data_lat,[1 1 1]);
hold on
fil=fill(data_lon,data_lat,[1 1 1]);
fil.EdgeColor='none';
end
How can I make the borders of each subgraph have the same linewidth?
It's better after saving the image to higher resolutions.
left:
saves(gcf,'*.png')
right:
print(gcf,'*.png','-dpng','-r600');%*//600 dpi

Complete partial circles in an image using MATLAB

I have binary images and they have semi or less circles. My aim is to find these circles, make them whole circles and remove all other objects . I found this but it is for MATLAB R2013a. I am using R2011b and it doesn't have the function centers = imfindcircles(A,radius).
How can I do that in MATLAB version R2011b?
Images:
Edit:
My aim is to get whole circle. I show this below for the last image.
Too bad about imfindcircles! One thing I can suggest is to invoke regionprops and specify the 'Area' and 'BoundingBox' flags. regionprops was available in MATLAB for as long as I can remember, so we can certainly use it here.
What this will do is that whatever distinct objects that are seen in the image that are connected, we will find both their areas and their bounding boxes that bound them. After you do this, threshold on the area so that any objects that have a very large area most likely contain circles of interest. Bear in mind that I'm only assuming that you have circles in your image. Should you have any objects that have a large area, this method will extract those out too.
As such, let's read in your image directly from Stack Overflow. When you uploaded the image, it's a RGB image, so I'll have to convert to binary:
im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im_bw = im2bw(im);
Next, call regionprops:
s = regionprops(im_bw, 'Area', 'BoundingBox');
Now, collect all of the areas, and let's take a look at all of the unique areas of all objects seen in this image:
areas = [s.Area].';
unique(areas)
ans =
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
19
20
23
24
25
28
29
38
43
72
73
85
87
250
465
3127
If you take a look at the very end, you'll see that we have an object that has 3127 pixels in it. This probably contains our circle. As such, let's pick out that single element that contains this object:
s2 = s(areas == 3127);
In general, you'll probably have more than one circle in your image, so you should threshold the area to select those potential circles. Something like:
s2 = s(areas > 2000);
Now, let's create a new blank image that is the same size as the original image, then simply use the BoundingBox property to extract out the area that encompasses the circle in the original image and copy it over to the same location in the output image. The BoundingBox field is structured in the following way:
[x y w h]
x and y are the top-left corner of the bounding box. x would be the column and y would be the row. w and h are the width and height of the bounding box. As such, we can use this directly to access our image and copy those pixels over into the output image.
out = false(size(im_bw));
bb = floor(s2.BoundingBox); %// Could be floating point, so floor it
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
This is what I get:
What you should probably do is loop over the circles in case we have more than one. The above code assumes that you detected just one circle. Therefore, do something like this:
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
A small thing to note is that the bounding box encompasses the entire object, but there could also be some noisy pixels that are disconnected that are within that bounding box. You may have to apply some morphology to get rid of those pixels. A binary opening could suffice.
Here's what I get with your other images. I thresholded the area to search for those that have 2000 pixels or more (I did this above):
Just for self-containment and your copy-and-pasting pleasure, here's the code in one segment:
clear all;
close all;
%im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);
s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
imshow(out);
All three images are there in the code. You just have to uncomment whichever one you want to use, comment out the rest, then run the code. It will display an image with all of your detected circles.
Edit
You would like to draw complete circles, instead of extracting the shape themselves. That isn't a problem to do. All you need to do is determine the best "radii" that can be enclosed inside each of the bounding boxes. This is simply the maximum of the width and height of each bounding box, then divide these quantities by 2.
After, create a 2D grid of co-ordinates through meshgrid that is the same size as the original image itself, then create a binary image such that the Euclidean distance between the centre of this bounding box with any point in this 2D grid less than the radius is set to logical true while the other positions are set to logical false.
In other words, do this:
clear all;
close all;
im = imread('http://i.stack.imgur.com/qychC.jpg');
%im = imread('http://i.stack.imgur.com/wQLPi.jpg');
%im = imread('http://i.stack.imgur.com/mZMBA.jpg');
im_bw = im2bw(im);
s = regionprops(im_bw, 'Area', 'BoundingBox');
areas = [s.Area].';
s2 = s(areas > 2000);
out = false(size(im_bw));
for idx = 1 : numel(s2) %// For each potential circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
%// Copy over pixels from original bw image to output
out(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1) = im_bw(bb(2):bb(2)+bb(4)-1, bb(1):bb(1)+bb(3)-1);
end
figure;
imshow(out);
%// Image that contains all of our final circles
out2 = false(size(im_bw));
[X,Y] = meshgrid(1:size(im_bw,2), 1:size(im_bw,1)); %// Find a 2D grid of co-ordinates
for idx = 1 : numel(s2) %// For each circle we have...
bb = floor(s2(idx).BoundingBox); %// Could be floating point, so floor it
cenx = bb(1) + (bb(3) / 2.0); %// Get the centre of the bounding box
ceny = bb(2) + (bb(4) / 2.0);
radi = max(bb(3), bb(4)) / 2; %// Find the best radius
tmp = ((X - cenx).^2 + (Y - ceny).^2) <= radi^2; %// Draw our circle and place in a temp. image
out2 = out2 | tmp; %// Add this circle on top of our output image
end
figure;
imshow(out2);
This script now shows you the original extracted shapes, and the best "circles" that describes these shapes in two separate figures. Bear in mind that this is a bit different than what I showed you previously with one circle. What I have to do now is allocate a blank image, then incrementally add each circle to this new image. For each circle, I create a temporary binary image that has just a circle I'm looking for, then I add this on top of the new image. At the end, we will show all of the circles in the image that are fully drawn as you desire.
This is what I get for the best circle for each of your images:
Good luck!

Colormaps custom using cbfit matlab

Hi I am trying to costomize my colormap according to tick values of the of the colorbar. I defined my own colorbar with 5 colors eg 5 colors from blue to red
cmap_my=[0 0 1;0 1 1;0 1 0; 1 1 0; 1 0 0];
than i would like that the colour changes for every tick i put. By using cbfit the colors are changing according to the ticks if ticks are evenly distributed in the range of 0:40, but my ticks are
h = colorbar;
set(h,'YTick',[5,10,15,22,30,35,40]);
and my range is up to 45. In addition to that the colors i have defined dont show anymore when i use cbfit. Is there a possibility to give certain ranges for colors and eg from 5 to 10 dark blue 10 to 15 light blue 15 to 22 green 22 to 30 lightyellow 30 to 35 yellow 35 to 40 orange and over 40 red and than makes clear cuts at the ticks?
I hope I understood your problem. Here goes one example. You can work from here for you specific colors.
mri=load('mri');
mri=double(mri.D(:,:,1,13));
%making my image within the same range as yours
mri=(mri-min(mri(:)))./(max(mri(:))-min(mri(:)))*45;
figure,imagesc(mri),axis off,axis image,h_bar=colorbar;
%h_map(1) is related with the min(mri), and h_map(end) with max(mri)
h_map=colormap;
min_mri=0;
max_mri=45;
lim=eps*100;
my_map_int=[0-lim,5-lim,5+lim,10-lim,10+lim,40-lim,40+lim,45+lim];
my_map_color=[0,0,0;0,0,0;0,0,1;0,0,1;0,1,0;0,1,0;1,0,0;1,0,0];
new_map_color(:,1)=interp1(my_map_int,my_map_color(:,1),linspace(min_mri,max_mri,64),'nearest');
new_map_color(:,2)=interp1(my_map_int,my_map_color(:,2),linspace(min_mri,max_mri,64),'nearest');
new_map_color(:,3)=interp1(my_map_int,my_map_color(:,3),linspace(min_mri,max_mri,64),'nearest');
figure,imagesc(mri),axis off,axis image
colormap(new_map_color)
colorbar

How to crop rows and columns of pixels out in MATLAB

I have an image with a white border around it, and I need to get rid of the border. There are 20 rows of white pixels above the image, 5 columns of white to the left, 5 of white columns to the right, and 5 rows of white below the image. I wan't to crop the image exactly out of that border, how do I do this in matlab? Thanks for any help you can give!
(The image is a tiff, which is why I can't use an online service for this, they won't let me upload .tiff)
What you need is the built-in MATLAB function imcrop. To use it, specify something like
B = imcrop(A,[xmin ymin width height]);
if A is your original image. First find the dimensions of your image. Say its 800 by 600. Then you are looking to crop a 770 by 580 image so these numbers respectively will be your width and height in the above function. Your x and y would be something like 5 and 20, respectively.
U can use imcrop for this if you have image processing toolbox or you can make new image as follows:
I2 = I(21:end-5, 6:end-5)
For 3 dimensions, you can use:
I2 = I(21:end-5,6:end-5,:)
For example as per your comment:
I = rand(153,1510,3);
size(I); % 153 1510 3
I2 = I(21:end-5,6:end-5,:);
size(I2); % 128 1500 3
newIm = oldIm(20:length(oldIm(:,1))-5,5:length(oldIm(1,:))-5)

Image/Color Comparison in Objective-C

I'm trying to find a way to compare two images.
Let me give you an example so you can better understand: my App will randomize a color (she will randomize a value from 0 to 255 for the R, then for the G and then for the B and the result is a completely random RGB color).
Now the user will take a photo from the camera of the iPhone and the App will comprare the color with the image.
Example: The App select the RGB = 205,133,63 wich is brown: the user will take a picture of a brown detail of a desk. Now I need to compare the brown selected by the iPhone and the brown of the picture and display a result (for example: "the pictures is faithful to 88% compared to the given color").
I found this example in internet, but I can figure out how I can implement this in my App: http://www.youtube.com/watch?v=hWRPn7IsChI
Thanks!!
Marco
There are plenty of ways you can do this. If you want to keep it simple, you can average the colours for your entire image. For the sake of simplicity, let's say your image only has two pixels:
RGB0 = 255, 0, 0 (red)
RGB1 = 0, 0, 0 (black)
Average between the two will be
RGB_AVG = 128, 0, 0 (dark red)
Now you can calculate the difference between this average and the selected colour 205, 133, 63. This too you can do in many different ways. Here is one:
R = 205 - 128 = 80
G = 133 - 0 = 133
B = 63 - 0 = 63
Total = 80 + 133 + 63 = 276
Total score = (756 - 276) / 756 = 63.5%
This is just one way, you could collect all colours in a dictionary and count them if you need it to be super accurate. It all depends on what you want to achieve.
Btw: Reassure your numbers don't end up being higher if they are higher than your sample color. Use ABS or whatever method you want. The above is just an example.