Create separated R-G-B array from loaded image - matlab

Sorry to bother, but it seem that I stuck with pretty easy task.
Simply, I want to create 3*m-by-3*n-by-3 RGB file from m-by-n-by-3 loaded image. Lets use folowing array as an example as example:
Image(:,:,1) = 0.5*ones(4);
Image(:,:,2) = ones(4);
Image(:,:,3) = 0.25*ones(4);
Image = uint8(255*Image); %3-D array, Red = 128, Green = 255, Blue = 64;
What I want to get is this:
ImageRGB(:,:,1) =
128 0 0 128 0 0 128 0 0 128 0 0
128 0 0 128 0 0 128 0 0 128 0 0
128 0 0 128 0 0 128 0 0 128 0 0
128 0 0 128 0 0 128 0 0 128 0 0
ImageRGB(:,:,2) =
0 255 0 0 255 0 0 255 0 0 255 0
0 255 0 0 255 0 0 255 0 0 255 0
0 255 0 0 255 0 0 255 0 0 255 0
0 255 0 0 255 0 0 255 0 0 255 0
ImageRGB(:,:,3) =
0 0 64 0 0 64 0 0 64 0 0 64
0 0 64 0 0 64 0 0 64 0 0 64
0 0 64 0 0 64 0 0 64 0 0 64
0 0 64 0 0 64 0 0 64 0 0 64
So far best I came up without using loops is this:
[i1,i2] = ndgrid(1:size(Image,1),[1:3:size(Image,2)*size(Image,3),2:3:size(Image,2)*size(Image,3),3:3:size(Image,2)*size(Image,3)]);
ImageRGB = accumarray([i1(:),i2(:),[ones(size(Image,1)*size(Image,2),1);2*ones(size(Image,1)*size(Image,2),1);3*ones(size(Image,1)*size(Image,2),1)] ],Image(:));
May be, there is some function I am not aware of, or more simple way to do this WITHOUT loops. Using them for such seemingly easy task feel just wrong.

What you have is completely fine, but it's very hard to read. Why not just do something very simple and very easy to understand:
ImageRGB = zeros(4,4*3,3);
ImageRGB(:,1:3:end,1) = Image(:,:,1);
ImageRGB(:,2:3:end,2) = Image(:,:,2);
ImageRGB(:,3:3:end,3) = Image(:,:,3);

Related

Is there a difference between WKB and the hex value returned in PostGIS

I've been doing some experimenting with PostGIS, and here's what I've noticed:
Suppose I have a table defined as follows:
CREATE TABLE IF NOT EXISTS geomtest (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
geom geometry(POLYGON, 4326) NOT NULL
);
And I add the following polygon:
SRID=4326;POLYGON((0 0,0 10,10 10,10 0,0 0))
If I query the geom column on its own, I get a Hex representation of the geometry. If I instead call ST_AsBinary(geom), I get a binary representation.
However, when I convert both the hex and binary representations to an array of bytes, the results I get are slightly different. The first comment is the result I get by converting the hex into binary, and the next is straight from ST_AsBinary()
//[1 3 0 0 32 230 16 0 0 1 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
//[1 3 0 0 0 1 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
As you can see, the first 4 bytes are identical; representing whether it's in big or little endian, and the type of geometry (3, in this case a Polygon). The rest of the bytes are the same too. The only difference is there are a few extra bytes added after the first 4.
I wondered if this had to do with representing the projection (SRID=4326), but I haven't found any evidence to that.
If someone could shed some light on this, I'd greatly appreciate it.
I didn't examine the bytes, but I am sure that the difference is the SRID that's not included in the WKB format.
Try st_asewkb instead.

Sparse matrix multiplication complexity and implementation

