Adobe Director - Lingo Quiz - lingo

So I have a quiz I'm making using Adobe director, but I'm struggling with the overall environment.
I'm adding the following Lingo script to each button with a correct answer:
on mouseDown
global gscore
set gscore = gscore + 1
And on the final stage, I use the following Lingo script to check the acquired points, and display the appropriate sprite for the result.
on enterFrame
if gscore = 0 then set the memberNum of sprite (3) to 154
end if
if gscore = 1 then set the memberNum of sprite (3) to 155
end if
if gscore = 2 then set the memberNum of sprite (3) to 156
end if
if gscore = 3 then set the memberNum of sprite (3) to 157
end if
if gscore = 4 then set the memberNum of sprite (3) to 158
end if
if gscore = 5 then set the memberNum of sprite (3) to 159
end if
end
So my errors seem to say there is no declared variable, but it's global right? So how come it doesn't recognise it. The first script is attached to the buttons corresponding to correct answers, each button has a seperate script to send it to the next question. The final stage which is meant to display the results should display a certain custom sprite dependant on the value of gscore.

Glad you figured out a solution. Another approach would have been to not use if statements at all. Your enterframe script could have read like this:
on enterframe
sprite(3).memberNum = 154+gscore
end

Figured it out, appologies.
I removed all the end if's to make it a complete if statement. Set the global variable on the first script used declaring the value as 0. Then later when incrementing it is adding to a previously defined global variable of the same name.
I believe my problem lay in global variable instances default value being void.

on exitframe me
global gscore
.
if gscore = 0
set the memberNum of sprite (3) to 154
else if gscore = 1 then
set the memberNum of sprite (3) to 155
else if gscore = 2 then
set the memberNum of sprite (3) to 156
else if gscore = 3 then
set the memberNum of sprite (3) to 157
else if gscore = 4 then
set the memberNum of sprite (3) to 158
else if gscore = 5 then
set the memberNum of sprite (3) to 159
end if
end

Related

Outputting Regionprops to csv in MATLAB

