Determine a regions average in MATLAB - image

I need some help with RGB capture in a image.
I am using impixel to manualy get RGB from a picture, but i would like to create a grid of let's say 20x20 px boxes where it will automatically tell me for each box a RGB value. So in a picture lets say i have 20 boxes it will tell me 20 RGB values. Yeah an if there is 20% or more of white space that it ignores that rgb box.
Can you point me to some links or give me a general idea how to do this.
Best regards
P.S. image is just a .jpg, the background is white an in the middle there is an item.
UPDATE
This is my code for collecting RGB using impixel
px=impixel(img);
st = num2cell(px,1);
zstup = cellfun(#sum,st);
zred = size(px,1);
rez = bsxfun(#rdivide,zstup,zred);
trez=round(rez);
What I want to do is :
http://imageshack.us/photo/my-images/696/exsample.jpg/
So every box like A1, A2, and so on will return RGB value like trez in my code.
So in my code i save my trez data in a table and it is like in excell lets say 220 | 23 | 34, now if i do that to another fruit i will have
220 | 23 | 34
123 | 212| 78
and so on...
Returning to automatization, A7 and A 15 would not be good RGB canditades because they have more then 50% white area so everything that has 20% white will be ignored.
So A31 is good and the RGB value needs to be saved.
So all in all here i would have my be 6 RGB values that would have to be automatically saved like the above example.
I know how to save to table i just need help for the gathering rgb values in every box.

Depending on your exact needs I see two solutions:
Downscale the image using impyramid(img, 'reduce'). This gives you a smaller image consisting of average values of the original image. Then do what you did before to access single pixels. Repeat as often as necessary to get 2x2, 4x4, 8x8 or larger "boxes".
Or you could use define a box (or arbitrary shape) as a matrix of ones and zeros and use the regionprops function in order to get information about the images content depending on the fields containing ones:
roi = zeros(size(img))
roi(1:10,1:10) = 1;
r = regionprops(roi, img, 'MeanIntensity')
average = r.MeanIntensity

This is my complete code for automatic color grabing from pictures in folder. So the program asks you to chose a folder and after that you get a table full of information about color and roundess. I am using this code to get color from fruits that have white background . It does everything by itself. Hope it helps someone.
clear all;
clc;
uiwait(msgbox('Chose the folder where your pictures are kept. Click OK to continue..'));
% Opening the folder
folder = uigetdir(pwd);
filePattern = fullfile(folder, '*.jpg');
jpegFiles = dir(filePattern);
for k = 1:length(jpegFiles)
baseFileName = jpegFiles(k).name;
fullFileName = fullfile(folder, baseFileName);
[pathstr, name, ext] = fileparts(fullFileName);
naziv_voca=name;
%Taking RGB color
slika = imread(fullFileName);
[redovi stupci RGBboje] = size(slika);
red_ink = floor(redovi/10);
stup_ink = floor(stupci/10);
r = 1;
c = 1;
for stupac = 1 : stup_ink : stupci
for red = 1 : red_ink : redovi
red1 = red;
red2 = red1 + red_ink;
stupac1 = stupac;
stupac2 = stupac1 + stup_ink;
red2 = min(red2, redovi);
stupac2 = min(stupac2, stupci);
crveniS = slika(red1:red2, stupac1:stupac2, 1);
zeleniS = slika(red1:red2, stupac1:stupac2, 2);
plaviS = slika(red1:red2, stupac1:stupac2, 3);
crvena(r,c) = mean2(crveniS);
zelena(r,c) = mean2(zeleniS);
plava(r,c) = mean2(plaviS);
r = r + 1;
if r >redovi
r = 1;
end
end
c = c + 1;
if c >1
c = 1;
end
end
RGB=[crvena,zelena,plava];
bijela=[255 255 255];
tolerancija = 50;
rez = RGB((abs(RGB(:,1)-bijela(1)) > tolerancija) | (abs(RGB(:,2)-bijela(2)) > tolerancija),:);
trez=round(rez);
%Taking shape
pic = rgb2gray(slika);
threshold = graythresh(pic);
bw = im2bw(pic,threshold);
fbw = ones(size(bw))-imfill(ones(size(bw))-bw);
invImg = ~fbw;
f = bwlabel(invImg);
S = regionprops(f,'Area','Perimeter','centroid');
Thr=100;
S=S([S.Area]>Thr);
score = (min(sqrt([S.Area]),[S.Perimeter]/4)./(max(sqrt([S.Area]), [S.Perimeter]/4))).^2;
score=max(score);
%Inserting data into table and creating data
if exist('tablica.mat','file')
vel=size(trez,1);
for z=1:vel
s=load('tablica');
olddata=s.data;
temp=trez(z,:);
dataCell= [naziv_voca,num2cell(temp),num2cell(score)];
data=[olddata;dataCell];
save('tablica.mat','-append','data');
end
else
stupac_rgb = num2cell(trez,1);
zstupac = cellfun(#sum,stupac_rgb);
zred = size(trez,1);
rez = bsxfun(#rdivide,zstupac,zred);
trez=round(rez);
data= [naziv_voca,num2cell(trez),num2cell(score)];
save('tablica','data')
end
end
uiwait(msgbox('Your information is saved'));

Related

Matlab - Scale Colorbar of Image

How can I scale the colorbar axis of a false color image?
I read this post,and copied the code but it seems not to work correctly:
MATLAB Colorbar - Same colors, scaled values
Please see the two images below. In the first (without the scaling) the coloraxis goes
[1 2 3 4 5 6]*10^4
In the second image, it goes
[0.005 0.01 0.015 0.02 0.025]
The correct scaling (with C = 100000) would be
[0.1 0.2 0.3 0.4 0.5 0.6]
Without scaling
Wrong scaling
I want that the coloraxis is scaled by 1/C and I can freely choose C, so that when the pixel value = 10^4 and C=10^6 the scale should show 10^-2.
The reason why I multiply my image first by C is to get more decimals places, because all values below 1 will be displayed as zero without the C scaling.
When I run the code I get yticks as a workspace variable with the following values:
[500 1000 1500 2000 2500]
My code:
RGB = imread('IMG_0043.tif');% Read Image
info = imfinfo('IMG_0043.CR2'); % get Metadata
C = 1000000; % Constant to adjust image
x = info.DigitalCamera; % get EXIF
t = getfield(x, 'ExposureTime');% save ExposureTime
f = getfield(x, 'FNumber'); % save FNumber
S = getfield(x, 'ISOSpeedRatings');% save ISOSpeedRatings
date = getfield(x,'DateTimeOriginal');
I = rgb2gray(RGB); % convert Image to greyscale
K = 480; % Kamerakonstante(muss experimentel eavaluiert werden)
% N_s = K*(t*S)/power(f,2))*L
L = power(f,2)/(K*t*S)*C; %
J = immultiply(I,L); % multiply each value with constant , so the Image is Calibrated to cd/m^2
hFig = figure('Name','False Color Luminance Map', 'ToolBar','none','MenuBar','none');
% Create/initialize default colormap of jet.
cmap = jet(16); % or 256, 64, 32 or whatever.
% Now make lowest values show up as black.
cmap(1,:) = 0;
% Now make highest values show up as white.
cmap(end,:) = 1;
imshow(J,'Colormap',cmap) % show Image in false color
colorbar % add colorbar
h = colorbar; % define colorbar as variable
y_Scl = (1/C);
yticks = get(gca,'YTick');
set(h,'YTickLabel',sprintfc('%g', [yticks.*y_Scl]))
ylabel(h, 'cd/m^2')% add unit label
title(date); % Show date in image
caxis auto % set axis to auto
datacursormode on % enable datacursor
img = getframe(gcf);
nowstr = datestr(now, 'yyyy-mm-dd_HH_MM_SS');
folder = 'C:\Users\Taiko\Desktop\FalseColor\';
ImageFiles = dir( fullfile(folder, '*.jpg') );
if isempty(ImageFiles)
next_idx = 1;
else
lastfile = ImageFiles(end).name;
[~, basename, ~] = fileparts(lastfile);
file_number_str = regexp('(?<=.*_)\d+$', basename, 'match' );
last_idx = str2double(file_number_str);
next_idx = last_idx + 1;
end
newfilename = fullfile( folder, sprintf('%s_%04d.jpg', nowstr, next_idx) );
imwrite(img.cdata, newfilename);
Problems:
1) You are getting YTick of the figure (gca) but not the color bar. That would give you the "pixel" coordinates of the graph, instead of the actual values. Use yticks = get(h,'YTick');.
2) caxis auto Should come before overwriting YTicks (and after enabling the color bar); otherwise the scale and ticks will mismatch.
3) Do you mean C = 100000?
Result:

