Increasing count of colors instead of 8 - image

I have completed a programming that can count up to 8 colors in images by using the RGB method from 000 up to 111. I need to do some modification to it. So far I declare the number if above 128 will equal to 1 & below 128 will be 0. It will count the 8 colours. How to increase the number of colours count if let say I do it partially from 0-64,65-128,129-192,193-255.
count=zeros(1,8);
for i = 1:w
for j = 1:h
if redChannel(i,j) > 128,
aredChannel2 = 1;
else
aredChannel2=0;
end
quantizedImage(i,j,1)=aredChannel2*255;
if greenChannel(i,j) > 128,
agreenChannel2 = 1;
else
agreenChannel2=0;
end
quantizedImage(i,j,2)=agreenChannel2*255;
if blueChannel(i,j) > 128,
ablueChannel2 = 1;
else
ablueChannel2=0;
end
quantizedImage(i,j,3)=ablueChannel2*255;
bin=4*aredChannel2+2*agreenChannel2+ablueChannel2+1;
count(bin)=count(bin)+1;
end
end
figure, imshow(uint8(quantizedImage))

Increasing the number of intervals increases the base you are counting in: instead of 2^3=8 quantized colors you will have 4^3=64 quantized colors.
rgb = imread( ... ); %// read you image here
qImage = zeros( size(rgb(:,:,1)) ); %// preallocate result
intervals = permute([64, 128, 192, 256], [1 3 2]); %// the quantization intervals
base = numel(intervals);
for ci=1:size(rgb,3) %// for each channel
whichInterval = bsxfun( #le, rgb(:,:,ci), intervals ); %// select per pixel, which interval is relevant
[~, q] = max( whichInterval, [], 3 ); %// get index of relevant interval
qImage = qImage*base + (q-1); %// -1 to convert from matlab's 1-based indexing
end

Related

How can I tile an image into patches of (constant) arbitrary size at (constant) arbitrary stride in MATLAB?

I have an image of arbitrary dimensions ROWS and COLS. I want to tile this image into patches of arbitrary, but constant size blockSize = [blockSizeR, blockSizeC], given an arbitrary, but constant stride stride = [strideR, strideC]. When the number of patches in row or column direction times the respective block size doesn't equal the number of rows or columns, respectively (i.e. if there were spare rows or columns), I don't care about them (i.e. they can be ignored). It's sufficient if the image is tiled into all possible patches that fit completely into the image starting from the top left pixel.
There is a bunch of possible solutions floating around the web, but some don't allow overlap, some don't allow outputs if there are spare rows or columns, some are making inefficient use of for loops.
The closest thing to what I need is probably the solution posted on https://de.mathworks.com/matlabcentral/answers/330357-how-do-i-store-a-series-of-rgb-images-in-a-2d-array:
%img: source image
stride = [5, 5]; %height, width
blocksize = [11, 11]; %height, width
tilescount = (size(img(:, :, 1)) - blocksize - 1) / stride + 1;
assert(all(mod(tilescount, 1) == 0), 'cannot divide image into tile evenly')
tiles = cell(tilescount);
tileidx = 1;
for col = 1 : stride(2) : size(img, 2 ) - blocksize(2)
for row = 1 : stride(1) : size(img, 1) - blocksize(1)
tiles{tileidx} = img(row:row+stride(1)-1, col:col+stride(2)-1, :);
tileidx = tileidx + 1;
end
end
However, it also seems to work only if there are no spare rows or columns. How can I adapt that to an efficient solution for images with an arbitrary number of channels (I seek to apply it on both single-channel images and RGB images)?
The code above did not fully work, so I came up with the following solution based on it. Variable names are chosen such that they are self-explanatory.
tilesCountR = floor((ROWS - rowBlockSize - 1) / rowStride + 1);
tilesCountC = floor((COLS - colBlockSize - 1) / colStride + 1);
tiles = cell(tilesCountR * tilesCountC,1);
tileidx = 1;
for col = 1 : colStride : COLS - colBlockSize
for row = 1 : rowStride : ROWS - rowBlockSize
tiles{tileidx} = img(row:row+rowBlockSize-1, col:col+colBlockSize-1, :);
tileidx = tileidx + 1;
end
end

Matlab image - how to count number of white pixels

The matlab code below splits up an image into a number of smaller images. It then counts the number of black pixels in the image and displays it as a percentage of the total number of pixels in the picture. example of image
My question is - instead of counting the black pixels and displaying the percentage, how can I count the white pixels? (essentially the opposite!)
Thanks
% Divide an image up into blocks (non-overlapping tiles).
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
workspace; % Make sure the workspace panel is showing.
fontSize = 20;
% Read the image from disk.
rgbImage = imread('edge-diff.jpg');
% Display image full screen.
imshow(rgbImage);
% Enlarge figure to full screen.
set(gcf, 'units','normalized','outerposition',[0 0 1 1]);
drawnow;
% Get the dimensions of the image. numberOfColorBands should be = 3.
[rows columns numberOfColorBands] = size(rgbImage)
%==========================================================================
% The first way to divide an image up into blocks is by using mat2cell().
blockSizeR = 400; % Rows in block.
blockSizeC = 400; % Columns in block.
% Figure out the size of each block in rows.
% Most will be blockSizeR but there may be a remainder amount of less than that.
wholeBlockRows = floor(rows / blockSizeR);
blockVectorR = [blockSizeR * ones(1, wholeBlockRows), rem(rows, blockSizeR)];
% Figure out the size of each block in columns.
wholeBlockCols = floor(columns / blockSizeC);
blockVectorC = [blockSizeC * ones(1, wholeBlockCols), rem(columns, blockSizeC)];
% Create the cell array, ca.
% Each cell (except for the remainder cells at the end of the image)
% in the array contains a blockSizeR by blockSizeC by 3 color array.
% This line is where the image is actually divided up into blocks.
if numberOfColorBands > 1
% It's a color image.
ca = mat2cell(rgbImage, blockVectorR, blockVectorC, numberOfColorBands);
else
ca = mat2cell(rgbImage, blockVectorR, blockVectorC);
end
percentBlack = cellfun(#(x)sum(sum(all(x == 0, 3))) / (numel(x) / size(x,3)), ca);
% Now display all the blocks.
plotIndex = 1;
numPlotsR = size(ca, 1);
numPlotsC = size(ca, 2);
for r = 1 : numPlotsR
for c = 1 : numPlotsC
fprintf('plotindex = %d, c=%d, r=%d\n', plotIndex, c, r);
% Specify the location for display of the image.
subplot(numPlotsR, numPlotsC, plotIndex);
ax2 = subplot(numPlotsR, numPlotsC, plotIndex);
% Extract the numerical array out of the cell
% just for tutorial purposes.
rgbBlock = ca{r,c};
imshow(rgbBlock); % Could call imshow(ca{r,c}) if you wanted to.
[rowsB columnsB numberOfColorBandsB] = size(rgbBlock);
set(ax2, 'box', 'on', 'Visible', 'on', 'xtick', [], 'ytick', []);
% Make the caption the block number.
averageBlack = percentBlack(r,c);
disp(numPlotsR);
disp(averageBlack);
caption = sprintf('Frame #%d of %d\n Percentage information content %0.2f', ...
plotIndex, numPlotsR*numPlotsC, averageBlack*100);
title(caption);
drawnow;
% Increment the subplot to the next location.
plotIndex = plotIndex + 1;
end
end
This line:
percentBlack = cellfun(#(x)sum(sum(all(x == 0, 3))) / (numel(x) / size(x,3)), ca);
specifically the part that says all(x == 0, 3) means "all color channels have value 0". You want to change it to "all color channels have value 1 (or 255 depends on your image)"
So basically, change that 0 to 1 or 255, deependinf if your image is unit8 or double

Sampling pixels from an Image - increasing performance

I am sampling some pixels from a reference image Ir and then moving them on a secondary image In. The first function I have written is as follows:
[r,c,d] = size(Ir);
rSample = fix(r * 0.4); % sample 40 percent of pixels
cSample = fix(c * 0.4); % sample 40 percent of pixels
rIdx = randi(r,rSample,1); % uniformly sample indices for rows
cIdx = randi(c,cSample,1); % uniformly sample indices for columns
kk = 1;
for ii = 1:length(rIdx)
for jj=1:length(cIdx)
In(rIdx(ii),cIdx(jj),:) = Ir(rIdx(ii),cIdx(jj),:) * fcn(rIdx(ii),cIdx(jj));
kk = kk + 1;
end
end
Another method to increase the performance (speed) of the code, that I came around is as follows:
nSample = fix(r*c*0.4);
Idx = randi(r*c,nSample,1);
for ii = 1:nSample
[I,J] = ind2sub([r,c],Idx(ii,1));
In(I,J,:) = Ir(I,J,:) * fcn(I,J);
end
In both codes, fcn(I,J) is a function that performs some computation on the pixel at [I,J] and the process can be different depending on the indices of the pixel.
Although I have removed one for-loop, I guess there is a better technique to increase the performance of the code even more.
Update:
As suggested by #Daniel the following line of the code does the job.
In(rIdx,cIdx,:)=Ir(rIdx,cIdx,:);
But the point is, I prefer to have only the sampled pixels to be able to process them faster. For instance having the samples in a vector format wit 3 layers for RGB.
Io = Ir(rIdx,cIdx,:);
Io1 = Io(:,:,1);
Io1v = Io1(:);
Ir=ones(30,30,3);
In=Ir*.5;
[r,c,d] = size(Ir);
rSamples = fix(r * 0.4); % sample 40 percent of pixels
cSamples = fix(c * 0.4); % sample 40 percent of pixels
rIdx = randi(r,rSamples,1); % uniformly sample indices for rows
cIdx = randi(c,cSamples,1); % uniformly sample indices for columns
In(rIdx,cIdx,:)=Ir(rIdx,cIdx,:);

Mid line through a set of dicom images in matlab

I have a set of Dicom images on matlab and i would like to add a midline going through all the images
I am outputting the images via imshow3d function
thanks
Edit: here's what i have, the random points are not in the middle they just run through the image
>> clc;
>>clear;
>>%imports dicom images
>>run DicomImport.m;
>>%random points for shortest distance test
>>a = [1 10 200];
>>b = [500 512 300];
>>ab = b - a;
>>n = max(abs(ab)) + 1;
>>s = repmat(linspace(0, 1, n)', 1, 3);
>>for d = 1:3
>> s(:, d) = s(:, d) * ab(d) + a(d);
>>end
>>s = round(s);
>>Z = 593;
>>N = 512;
>>X = zeros(N, N, Z);
>>X(sub2ind(size(X), s(:, 1), s(:, 2), s(:, 3))) = 1;
>>C = find(X);
>>ans.Img(C) = 5000;
>> %shows image
>>imshow3D(ans.Img);
So it looks like ans.Img contains the 3D matrix consisting of your image stack. It looks like you've got something going, but allow me to do this a bit differently. Basically, you need to generate a set of coordinates where we can access the image stack and draw a vertical line in the middle of the each image in the image stack. Do something like this. First get the dimensions of the stack, then determine the halfway point for the columns. Next, generate a set of coordinates that will draw a line down the middle for one image. After you do this, repeat this for the rest of the slices and get the column major indices for these:
%// Get dimensions
[rows,cols,slices] = size(ans.Img);
%// Get halfway point for columns
col_half = floor(cols/2);
%// Generate coordinates for vertical line for one slice
coords_middle_row = (1:rows).';
coords_middle_col = repmat(col_half, rows, 1);
%// Generate column major indices for the rest of the slices:
ind = sub2ind(size(ans.Img), repmat(coords_middle_row, slices, 1), ...
repmat(coords_middle_col, slices, 1), ...
reshape(kron(1:slices, ones(rows, 1)), [], 1));
%// Set the pixels accordingly
ans.Img(ind) = 5000;
This code is quite similar to the answer I provided to one of your earlier question; i.e. I don't use imshow3D but the framework is similar and simpler to modify in order to suit your need. In this case, upon pressing a pushbutton a line appears at the middle of the stack and you can scroll through it with the slider. I hope this can be of help.
function LineDicom(~)
clc
clear
close all
%// Load demo data
S = load('mri');
%// Get dimensions and number of slices.
ImageHeight = S.siz(1); %// Not used here
ImageWidth = S.siz(2); %// Not used here
NumSlices = S.siz(3);
S.D = squeeze(S.D);
%// Create GUI
hFig = figure('Position',[100 100 400 400],'Units','normalized');
%// create axes with handle
handles.axes1 = axes('Position', [0.2 0.2 0.6 0.6]);
%// create y slider with handle
handles.y_slider = uicontrol('style', 'Slider', 'Min', 1, 'Max', NumSlices, 'Value',1, 'Units','normalized','position', [0.08 0.2 0.08 0.6], 'callback', #(s,e) UpdateY);
handles.SlideryListener = addlistener(handles.y_slider,'Value','PostSet',#(s,e) YListenerCallBack);
%// Create pusbutton to draw line
handles.DrawLineButton= uicontrol('style', 'push','position', [40 40 100 30],'String','Draw line', 'callback', {#DrawLine,handles});
%// Flag to know whether pushbutton has been pushed
handles.LineDrawn = false;
%// Show 1st slice
imshow(S.D(:,:,1))
guidata(hFig,handles);
%// Listeners callbacks followed by sliders callbacks. Used to display each
%// slice smoothly.
function YListenerCallBack
handles = guidata(hFig);
%// Get current slice
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
%// If button was button, draw line
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
function UpdateY(~)
handles = guidata(hFig); %// Get handles.
CurrentSlice = round(get(handles.y_slider,'value'));
hold on
imshow(S.D(:,:,CurrentSlice));
if handles.LineDrawn
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
end
drawnow
guidata(hFig,handles);
end
%// Pushbutton callback to draw line.
function DrawLine(~,~,handles)
line([round(ImageWidth/2) round(ImageWidth/2)],[1 ImageHeight],'Color','r','LineWidth',2);
handles.LineDrawn = true;
guidata(hFig,handles);
end
end
Sample output:
and after moving the slider up:
Is this what you meant? If not I'll remove that answer haha and sorry.

MATLAB finding average RGB value across all pixels in image

Code is below. I'm looping through an input image 1 pixel at a time and determining its RGB value. Afterwards i'm trying to find the average RGB value for the image overall. For some reason the averaging portion of my code isnt working though.
im = imread(filename);
[width, height, depth] = size(im);
count = 0;
r=0;
g=0;
b=0;
for x = 1 : width
for y = 1: height
r = r + im(x,y,1);
g = g + im(x,y,2);
b = b + im(x,y,3);
count = count + 1;
end
end
%find averages of each RGB value.
r2 = r/count;
g2 = g/count;
b2 = b/count;
Why not vectorizing and using mean?
mean( reshape( im, [], 3 ), 1 )
The following code would work as well;
pep = imread('peppers.png');
mean(mean(pep))
This will return a 1x1x3 vector which will be the mean values of R, G, and B respectively.

Resources