I have code as below to implement a sparse matrix:
close all
n=10;
p = 1/11;
term13 = -(1 / p^2);
term2 = (2 / p^2);
e=ones(n,1);
z=sparse(n,n);
for j=1:n
vval(j) = barrier(j*p);
z(j)=term2 + vval(j);
end
h = spdiags([term13*e z(j)*e term13*e], -1:1, n,n);
t=full(h)
and barrier is a function that has the value of 600 if 0.4<= j*p <=0.6, otherwise it is zero.
Naturally, I expect the matrix to be as bellow:
242 -121 0 0 0 0 0 0 0 0
-121 242 -121 0 0 0 0 0 0 0
0 -121 242 -121 0 0 0 0 0 0
0 0 -121 242 -121 0 0 0 0 0
0 0 0 -121 842 -121 0 0 0 0
0 0 0 0 -121 842 -121 0 0 0
0 0 0 0 0 -121 242 -121 0 0
0 0 0 0 0 0 -121 242 -121 0
0 0 0 0 0 0 0 -121 242 -121
0 0 0 0 0 0 0 0 -121 242
but surprisingly it has the form
242 -121 0 0 0 0 0 0 0 0
-121 242 -121 0 0 0 0 0 0 0
0 -121 242 -121 0 0 0 0 0 0
0 0 -121 242 -121 0 0 0 0 0
0 0 0 -121 242 -121 0 0 0 0
0 0 0 0 -121 242 -121 0 0 0
0 0 0 0 0 -121 242 -121 0 0
0 0 0 0 0 0 -121 242 -121 0
0 0 0 0 0 0 0 -121 242 -121
0 0 0 0 0 0 0 0 -121 242
To be exact, I expect h(5,5) = h(6,6) = 842 i.e. 242+600.
but it takes barrier =0.
Why is this value incorrect?
I'm not sure:
why the for loop is needed,
why you allocate a nxn sparse matrix z, and then use it with a single index z(j),
where vval is allocated, or used for that matter,
and why you create a sparse diagonal matrix, only to call full in the next line.
But regardless, the issue you asked about is caused by the line
h = spdiags([term13*e z(j)*e term13*e], -1:1, n,n);
which should be
h = spdiags([term13*e, z*e, term13*e], -1:1, n,n);
instead (note z instead of z(j)).

Avoid restarting for-loop

I have a folder with pictures. For each picture, I want to take the maximum value and add it to a new matrix (I created a zeros-matrix, so the zeroes will be replaced with the new values).
This is my code:
function handles = original(hObject, eventdata, handles)
handles.weed=handles.selected;
pic=imread(handles.me);
handles.pic=pic;
axes(handles.axes1)
imshow(pic);
num=max(pic(:))
zeroMat = zeros(1,70);
handles.zeroMat = zeroMat;
for i =1:3
if zeroMat(1,i)~= 0;
i=i+1
else
zeroMat(1,i)=num
break
end
end
zeroMat(1,i)=num
Every time I select a new picture, the zeromat restarts itself to a new zeros-matrix. I know why it happens, but unfortunately I don't know how to overcome it.
This is the output:
pic1:
zeroMat =
Columns 1 through 20
255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 21 through 40
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 41 through 60
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 61 through 70
0 0 0 0 0 0 0 0 0 0
pic2:
Columns 1 through 20
203 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 21 through 40
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 41 through 60
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Columns 61 through 70
0 0 0 0 0 0 0 0 0 0
I can't tell how this function is being invoked, so can't advice how to change up the logic. A rough fix could be to include the line
if ~isfield(handles,'zeroMat')
handles.zeroMat = zeros(1,70);
end % if
which should create handles.zeroMat the first time the function is run. You could then do something like
firstNonzero = find(handles.zeroMat > 0, 1, 'first'); % 'first' not needed, default
handles.zeroMat(firstNonzero) = max(pic(:));

Tallying co-incidences of numbers in columns of a matrix - MATLAB

