Find random points inside binary mask

5 次查看(过去 30 天)
I am extracting random tiles from huge binary image masks. I do this by finding the random upper left corner of the tiles as shown below. And then check if enough of the tile is inside the mask. But I have some memory issues.
[y_cord, x_cord] = find(mask); % Find all xy-pairs inside mask
xy_rand = randperm(length(x_cord), 1e4); % Select 1e4 random xy-pairs
This works fine for most of my masks, but when the masks are getting really big I'm running out of memory. As an example: one of the masks ( 48500x63000 logical) result in x_cord and y_cord having the dim 11e9 x 1, which is more than my machine can handle.
Any ideas on how to solve this more memory efficient?

采纳的回答

Jan
Jan 2018-2-7
编辑:Jan 2018-2-8
Using the linear index needs the half of the memory:
index = find(mask);
select = index(randperm(length(index), 1e4));
[y, x] = ind2sub(size(mask), select);
Another approach:
n = sum(mask(:));
v = false(1, n);
s = randperm(n, 1e4);
v(s) = true;
mask2 = false(size(mask));
mask2(mask) = v;
[y_cord, x_cord] = find(mask2);
This uses the mask as logical mask to create a new mask with 1e4 true elements.
The problem would be leaner in a loop:
% !!! UNTESTED !!!
idx = zeros(1, 1e4);
n = sum(mask(:)); % Number of all TRUE elements
s = sort(randperm(n, 1e4)); % Select 1e4 of them
si = 1; % index related to s
c = 0; % Counter of found TRUE elements
for k = 1:numel(mask)
if mask(k) % If element is TRUE
c = c + 1; % Increase the counter
if c == s(si) % If counter equals current s
idx(si) = k; % Remember this linear index
si = si + 1; % Proceed to the next s
if si > length(s) % Break if 1e4 elements are found
break;
end
end
end
end
[y, x] = ind2sub(size(mask), idx);
This would be very fast as C-Mex function and it does not use any temporary memory.
  4 个评论
Kay Raymond
Kay Raymond 2018-2-8
No worries. I went for alternative 1. It helped me alot :)
Thaks again.
Jan
Jan 2018-2-8
@Kay: I'm eager to implement this in C, because I needed a "nested logical indexing" multiple times by my own also. The job is easy, but does not match to Matlab's vectorized methods.
X = rand(huge, giant);
mask = logical(X < 0.5);
mask2 = 1:1000:nnz(mask); % Every 1000th selected element
Y = X(mask); % Very large temporary array
Z = Y(mask2); % Small result
Here it would be useful, if mask and mask2 could be "linked" at first. mask2 could be a linear index vector or another logical mask.
I was astonished, that even the logical indexing can be accelerated compared to the built-in methods: FEX: CopyMask. Then a "linked masking" might be nice.

请先登录,再进行评论。

更多回答(0 个)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by