Octave imwrite loses grayscale

I am using Octave 3.6.4 to process an image and store it afterwards. The image I read is grayscale, and after calculations the matrix should be of the same type. However, if I open the stored image, there are no gray pixels. There are only black and white ones and the gray ones got lost. They are essentially all white.
Here is the processing code:
function aufgabe13()
[img, map, alpha] = imread("Buche.png");
[imax, jmax] = size(img);
a = 0.7;
M = 255 * ones(imax,jmax + round(imax * a));
for i = 1:imax
begin = round((imax-i)*a);
M(i,begin +1 : begin + jmax) = img(i,:);
end
imwrite(M, 'BucheScherung.png', 'png');
end
So what am I doing wrong?
The reason why is because M is a double matrix so the values are expected to be between [0,1] when representing an image. Because your values in your image are between [0,255] when read in (type uint8), a lot of the values are white because they're beyond the value of 1. What you should do is convert the image so that it is double precision and normalized between [0,1], then proceed as normal. This can be done with the im2double function.
In other words, do this:
function aufgabe13()
[img, map, alpha] = imread("Buche.png");
img = im2double(img); % Edit
[imax, jmax] = size(img);
a = 0.7;
M = ones(imax,jmax + round(imax * a)); % Edit
for i = 1:imax
begin = round((imax-i)*a);
M(i,begin +1 : begin + jmax) = img(i,:);
end
imwrite(M, 'BucheScherung.png', 'png');
end

