Create a random background image for gui - image

I am trying to create a function that will choose a picture for the background image for my gui at random. I tried doing this by creating random integers from 1 to 6 (i have 6 different background images to choose from) and then writing if statements where if the integer is equal to a certain value, then a certain image will be called. it works the first time I run the gui, and then every time after that I just get a grey background and no image.
% creates the 'background' axes
ha = axes('units','normalized','position',[0 0 1 1]);
% Move the background axes to the bottom
uistack(ha,'bottom');
% Load in a random background image and display it using the correct colors
bg = randi(6); % random integer
handles.p = 0; % background image variable
% pick a background based on random integer
if bg == 1
handles.p = imread('dark.jpg');
elseif bg == 2
handles.p = imread('powerup.PNG');
elseif bg == 2
handles.p = imread('what.jpg');
elseif bg == 2
handles.p = imread('earth.PNG');
elseif bg == 2
handles.p = imread('namek.PNG');
elseif bg == 2
handles.p = imread('namekexplode.PNG');
end
hi = imagesc(handles.p);
colormap gray;
% Turn the handlevisibility off and make the axes invisible
set(ha,'handlevisibility','off', 'visible','off');
clearvars handles.p
This is my attempt. Please help

You've written bg == 2 repeatedly instead of 3, 4, 5 ...

Related

Paint on Image MATLAB