I'm currently running some data analysis on a lot of pictures and the code i have running is the following:
close all
clear all
clc
A=imread('Ring_1_frame_120.jpg'); %Load picture
%A01-A010 = xmin ymin width height
%for all vials
A001=imcrop(A,[65 159 95 332]);
A002=imcrop(A,[182 161 95 332]);
A003=imcrop(A,[297 164 95 332]);
A004=imcrop(A,[402 165 90 332]);
A005=imcrop(A,[495 168 90 332]);
A006=imcrop(A,[606 166 90 332]);
A007=imcrop(A,[705 171 90 332]);
A008=imcrop(A,[808 175 90 332]);
A009=imcrop(A,[922 175 90 332]);
A0010=imcrop(A,[1031 175 90 332]);
w = who; % returns the names of all your current variables in a cell.
for i = 1:numel(w)
% A00 is unique to all the variables you want to process.
if ~isempty(strfind(w{i}, 'A00'))
% hard coding greenChannel and extracting the second plane.
eval(['greenChannel = ',w{i},'(:,:,2)']);
BW = edge(greenChannel,'Prewitt');
%figure, imshow(BW);
%Dialate Lines
se90 = strel('line', 3, 90);
se0 = strel('line', 3, 0);
BWsdil = imdilate(BW, [se90 se0]);
%figure, imshow(BWsdil), title('dilated gradient mask');
%Fill Lines
BWdfill = imfill(BWsdil, 'holes');
%figure, imshow(BWdfill), title('binary image with filled holes');
%Clean up borders
BWnobord = imclearborder(BWdfill, 4);
%figure, imshow(BWnobord), title('cleared border image');
%Final cleanup
seD = strel('diamond',1);
BWfinal = imerode(BWnobord,seD);
BWfinal = imerode(BWfinal,seD);
figure, imshow(BWfinal), title('segmented image');
L = bwlabel(BWfinal);
s = regionprops(L,'centroid');
data(:,:,i) = s; %save the xy coords as data matrix
end
end
The goal I'm trying to achieve is getting the variable s into a csv file, but I'm stuck at the last line since it's not working. It keeps overwriting itself. s is a structure ranging from 3x1 to 5x1 and I have also tried to use struct2cell and mat2cell but that was unsuccessful.
s is a structure, so what you need to do is unpack the structure so that it becomes a matrix, then you can save the matrix to file. s contains a field called Centroid, so you need to access that field.
However before I address that point, checking to see how many variables are in your workspace so you can determine how many times your loop has to iterate.... is very bad practice. Especially if you are using each variable name as a separate occurrence for processing. I highly recommend you use a structure to encapsulate this or some sort of cell array.
If I can provide a canonical post, please consult user Adriaan's excellent post on how to avoid dynamic variable names and sheds light on what I'm about to talk about here.
Something like this would work instead. I'll use a cell array because (at least to me) it is easier. Place your desired coordinates in a 2D matrix where each row is the top-left corner of the location in the image you want to process as well as the width and height (basically suitable for imcrop), then loop over each set of coordinates and place the cropped image as an element in a cell array. Cell array use is important because the dimensions per cropped image are different and so you can't use a normal matrix here:
A=imread('Ring_1_frame_120.jpg'); %Load picture
%A01-A010 = xmin ymin width height
coords = [65 159 95 332; 182 161 95 332; 297 164 95 332; 402 165 90 332;...
495 168 90 332; 606 166 90 332; 705 171 90 332; 808 175 90 332;...
922 175 90 332; 1031 175 90 332];
numImages = size(coords,1);
images = cell(1,numImages);
for ii = 1 : numImages
images{ii} = imcrop(A,coords(ii,:));
end
images is now a cell array of cropped images that belong to the image A. To access the right image, you can use images to do that like so:
img = images{ii};
ii is the image number you wish to access. Another comment I'd like to make is your use of eval. It is really not recommended in your loop either... which is why I decided to change the logic.
Do this instead:
for ii = 1 : numImages
% hard coding greenChannel and extracting the second plane.
greenChannel = images{ii}(:,:,2); %// Change for green channel
%// Now code is the same as before
BW = edge(greenChannel,'Prewitt');
%figure, imshow(BW);
%Dilate Lines
se90 = strel('line', 3, 90);
se0 = strel('line', 3, 0);
BWsdil = imdilate(BW, [se90 se0]);
%figure, imshow(BWsdil), title('dilated gradient mask');
%Fill Lines
BWdfill = imfill(BWsdil, 'holes');
%figure, imshow(BWdfill), title('binary image with filled holes');
%Clean up borders
Wnobord = imclearborder(BWdfill, 4);
%figure, imshow(BWnobord), title('cleared border image');
%Final cleanup
seD = strel('diamond',1);
BWfinal = imerode(BWnobord,seD);
BWfinal = imerode(BWfinal,seD);
figure, imshow(BWfinal), title('segmented image');
...
end
Alright, so now how do we get the coordinates of the centroid and save them to file? You simply need to unpack the structure and get the centroid coordinates. Make sure data is declared at the top is now a cell array:
data = cell(1, numImages);
The reason why you need a cell array (again) is because you don't know how many segmented components there are per cropped image you're looking at. Now finally at the end of your loop:
for ii = 1 : numImages
%// Your code...
%//...
L = bwlabel(BWfinal);
s = regionprops(L,'centroid');
%// New code
data{ii} = reshape([s.Centroid],2,[]).';
end
Now that you have the centroid coordinates stored in a cell array per cropped image, you can either create multiple CSVs where each CSV contains the centroids of each detected object for each cropped image, or you can concatenate all of the centroids together in a single matrix.
So, do either:
for ii = 1 : numImages
csvwrite(sprintf('data%d.csv', ii), data{ii});
end
... or
out = cat(1, data{:});
csvwrite('data.csv', out);
I'm not sure which method you want to use to write to file, but either of those should work.
You need to access struct elements using s(i).Centroid, as a minimal example,
a =imread('circlesBrightDark.png');
bw = a < 100;
s = regionprops(bw,'centroid');
for i =1:size(s)
data(:,:,i) = s(i).Centroid
end

Create a random background image for gui

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 ...

Transition shader