I have a matrix (A) in the form of (much larger in reality):
205 204 201
202 208 202
How can I tally the co-incidence of numbers on a column-by-column basis and then output this to a matrix?
I'd want the final matrix to run from min(A):max(A) (or be able to specify a specific range) across the top and down the side and for it to tally co-incidences of numbers in each column. Using the above example:
200 201 202 203 204 205 206 207 208
200 0 0 0 0 0 0 0 0 0
201 0 0 1 0 0 0 0 0 0
202 0 0 0 0 0 1 0 0 0
203 0 0 0 0 0 0 0 0 0
204 0 0 0 0 0 0 0 0 1
205 0 0 0 0 0 0 0 0 0
206 0 0 0 0 0 0 0 0 0
207 0 0 0 0 0 0 0 0 0
208 0 0 0 0 0 0 0 0 0
(Matrix labels are not required)
Two important points: The tallying needs to be non-duplicating and occur in numerical order. For example a column containing:
205
202
Will tally this as a 202 occurring with 205 (as shown in the above matrix) but NOT 205 with 202 - the duplicate reciprocal. When deciding what number to use as the reference, it should be the smallest.
EDIT:
sparse to the rescue!
Let your data and desired range be defined as
A = [ 205 204 201
202 208 202 ]; %// data. Two-row matrix
limits = [200 208]; %// desired range. It needn't include all values of A
Then
lim1 = limits(1)-1;
s = limits(2)-lim1;
cols = all((A>=limits(1)) & (A<=limits(2)), 1);
B = sort(A(:,cols), 1, 'descend')-lim1;
R = full(sparse(B(2,:), B(1,:), 1, s, s));
gives
R =
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Alternatively, you can dispense with sort and use matrix addition followed by triu to obtain the same result (possibly faster):
lim1 = limits(1)-1;
s = limits(2)-lim1;
cols = all( (A>=limits(1)) & (A<=limits(2)) , 1);
R = full(sparse(A(2,cols)-lim1, A(1,cols)-lim1, 1, s, s));
R = triu(R + R.');
Both approaches handle repeated columns (up to sorting), correctly increasing their tally. For example,
A = [205 204 201
201 208 205]
gives
R =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
See if this is what you were after -
range1 = 200:208 %// Set the range
A = A(:,all(A>=min(range1)) & all(A<=max(range1))) %// select A with columns
%// that fall within range1
A_off = A-range1(1)+1 %// Get the offsetted indices from A
A_off_sort = sort(A_off,1) %// sort offset indices to satisfy "smallest" criteria
out = zeros(numel(range1)); %// storage for output matrix
idx = sub2ind(size(out),A_off_sort(1,:),A_off_sort(2,:)) %// get the indices to be set
unqidx = unique(idx)
out(unqidx) = histc(idx,unqidx) %// set coincidences
With
A = [205 204 201
201 208 205]
this gets -
out =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
Few performance-oriented tricks could be used here -
I. Replace
out = zeros(numel(range1));
with
out(numel(range1),numel(range1)) = 0;
II. Replace
idx = sub2ind(size(out),A_off_sort(1,:),A_off_sort(2,:))
with
idx = (A_off_sort(2,:)-1)*numel(range1)+A_off_sort(1,:)
What about a solution using accumarray? I would first sort each column independently, then use the first row as first dimension into the final accumulation matrix, then the second row as the second dimension into the final accumulation matrix. Something like:
limits = 200:208;
A = A(:,all(A>=min(limits)) & all(A<=max(limits))); %// Borrowed from Divakar
%// Sort the columns individually and bring down to 1-indexing
B = sort(A, 1) - limits(1) + 1;
%// Create co-occurrence matrix
C = accumarray(B.', 1, [numel(limits) numel(limits)]);
With:
A = [205 204 201
202 208 202]
This is the output:
C =
0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
With duplicates (borrowed from Luis Mendo):
A = [205 204 201
201 208 205]
Output:
C =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0

Easy Way To Accomplish Data Compression in MATLAB?

I am working on an assignment where I have to take a large matrix containing data, and somehow compress the data so that it will be in a form of more manageable size. However, the data needs to be re-utilized as input to something else. (A toolbox, for example). Here's what I've done so far. For this example matrix, I use the find function to give me a matrix of all the indices where the values are non-zero. But I have no idea as to how to use it as input so that the original figure information is retained. I was curious if other folks had any other better (simple) solutions to this.
number_1 = [0 0 0 0 0 0 0 0 0 0 ...
0 0 1 1 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 1 1 1 1 1 1 1 1 0 ...
0 0 0 0 0 0 0 0 0 0];
number = number_1;
compressed_number = find(number);
compressed_number = compressed_number';
disp(compressed_number)
When you have only ones and zeros, and the fill factor is not terribly small, your best bet is to store the numbers as binary numbers; if you need the original size, save it separately. I have expanded the code, showing the intermediate steps a little more clearly, and also showing the amount of storage needed for the different arrays. Note - I reshaped your data into a 13x10 array because it displays better.
number_1 = [0 0 0 0 0 0 0 0 0 0 ...
0 0 1 1 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 1 1 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 0 0 0 1 1 0 0 0 0 ...
0 1 1 1 1 1 1 1 1 0 ...
0 0 0 0 0 0 0 0 0 0];
n1matrix = reshape(number_1, 10, [])'; % make it nicer to display;
% transpose because data is stored column-major (row index changes fastest).
disp('the original data in 13 rows of 10:');
disp(n1matrix);
% create a matrix with 8 rows and enough columns
n1 = numel(number_1);
nc = ceil(n1/8); % "enough columns"
npad = zeros(8, nc);
npad(1:n1) = number_1; % fill the first n1 elements: the rest is zero
binVec = 2.^(7-(0:7)); % 128, 64, 32, 16, 8, 4, 2, 1 ... powers of two
compressed1 = uint8(binVec * npad); % 128 * bit 1 + 64 * bit 2 + 32 * bit 3...
% showing what we did...
disp('Organizing into groups of 8, and calculated their decimal representation:')
for ii = 1:nc
fprintf(1,'%d ', npad(:, ii));
fprintf(1, '= %d\n', compressed1(ii));
end
% now the inverse operation: using dec2bin to turn decimals into binary
% this function returns strings, so some further processing is needed
% original code used de2bi (no typo) but that requires a communications toolbox
% like this the code is more portable
decompressed = dec2bin(compressed1);
disp('the string representation of the numbers recovered:');
disp(decompressed); % this looks a lot like the data in groups of 8, but it's a string
% now we turn them back into the original array
% remember it is a string right now, and the values are stored
% in column-major order so we need to transpose
recovered = ('1'==decompressed'); % all '1' characters become logical 1
display(recovered);
% alternative solution #1: use logical array
compressed2 = (n1matrix==1);
display(compressed2);
recovered = double(compressed2); % looks just the same...
% other suggestions 1: use find
compressed3 = find(n1matrix); % fewer elements, but each element is 8 bytes
compressed3b = uint8(compressed); % if you know you have fewer than 256 elements
% or use `sparse`
compressed4 = sparse(n1matrix);
% or use logical sparse:
compressed5 = sparse((n1matrix==1));
whos number_1 comp*
the original data in 13 rows of 10:
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0
Organizing into groups of 8, and their decimal representation:
0 0 0 0 0 0 0 0 = 0
0 0 0 0 1 1 1 1 = 15
0 0 0 0 0 1 1 0 = 6
1 1 0 0 0 0 0 1 = 193
1 0 1 1 0 0 0 0 = 176
0 0 0 0 1 1 0 0 = 12
0 0 0 0 0 0 1 1 = 3
0 0 0 0 0 0 0 0 = 0
1 1 0 0 0 0 0 0 = 192
0 0 1 1 0 0 0 0 = 48
0 0 0 0 1 1 0 0 = 12
0 0 0 0 0 0 1 1 = 3
0 0 0 0 0 0 0 0 = 0
1 1 0 0 0 0 0 1 = 193
1 1 1 1 1 1 1 0 = 254
0 0 0 0 0 0 0 0 = 0
0 0 0 0 0 0 0 0 = 0
the string representation of the numbers recovered:
00000000
00001111
00000110
11000001
10110000
00001100
00000011
00000000
11000000
00110000
00001100
00000011
00000000
11000001
11111110
00000000
00000000
compressed2 =
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0
recovered =
0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 1 1 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0
0 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0
Name Size Bytes Class Attributes
compressed1 1x17 17 uint8
compressed2 13x10 130 logical
compressed3 34x1 272 double
compressed3b 34x1 34 uint8
compressed4 13x10 632 double sparse
compressed5 13x10 394 logical sparse
number_1 1x130 1040 double
As you can see, the original array takes 1040 bytes; the compressed array takes 17. You get almost 64x compression (not quite because 132 is not a multiple of 8); only a very sparse dataset would be better compressed by some other means. The only thing that gets close (and that is super fast) is
compressed3b = uint8(find(number_1));
At 34 bytes, it is definitely a contender for small arrays (< 256 elements).
Note - when you save data in Matlab (using save(fileName, 'variableName')), some compression happens automatically. This leads to an interesting and surprising result. When you take each of the above variables and save them to file using Matlab's save, the file sizes in bytes become:
number_1 195
compressed1 202
compressed2 213
compressed3 219
compressed3b 222
compressed4 256
compressed5 252
On the other hand, if you create a binary file yourself using
fid = fopen('myFile.bin', 'wb');
fwrite(fid, compressed1)
fclose(fid)
It will by default write uint8, so the file sizes are 130, 17, 130, 34, 34 -- sparse arrays cannot be written in this way. It still shows the "complicated" compression having the best compression.
First of all, you can use the find function to get all non-zero indices of your array, instead of doing it manually. More info here: http://www.mathworks.com/help/matlab/ref/find.html
Anyways, you will need not only matrix but also the original size. So when you pass matrix into whatever, you must also pass in length(number_1). This is because matrix will not tell you how many 0s there were after the last 1. You can figure it out by subtracting the last value of matrix from the original length (there might be an off-by-one error there).