How to find more than one matching pattern using Normalized Correalation

I'm using normxcorr2 to find the area that exactly match with my pattern and i also want to find the other area(in the red rectangle) that is look like the pattern. I think it will be works if i can find the next maximum and so on and that value must not in the first maximum area or the first one that it has been detected but i can't do it. Or if you have any idea that using normxcorr2 to find the others area please advise me, I don't have any idea at all.
Here's my code. I modified from this one http://www.mathworks.com/products/demos/image/cross_correlation/imreg.html
onion = imread('pattern103.jpg'); %pattern image
peppers = imread('rsz_1jib-159.jpg'); %Original image
onion = rgb2gray(onion);
peppers = rgb2gray(peppers);
%imshow(onion)
%figure, imshow(peppers)
c = normxcorr2(onion,peppers);
figure, surf(c), shading flat
% offset found by correlation
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = ind2sub(size(c),imax(1));
corr_offset = [(xpeak-size(onion,2))
(size(onion,1)-ypeak)]; %size of window show of max value
offset = corr_offset;
xoffset = offset(1);
yoffset = offset(2);
xbegin = round(xoffset+1); fprintf(['xbegin = ',num2str(xbegin)]);fprintf('\n');
xend = round(xoffset+ size(onion,2));fprintf(['xend = ',num2str(xbegin)]);fprintf('\n');
ybegin = round(yoffset+1);fprintf(['ybegin = ',num2str(ybegin)]);fprintf('\n');
yend = round(yoffset+size(onion,1));fprintf(['yend = ',num2str(yend)]);fprintf('\n');
% extract region from peppers and compare to onion
extracted_onion = peppers(ybegin:yend,xbegin:xend,:);
if isequal(onion,extracted_onion)
disp('pattern103.jpg was extracted from rsz_org103.jpg')
end
recovered_onion = uint8(zeros(size(peppers)));
recovered_onion(ybegin:yend,xbegin:xend,:) = onion;
figure, imshow(recovered_onion)
[m,n,p] = size(peppers);
mask = ones(m,n);
i = find(recovered_onion(:,:,1)==0);
mask(i) = .2; % try experimenting with different levels of
% transparency
% overlay images with transparency
figure, imshow(peppers(:,:,1)) % show only red plane of peppers
hold on
h = imshow(recovered_onion); % overlay recovered_onion
set(h,'AlphaData',mask)