I have created a transition shader.
This is what is does:
On each update the color that should be alpha changes.
Then preform a check for each pixel.
If the color of the pixel is more that the 'alpha' value
Set this pixel to transparent.
Else If the color of the pixel is more that the 'alpha' value - 50
Set this pixel to partly transparent.
Else
Set the color to black.
EDIT (DELETED OLD PARTS):
I tried converting my GLSL into AGAL (using http://cmodule.org/glsl2agal):
Fragment shader:
const float alpha = 0.8;
varying vec2 TexCoord; //not used but required for converting
uniform sampler2D transition;//not used but required for converting
void main()
{
vec4 color = texture2D(transition, TexCoord.st);//not used but required for converting
color.a = float(color.r < alpha);
if(color.r >= (alpha - 0.1)){
color.a = 0.2 * (color.r - alpha - 0.1);
}
gl_FragColor = vec4(0, 0, 0, color.a);
}
And I've customized the output and added that to a (custom) Starling filter:
var fragmentShader:String =
"tex ft0, v0, fs0 <2d, clamp, linear, mipnone> \n" + // copy color to ft0
"slt ft0.w, ft0.x, fc0.x \n" + // alpha = red < inputAlpha
"mov ft0.xyz, fc1.xyzz \n" + // set color to black
"mov oc, ft0";
mShaderProgram = target.registerProgramFromSource(PROGRAM_NAME, vertexShader, fragmentShader);
It works and when I set the filters alpha, it will update the stuff. The only thing left is the partly transparent thing, but I have no idea how I can do that.
Swap the cycle on the Y and X coordinates. By using the X in the inner loop you optimize the L1 cache and the prefetcher of the CPU.
Some minor hints:
Remove the zeros for a cleaner code:
const c:uint = a << 24
Verify that 255/50 is collapsed into a single constant by the compiler.
Don't be crazy by doing it with BitmapData once you're using Starling.
I didn't get if you're grayscaling it by yourself or not. In not, just create a Starling filter for grayscale (pixel shader below will do the trick)
tex ft0, v0, fs0 <2d,linear,clamp>
add ft1.x, ft0.x, ft0.y
add ft1.x, ft1.x, ft0.z
div ft1.x, ft1.x, fc0.x
mov ft0.xyz, ft1.xxx
mov oc ft0
And for the alpha transition just extend the Image Class, implement IAnimatable add it to the Juggler. in the advanceTime just do a this.alpha -= VALUE;
Simple like that :)
Just going to elaborate a bit on #Paxel's answer. I discussed with another developer Jackson Dunstan about the L1 caching, where the speed improvement comes from, and what other improvements can be made to code like this to see performance gain.
After which Jackson posted a blog entry which can be read at here: Take Advantage of CPU caching
I'll post some the relative items. First the bitmap data is stored in memory by rows. The rows memory addresses might look something like this:
row 1: 0 1 2 3 4 5
row 2: 6 7 8 9 10 11
row 3: 12 13 14 15 16 17
Now running your inner loop through the rows will allow you leverage the L1 cache advantage since you can read the memory in order. So inner looping X first you'll read the first row as:
0 1 2 3 4 5
But if you were to do it Y first you'd read it as:
0 6 12 1 7 13
As you can see you are bouncing around memory addresses making it a slower process.
As for optimizations that could be made, the suggestion is to cache your width and height getters, storing the properties into local variables. Also using the Math.round() is pretty slow, replacing that would see a speed increase.

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.

Display a tree structure inside a box in MATLAB

I have a problem to see the tree structure created by the following code. I want the tree box fulfills the interior of the pane which handle is hPanLeft. However, if I use normalized units, I get NaN and Inf for the Position property of the tree structure. I do not understand what is wrong.
function example
import javax.swing.*
import javax.swing.tree.*;
f = figure;
hPanRight = uipanel('Parent',f,'Units','normalized','Position',...
[0.5 0 0.5 0.5]);
hPanLeft = uipanel('Parent',f,'Units','normalized','Position',...
[0 0.5 0.5 0.5]);
[tree, container]= uitree('v0');
set(container,'Parent',hPanLeft);
set(tree, 'Units', 'normalized');
set(tree,'Position',[0 0 1 1]);
get(tree,'Position'),
root = uitreenode('v0','root','MAIN',[],false);
Nodo1 = uitreenode('v0','Nodo1','LEAF 1',[],true);
Nodo2 = uitreenode('v0','Nodo2','LEAF 2',[],true);
Nodo3 = uitreenode('v0','Nodo3','LEAF 3',[],true);
root.add(Nodo1);
root.add(Nodo2);
root.add(Nodo3);
treeModel = DefaultTreeModel(root);
tree.setModel(treeModel);
jtree = handle(tree.getTree,'CallbackProperties');
tree.setSelectedNode(root);
end
You want to set the position property of the container not the tree object handle:
[tree,container] = uitree('v0');
set(container, 'Parent',hPanLeft);
set(container, 'Units','normalized', 'Position',[0 0 1 1]);
Just remember that UITREE is an undocumented function. You might want to read this series of articles on this component.

Resources