Basically, I have a matrix filled with 0's and 1's that is a representation of an image. I essentially want a GUI that allows me to arbitrarily draw or make lines on the image, so essentially, Microsoft paint capabilities of drawing on the image.
Thanks for all your help.
As I commented, you can use ginput.
Here is a short program you can test.
fh = figure;
imageh = imshow(false(50));
% Create a button in the figure.
uicontrol('Parent',fh,'Style','pushbutton','String','paint','Callback',{#paintButtonCallback, imageh});
% button callback function
function paintButtonCallback(~,~,imageh)
[x,y] = ginput(1);
% round the values so they can be used for indexing.
x = round(x);
y = round(y);
% make sure the values do not go outside the image.
s = size(imageh.CData);
if x > s(2) || y > s(1) || x < 1 || y < 1
return
end
% make the selected pixel white.
imageh.CData(round(y),round(x)) = true;
end
Update
I'm not sure if there is any existing toolbox would allow you to edit images as conveniently as you can with MS paint. However, it is possible to code it yourselves.
To draw a line you can use 'ginput(2)' to take two points and plot the line. Note that the findLine function isn't perfect.
[x,y] = ginput(2);
% find all pixels on the line xy
ind = findLine(size(imageh.CData),x,y);
% make the selected pixel white.
imageh.CData(ind) = true;
function [x,y] = findLine(x,y)
% Find all pixels that lie between points defined by [x(1),y(1)] and [x(2),y(2)].
supersampling = 1.2;
[x,y,~] = improfile(s,round(x),round(y),max([diff(x);diff(y)])*supersampling);
ind = sub2ind(s,round(x),round(y));
end
If you have Image Processing Toolbox, you have the option to use drawline, which gives a better draw experience and you can get the pixels on the line using createMask function:
h = drawline;
ind = h.createMask;
drawfreehand may be also relevant:
h = drawfreehand;
x = h.Position(:,1);
y = h.Position(:,2);
You can delete the object created on the image with delete(h) if you don't need it. See more similar functions in MATLAB documentation.
It is also painful when you have to click the paint button each time you need to paint a point. To overcome this problem, you can use the ButtonDownFcn of the figure. The paint button will update the ButtonDownFcn with a meaningful callback or empty value depending on the circumstance:
function paintButtonCallback(obj,~,imageh)
if isempty(obj.Tag)
imageh.ButtonDownFcn = #paintMode;
obj.Tag = 'on';
else
imageh.ButtonDownFcn = '';
obj.Tag = '';
end
And the meaningful callback paintMode:
function paintMode(~,~)
[x,y] = ginput(1);
% round the values so they can be used for indexing.
x = round(x);
y = round(y);
% make sure the values do not go outside the image.
s = size(imageh.CData);
if x > s(2) || y > s(1) || x < 1 || y < 1
return
end
% make the selected pixel white.
imageh.CData(y,x) = true;
end
The full demo code:
fh = figure;
imageh = imshow(false(20));
% Create buttons in the figure.
uicontrol('Parent',fh,'Style','pushbutton','String','paint','Callback',{#paintButtonCallback, imageh});
bh = uicontrol('Parent',fh,'Style','pushbutton','String','line','Callback',{#lineButtonCallback, imageh});
bh.Position(2) = 50;
bh2 = uicontrol('Parent',fh,'Style','pushbutton','String','line2','Callback',{#line2ButtonCallback, imageh});
bh2.Position(2) = 80;
bh3 = uicontrol('Parent',fh,'Style','pushbutton','String','free','Callback',{#freeButtonCallback, imageh});
bh3.Position(2) = 110;
% button callback function
function paintButtonCallback(obj,~,imageh)
if isempty(obj.Tag)
imageh.ButtonDownFcn = #paintMode;
obj.Tag = 'on';
else
imageh.ButtonDownFcn = '';
obj.Tag = '';
end
function paintMode(~,~)
[x,y] = ginput(1);
% round the values so they can be used for indexing.
x = round(x);
y = round(y);
% make sure the values do not go outside the image.
s = size(imageh.CData);
if x > s(2) || y > s(1) || x < 1 || y < 1
return
end
% make the selected pixel white.
imageh.CData(y,x) = true;
end
end
% button callback function
function lineButtonCallback(~,~,imageh)
% take two points at a time
[x,y] = ginput(2);
% make sure the values do not go outside the image.
s = size(imageh.CData);
if any(x > s(2)+0.5 | y > s(1)+0.5 | x < 0.5 | y < 0.5) || (diff(x) == 0 && diff(y) == 0)
return
end
% find all pixels on the line xy
ind = findLine(size(imageh.CData),x,y);
% make the selected pixel white.
imageh.CData(ind) = true;
end
function ind = findLine(s,x,y)
% Find all pixels that lie between points defined by [x(1),y(1)] and [x(2),y(2)].
supersampling = 1.2;
[x,y,~] = improfile(s,round(x),round(y),max([diff(x);diff(y)])*supersampling);
ind = sub2ind(s,round(x),round(y));
end
% button callback function
function line2ButtonCallback(~,~,imageh)
% take two points at a time
h = drawline;
ind = h.createMask;
delete(h);
% make the selected pixel white.
imageh.CData(ind) = true;
end
% button callback function
function freeButtonCallback(~,~,imageh)
% take two points at a time
h = drawfreehand;
x = h.Position(:,1);
y = h.Position(:,2);
delete(h);
ind = sub2ind(size(imageh.CData),round(y),round(x));
% make the selected pixel white.
imageh.CData(ind) = true;
end

Detection of pellet on petri dish

I am currently doing a project on morphology of filamentous fungi during batch fermentation (Yes, I am not a software engineer.. Biotech). Where I am taken pictures of the morphology in a petri dish. I am developing a "fast" method to describe the pellets (small aggregates of fungi) that occurs during the fermentation. To do this I am writing a code in MatLab.
Depending on the color of the pellets (light or dark) the pictures are taken on differen backgrounds, black or white. I am inverting the picture if the mean gray value is below 70 to distinguish between backgrounds.
Pictures:
White background
Dark background
I have several problems:
Detecting the edge of the petri dish so it won't be regarded as an object (Currently done with the edge('log',) function). The edge is detected, but i miss some parts, think because of the lower light in top.
Proper thresholding inside the dish
Detection of pellets - right now it is done by a combination of running through each color channel, but might be done with some blob detection?
Does anybody have some inputs?
My code is as following:
close all
clear all
clc
%Empty arrays to hold data
metricD=[];
areaD=[];
perimeterD=[];
% Specify the folder where the files live.
myFolder = pwd;
% Check to make sure that folder actually exists. Warn user if it doesn't.
if ~isdir(myFolder)
errorMessage = sprintf('Error: The following folder does not exist:\n%s', myFolder);
uiwait(warndlg(errorMessage));
return;
end
% Get a list of all files in the folder with the desired file name pattern.
filePattern = fullfile(myFolder, '*.jpg'); % Change to whatever pattern you need.
theFiles = dir(filePattern);
% Show debugging plots
plotFig = 0;
% parameters that can be tuned
% how many colors channels we minimum want to see a spore in
% e.g. set to 1 for image "P. f Def C.tif"
labelcutOff = 1;
% remove areas larger than
removeLargerthan = 500000;
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(myFolder, baseFileName);
%% reading as an image array with im
I = imread(fullFileName);
% convert to grayscale
Ig = rgb2gray(I);
if plotFig
figure;imagesc(I)
figure;imagesc(Ig)
end
mm=mean(mean(Ig));
if mm < 70
I=imcomplement(I);
Ig = imcomplement(Ig);
end
% BLOB DETCTION
% h = fspecial('log', [15 15], 2);
% imLOG = imfilter(Ig, h);
% figure;imagesc(imLOG)
%% find petridish by edges and binary operations
% HACK - NOT HOW IT SHOULD BE DONE
Ig = wiener2(Ig,[5 5]);
imEdge = edge(Ig,'log');
circle = bwareaopen(imEdge,50);
circle = imclose(circle,strel('disk',30));
circle = bwareaopen(circle,8000);
% circle = imfill(circle,'holes');
circle = bwconvhull(circle);
circle = imerode(circle,strel('disk',150));
if plotFig
figure;imagesc(circle)
end
%% Get thresholds inside dish using otsu on each channel
imR = double(I(:,:,1)) .* circle;
imG = double(I(:,:,2)) .* circle;
imB = double(I(:,:,3)) .* circle;
thresR = graythresh(uint8(imR(circle))) *max(imR(circle));
thresG = graythresh(uint8(imG(circle))) *max(imG(circle));
thresB = graythresh(uint8(imB(circle))) *max(imB(circle));
if plotFig
figure;imagesc(imR)
figure;imagesc(imG)
figure;imagesc(imB)
end
%% classify inside dish
% check if it should be smaller or larger than
if sum(imR(circle) < thresR) > sum(imR(circle) > thresR)
labelR = imR > thresR;
else
labelR = imR < thresR;
end
if sum(imG(circle) < thresG) > sum(imG(circle) > thresG)
labelG = imG > thresG;
else
labelG = imG < thresG;
end
if sum(imB(circle) < thresB) > sum(imB(circle) > thresB)
labelB = imB > thresB;
else
labelB = imB < thresB;
end
if plotFig
figure;imagesc(labelR)
figure;imagesc(labelG)
figure;imagesc(labelB)
end
labels = (labelR + labelG + labelB) .* circle;
labels(labels < labelcutOff) = 0;
labels = imfill(labels,'holes');
labels = bwareaopen(labels,30);
if plotFig
figure;imagesc(labels)
end
%% clean up labels
labelBig = bwareaopen(labels,removeLargerthan);
labels = labels - labelBig;
if plotFig
figure;imagesc(labels)
end
BN = labels;
%% old script
stats = regionprops(BN,'Basic');
obj2 = numel(stats);
[B,L] = bwboundaries(BN,'holes');
figure
% imshow(label2rgb(L, #jet, [.5 .5 .5]))
imshow(I)
hold on
title(baseFileName)
for j = 1:length(B)
boundary = B{j};
plot(boundary(:,2), boundary(:,1),'w','LineWidth',2)
end
%region stats
stats = regionprops(L,'Area','Centroid');
%Threshold for printing in end
threshold = 0.2;
%Conversion factor pixel to cm
conversionF=9/2125;
% loop over the boundaries
for j = 1:length(B)
% obtain (X,Y) boundary coordinates corresponding to label 'j'
boundary = B{j};
% compute a simple estimate of the object's perimeter
delta_sq = diff(boundary).^2;
perimeter = sum(sqrt(sum(delta_sq,2)));
perimeterD(j,k)=perimeter*conversionF;
% obtain the area calculation corresponding to label 'k'
area = stats(j).Area;
areaD(j,k)=area*conversionF^2;
% compute the roundness metric
metric = 4*pi*area/perimeter^2;
metricD(j,k)=metric;
% display the results
metric_string = sprintf('%d. %2.2f', j,metric);
text(boundary(1,2)-50,boundary(1,1)+23,metric_string,'Color','k',...
'FontSize',14,'FontWeight','bold');
end
drawnow; % Force display to update immediately.
end
%Calculating stats
areaM=mean(areaD);
pM=mean(perimeterD);
metricD(metricD==Inf)=0;
mM=mean(metricD);
Hint:
A morphological top-hat filter fllowed by binarization (with a constant threshold ?) can be a good start. And filtering on the blob size will do a reasonable cleanup.
For the edges, try circular Hough.

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

Bouncing text animation issue in Pygame

I'm trying to code a program that can take text and animate it to bounce on a loop, like a ball bouncing to the floor. I used a similar piece of code I found a starting point as I'm still fairly new to Pygame (thank you Pete Shinners, whoever you are), but after updating the code and playing with it for a long time I still can't get it to blit to the screen correctly. The text starts above the rendered area and then gradually falls into view, but the top part of the text is cut off.
I've tried moving the blitted region around the window and resizing the rectangles and surface the program is using, but nothing seems to fix it.
import os, sys, math, pygame, pygame.font, pygame.image
from pygame.locals import *
def bounce():
# define constants
G = 0.98
FLOOR = 0
COEFFICIENT = 0.8
#define variables
ball = 500
direction = 'DOWN'
v = 0
count = 0
#create array to store data
array = [ball]
while True:
if count == 4:
return array
elif ball > FLOOR and direction == 'DOWN':
v += G
if (ball - v) >= FLOOR:
ball = ball - v
array.append(round(ball,2))
else:
ball = FLOOR
array.append(round(ball,2))
direction = 'UP'
v *= COEFFICIENT
count += 1
elif ball >= FLOOR and direction == 'UP':
v -= G
if (ball + v) >= FLOOR:
ball = ball + v
array.append(round(ball,2))
if v <= 0:
direction = 'DOWN'
else:
ball = FLOOR
array.append(ball)
direction = 'UP'
v *= COEFFICIENT
class textBouncy:
array = bounce()
def __init__(self, font, message, fontcolor, amount=10):
# Render the font message
self.base = font.render(message, 0, fontcolor)
# bounce amount (height)
self.amount = amount
#size = rect of maximum height/width of text
self.size = self.base.get_rect().inflate(0, amount).size
#normalise array to meet height restriction
self.array = [round(-x/(500/amount),2) for x in array]
def animate(self):
# create window surface s
s = pygame.Surface(self.size)
# height = max inflated height
height = self.size[1]
# define a step-sized rectangle in the location of the step
src = Rect(0, 0, self.base.get_width(), height)
# moves the message according to the array list.
dst = src.move(0, self.array[i])
if (i + 1) == len(self.array):
global i
i = 0
# blits the information onto the screen
s.blit(self.base, dst, src)
return s
entry_info = 'Bouncing ball text'
if __name__ == '__main__':
pygame.init()
#create text renderer
i = 0
array = bounce()
bigfont = pygame.font.Font(None, 60)
white = 255, 255, 255
renderer = textBouncy(bigfont, entry_info, white, 16)
text = renderer.animate()
#create a window the correct size
win = pygame.display.set_mode(text.get_size())
win.blit(text, (0, 10))
pygame.display.flip()
#run animation loop
finished = 0
while True:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
text = renderer.animate()
i += 1
win.blit(text, (0, 10)) # blits the finished product from animate
pygame.display.flip()
(Quote) "it all comes down to math really" Kay so you need to - the y axis when you want to make it go up and + the x axis to make it go side ways you could make it go up and down will moveing it horizontally and then when it reaches a point it will stop moving horizontally and just bonce up and down +ing it more every time
That was my 100$ which took me 5 mins to write
After revisiting this I managed to work this out - I needed to add everything I blitted down to compensate for the bounce up. So in the __init__function:
self.array = [round(-x/(500/amount),2)**+self.amount** for x in array]
Works perfectly now :)

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.

Resources