Separating Background and Foreground

I am new to Matlab and to Image Processing as well. I am working on separating background and foreground in images like this
I have hundreds of images like this, found here. By trial and error I found out a threshold (in RGB space): the red layer is always less than 150 and the green and blue layers are greater than 150 where the background is.
so if my RGB image is I and my r,g and b layers are
redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);
by finding coordinates where in red, green and blue the values are greater or less than 150 I can get the coordinates of the background like
[r1 c1] = find(redMatrix < 150);
[r2 c2] = find(greenMatrix > 150);
[r3 c3] = find(blueMatrix > 150);
now I get coordinates of thousands of pixels in r1,c1,r2,c2,r3 and c3.
My questions:
How to find common values, like the coordinates of the pixels where red is less than 150 and green and blue are greater than 150?
I have to iterate every coordinate of r1 and c1 and check if they occur in r2 c2 and r3 c3 to check it is a common point. but that would be very expensive.
Can this be achieved without a loop ?
If somehow I came up with common points like [commonR commonC] and commonR and commonC are both of order 5000 X 1, so to access this background pixel of Image I, I have to access first commonR then commonC and then access image I like
I(commonR(i,1),commonC(i,1))
that is expensive too. So again my question is can this be done without loop.
Any help would be appreciated.
I got solution with #Science_Fiction answer's
Just elaborating his/her answer
I used
mask = I(:,:,1) < 150 & I(:,:,2) > 150 & I(:,:,3) > 150;
No loop is needed. You could do it like this:
I = imread('image.jpg');
redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);
J(:,:,1) = redMatrix < 150;
J(:,:,2) = greenMatrix > 150;
J(:,:,3) = blueMatrix > 150;
J = 255 * uint8(J);
imshow(J);
A greyscale image would also suffice to separate the background.
K = ((redMatrix < 150) + (greenMatrix > 150) + (blueMatrix > 150))/3;
imshow(K);
EDIT
I had another look, also using the other images you linked to.
Given the variance in background colors, I thought you would get better results deriving a threshold value from the image histogram instead of hardcoding it.
Occasionally, this algorithm is a little to rigorous, e.g. erasing part of the clothes together with the background. But I think over 90% of the images are separated pretty well, which is more robust than what you could hope to achieve with a fixed threshold.
close all;
path = 'C:\path\to\CUHK_training_cropped_photos\photos';
files = dir(path);
bins = 16;
for f = 3:numel(files)
fprintf('%i/%i\n', f, numel(files));
file = files(f);
if isempty(strfind(file.name, 'jpg'))
continue
end
I = imread([path filesep file.name]);
% Take the histogram of the blue channel
B = I(:,:,3);
h = imhist(B, bins);
h2 = h(bins/2:end);
% Find the most common bin in the *upper half*
% of the histogram
m = bins/2 + find(h2 == max(h2));
% Set the threshold value somewhat below
% the value corresponding to that bin
thr = m/bins - .25;
BW = im2bw(B, thr);
% Pad with ones to ensure background connectivity
BW = padarray(BW, [1 1], 1);
% Find connected regions in BW image
CC = bwconncomp(BW);
L = labelmatrix(CC);
% Crop back again
L = L(2:end-1,2:end-1);
% Set the largest region in the orignal image to white
for c = 1:3
channel = I(:,:,c);
channel(L==1) = 255;
I(:,:,c) = channel;
end
% Show the results with a pause every 16 images
subplot(4,4,mod(f-3,16)+1);
imshow(I);
title(sprintf('Img %i, thr %.3f', f, thr));
if mod(f-3,16)+1 == 16
pause
clf
end
end
pause
close all;
Results:
Your approach seems basic but decent. Since for this particular image the background is composed of mainly blue so you be crude and do:
mask = img(:,:,3) > 150;
This will set those pixels which evaluate to true for > 150 to 0 and false to 1. You will have a black and white image though.
imshow(mask);
To add colour back
mask3d(:,:,1) = mask;
mask3d(:,:,2) = mask;
mask3d(:,:,3) = mask;
img(mask3d) = 255;
imshow(img);
Should give you the colour image of face hopefully, with a pure white background. All this requires some trial and error.

Matlab - displaying a background image

I'm trying to find the median values for the R,G & B channels of each pixel for each 10th image in a set of 100, to find the background image. My values all seem correct but when i try to display the background at the end of my code it's always white, please help
%// list all the files in some folder
folder = '~/V&R/1/';
filelist = dir(folder);
images = zeros(480,640,3,100);
% images = [];
%// the first two in filelist are . and ..
count = 1;
for i=3:size(filelist,1)
if filelist(i).isdir ~= true
fname = filelist(i).name;
%// if file extension is jpg
if strcmp( fname(size(fname,2)-3:size(fname,2)) ,'.jpg' ) == 1
tmp = imread([folder fname]);
images(:,:,:,count) = tmp;
count = count +1;
end
end
end
background = zeros(480,640,3);
for j=1:480
for i=1:640
tmpR = zeros(1,10);
tmpG = zeros(1,10);
tmpB = zeros(1,10);
for k=1:10
tmpR(k) = images(j,i,1,k*10);
tmpG(k) = images(j,i,2,k*10);
tmpB(k) = images(j,i,3,k*10);
end
background(j,i,1) = floor(median(tmpR));
background(j,i,2) = floor(median(tmpG));
background(j,i,3) = floor(median(tmpB));
end
end
imshow(background)
thanks
The first step is to vectorize your code. Instead of the following block of code:
background = zeros(480,640,3);
for j=1:480
for i=1:640
tmpR = zeros(1,10);
tmpG = zeros(1,10);
tmpB = zeros(1,10);
for k=1:10
tmpR(k) = images(j,i,1,k*10);
tmpG(k) = images(j,i,2,k*10);
tmpB(k) = images(j,i,3,k*10);
end
background(j,i,1) = floor(median(tmpR));
background(j,i,2) = floor(median(tmpG));
background(j,i,3) = floor(median(tmpB));
end
end
write:
subimages = images(:, :, :, 1:10:end);
background = median(subimages, 4);
now as said before, use imshow with the [] option to show your image:
imshow(background, []);
if you still see a white image, then it's possible that you are dealing with a matrix of double values that are not between [0, 1]. Images in Matlab are usually of class double or single with values between 0 and 1, or of class uint8 or uint16 with values between 0, 255 or 0, 65535 respectively. If your values are between 0 and 255 but class(subimages) returns double or single, do the following before using imshow():
subimages = uint8(subimages);
Try
imshow(background,[])
When using imshow, MATLAB needs to set a display range. For single or double grayscale images, the default display range is [0 1]. This means that any value larger than 1 will be represented as white. You can fix this by setting your own display range manually, say
imshow(background,[0 100],
or you can let MATLAB calculate a new display range by doing
imshow(background,[])
which is the same as
imshow(background,[min(background(:)) max(background(:))])
You can rewrite your code as:
%# get filenames of all JPG images in some folder
folder = '~/V&R/1/';
filelist = dir( fullfile(folder,'*.jpg') );
filelist = strcat(folder, filesep, {filelist.name});
%# read files, and store as 'double' images in a 4D matrix
images = zeros(480,640,3, numel(filelist), 'double');
for i=1:numel(filelist)
images(:,:,:,i) = im2double( imread(filelist{i}) );
end
%# estimate background using median
subimages = images(:,:,:,1:10:end);
background = median(subimages, 4);
imshow(background)

Resources