Generating a discrete random subwindow from a given window - algorithm

I'm working on an image processing application, and I have the problem that I'd like to generate a random subwindow from a given window. For instance, given a 5x5 (pixel) window, I would like to generate a subwindow in a given location in x,y with a given width and height. Currently, it's OK to assume that the width and height of the subwindow will always be equal to each other. The original window, however, does not have this constraint.
Currently, I'm just generating a random width/height for the subwindow that I know fits inside of the original window. Then I generate a valid x,y coordinate that allows that subwindow to fit within the original window. The problem with the current approach is that it doesn't respect the fact that smaller windows are much more plentiful and are therefore more likely to occur. By choosing a random dimension for the subwindow width/height, I'm assuming that their distribution in terms of width and height is uniform, when in fact it is not.
For instance, imagine we are given a 5x5 window. There are 25 possible 1x1 subwindows, 16 possible 2x2 windows, 9 possible 3x3 windows, 4 possible 4x4 windows, and 1 possible 5x5 window. Thus, I should choose a 1x1 window with a probability of about 0.45 (25/(25+16+9+4+1), a 2x2 window with a probability of about 0.29, etc.
I'm not sure how to quickly generate such allowable subwindows from the correct distribution without brute force evaluating all possible windows and then simply choosing one from the list, but I'm fairly sure there's a smarter approach to doing this, I just don't know where to begin.
Thanks!

For an n∙n window, there are (n-m+1)² sub-windows of size m∙m.
In general, for an x∙y window, there are (x-m+1)(y-m+1) sub-windows of size m∙m.
Suggested algorithm:
For each m, calculate the number of sub-windows; build an array of these values.
Sum the values in the array, and generate a uniformly-distributed integer in this range
Map this integer into the relevant sub-window size (using value-map or range-map)
Edit:
Actually you can do better.
There is 1 sub-window with width x, 2 sub-windows with width (x-1), ... , x sub-windows with width (x-(x-1)). In total, there are (1+2+3+...+x)= x(x+1)/2 possible options for width/horizontal-position.
Generate a uniformly-distributed integer r in the range [1, x(x+1)/2].
Determine the width using the following formula: w= x-floor( sqrt(2r-1.75)-0.5 )
Same for the height.

I am going to put this here even though it isn't quite right because my simulation shows that it is close-ish and perhaps we can work out what the flaw is. if it can't be fixed I will delete it:
1) Generate an Px discretely uninform on 1 to X
2) Generate a Py discretely uniform on 1 to Y
3) let Rx = X - Px + 1, let Ry = Y - Py + 1
4) Let A = Rx * Ry - the remaining area we can fill
5) Generate S discretely uniform on 1:min(Rx,Ry)
(Px,Py), (Px+S,Py),(Px,Py+S),(Px+S,Py+S) would define the coordinates of the region
Basically I just select the top left corner of the subregion and then randomly select an allowbale square subregion size given that my subregion starts at Rx, Ry position. The distribution of subregion size has the right diminishing shape, but it is too steep (100,000 iterations of 5x5):
1 2 3 4 5
0.60427 0.24523 0.10356 0.03875 0.00819

Related

Having more control over the thinning algorithm?

I have some text documents where I want to thin the text to varying widths such as 2 pixel wide strokes, 4 pixel wide and so on.
I know that matlab already has the thinning algorithm in bwmorph and one can get to the one pixel wide thinning by using
thinned = bwmorph(bw_image, 'thin', 'n=Inf');
But this thins the image to 1 pixel width. changing the value of n does not produce the desired result. Is there any way I could ensure thinning to n-pixel width?
You could always thin the characters first, then artificially expand their skeletons by performing morphology. For expanding, morphological dilation is most suitable. As such, thin the characters using the standard thinning algorithm, then dilate the result after using a suitable structuring element with a good size. The size of the structuring element should dictate how thick the thinned result is.
To further exemplify my point, here's an example with an image I found on Google:
Reading this in with MATLAB and converting to binary:
im = im2bw(imread('https://lh3.ggpht.com/aWaaZ-BsAXSYyyHRlube_NkiB-Q-FDx-Wpgg8qi5jqrNvAvNp87amEwSUNr7PdbCizY=w300'));
This is what we get:
Performing a thinning gives us:
thinned = bwmorph(im, 'thin', 'n=Inf');
If you want to increase the thickness of the thinning result so that the thickness is n pixels, use a basic square structuring element with size n x n and use this with the imdilate function, which performs morphological dilation on binary images. In general, to increase the thickness of the text to have an overall thickness of n pixels, you would choose the size of the square structuring element to be n.
Here are some examples of what I have discussed above.
n = 2
This would increase the thinning to be 2 pixels wide:
se = strel('square', 2);
expand = imdilate(thinned, se);
imshow(expand);
The function strel defines different structuring elements, but we will choose the square one via 'square' flag. Dilating the thinned image that you see above, we get:
n = 5
Simply change the structuring element to size to 5 x 5, and we get:
se = strel('square', 5);
expand = imdilate(thinned, se);
imshow(expand);
If you take any of the results and zoom into the text, you will see that the width of each stroke is indeed either 2 or 5 pixels. However, the assumption with the above code is that each character is sufficiently separated to allow the variable thickness of each stroke to be maintained. Should the characters be very close together, then dilation will merge these text characters together... but the thinning algorithm will most likely give you bad results even before dilation.

Tile placement algorithm

I have this field of tiles which is 36 x 36 inches wide and high.
So I have blocks 8x8, 6x6, 6x8, 4x8 which can be rotated 90 degrees to fit wherever possible.
My task is to make application that calulates which and how many blocks should be chosen so that all together fit in to a given wall oppening. In this example oppening 36 x 36.
Note: The oppening should be filled with as least as possible tiles, meaning bigger tiles have priority
Which algorithm should I use for tile placement?
Another example. Field 30 x 30 is drawn like this:
50 x 50
Since amit gave the general case answer, I'll make this one specific. With those four blocks sizes, and assuming it's even possible (dimensions are even and >= 6, etc), you can use a semi-greedy algorithm:
The first obective is to maximize the number of 8x8 blocks. To do that, you need to figure out how many 6 size blocks you need in each direction. For each dimension, just check for divisibility by 8. If it's not divisible, subtract 6. Repeat until divisible (it shouldn't take more than 3 tries).
However many times it took, that's how may 6x6 blocks you need in that dimension. Form a rectangle out of them and put it in one corner. Form another rectangle out of 8x8 blocks and put them in the opposite corner. The corners of these two rectangles should be touching.
So now you probably have some leftover space, in the form of two rectangles in the opposite corners. We know that one dimension of each is divisible by 8, and one is divisible by 6. The easy way out here would be to fill it up with 6x8 blocks rotated appropriately, but that doesn't guarantee the maximum number of large(8x8) blocks. For example, with 50x50, you'd have two rectangles of 18x32 left. You could fill them with twelve 6x8 tiles each. You can't even do better than 12 blocks each, but you can fit more 8x8 blocks in there.
If that's not a concern, then you're done (hooray). The bonus this way is that you never need to use the 4x8 blocks.
If you do want to maximize the 8x8 blocks, you'll have to take another step. We're concentrating on the dimension divisible by 6 here, because the 8 is easy. Every size we might need(8x8,6x8,4x8) stacks there perfectly.
For the other side, there are only 3 possible numbers that it could be: 6, 12, and 18. If it's anything else, the first step wasn't done right. Then take the following action:
For 6, add a row of 6x8 (no optimization)
For 12, add a row of 4x8 and a row of 8x8
For 18, add a row of 4x8, a row of 6x8, a row of 8x8
Done!
To see the difference, here we have two 50x50 grids:
Blue - 8x8
Red - 6x6
Green - 6x8
Gray - 4x8
This first example gives us 49 total blocks. The blue is a 32x32 area (16 blocks), red is 18x18 (9 blocks), and the rest is simply filled with 6x8's (24 blocks).
This example still gives 49 total, but there are more 8x8 blocks. Here we have 24 large blocks, rather than 16 in the last example. There are now also 4x8 blocks being used.
Here you go, in Python:
def aux(x):
# in h we store the pre-calculated results for small dimensions
h = {18:[6,6,6], 16:[8,8], 14:[8,6], 12:[6,6], 10:[6,4], 8:[8], 6:[6], 4:[4]}
res = []
while x > 18:
# as long as the remaining space is large, we put there tiles of size 8
res.append(8)
x -= 8
if x not in h:
print("no solution found")
return []
return res + h[x]
def tiles( x, y ):
ax = aux(x) # split the x-dimension into tiles
ay = aux(y) # split the y-dimension into tiles
res = [ [ (x,y) for x in ax ] for y in ay ]
for u in res:
print(u)
return res
tiles( 30, 30 )
The basic idea is that you can solve x and y independently, and then combine the two solutions.
Edit: As Dukeling says this code happily uses 4x6 and 4x4 blocks, contrary to the requirements. However, I think it does that only if there is no other way. So if the results contains such blocks then there is no solution without those blocks. And if you have no Python readily available, you can play with this code here: http://ideone.com/HHB7F8 , just press fork right above the source code.
Assuming you are looking for general case answer, I am sorry to say - but this problem is NP-Complete. It is basically a 2D variation of the Subset Sum Problem.
The subset sum problem: Given a set S and a number x - find out if there is a subset of S that sums to x.
It is easy to see that by reducing the subset sum problem to a "field" of size 1*x and for every s in S we have a tile 1*s - a solution to one problem is also a solution to the other one.
Thus - there is no known polynomial solution to this problem, and most believe one does not exist.
Note however, there is a pseudo-polynomial dynamic programming solution to subset sum that might be utilized here as well.

Calculate the size of windows tiling

I have a number of windows and I'd like to tile them to cover the entire workingarea of the screen. If there are less windows, the individual windows are bigger. The windows are almost squares -- an example is 800x585. They always scale with a fixed ratio.
In this example I only have 4 windows, so my calculation should figure out that filling the screen is done with a 2x2 grid.
In this example I have 8 windows, but instead of 4 cols x 2 rows (which would leave a huge gap underneath the 2nd row because of the fixed ratio) the windows are divided in 3x3 with one empty spot.
The basic idea is to leave as little uncovered screen space as possible. I'm trying to do this in AutoIt, but if someone can explain this in C# or Python I am equally happy :)
A brute force algorithm in pseudo-code:
Begin:
Let n be the number of windows.
Find s such that:
squareroot s is a positive integer
s >= n
Let wasted-area = the actual wasted area in the square grid of s slots.
Let x = square root s
Let y = square root s
For each (i, j) where:
i and j are positive integers
i * j = n --------------> i and j are factors of n
Let a = the actual wasted area of the rectangular grid (i, j)
When a < wasted-area then
set x to i
set y to j
set wasted-area to a
Next (i, j)
Tile screen with (x, y)
End
Note: that if some assumptions can be made about he ratio of the window and the ratio of the screen, then some pairs of factors can be excluded. If no assumptions can be made, then brute force is as good as I can do. Someone with a stronger math background might do better.
Keeping in mind that on a real computer n may seldom be large in an absolute sense, brute force probably is acceptable for many situations.

Usage of the gaussian blur

I read now tons of different explanations of the gaussian blur and I am really confused.
I roughly understand how the gaussian blur works.
http://en.wikipedia.org/wiki/Gaussian_blur
I understood that we choose 3*sigma as the maxium size for our mask because the values will get really small.
But my three questions are:
How do I create a gaussian mask with the sigma only?
If I understood it correctly, the mask gives me the weights, then
I place the mask on the top left pixel. I multiply the weights for
each value of the pixels in the mask. Then I move the mask to the
next pixel. I do this for all pixels. Is this correct?
I also know that 1D masks are faster. So I create a mask for x and a
mask for y. Lets say my mask would look like this. (3x3)
1 2 1
2 4 2
1 2 1
How would my x and y mask look like?
1- A solution to create a gaussian mask is to setup an N by N matrix, with N=3*sigma (or less if you want a coarser solution), and fill each entry (i,j) with exp(-((i-N/2)^2 + (j-N/2)^2)/(2*sigma^2)). As a comment mentioned, taking N=3*sigma just means that you truncate your gaussian at a "sufficiently small" threshold.
2- yes - you understood correctly. A small detail is that you'll need to normalize by the sum of your weights (ie., divide the result of what you said by the sum of all the elements of your matrix). The other option is that you can build your matrix already normalized, so that you don't need to perform this normalization at the end (the normalized gaussian formula becomes exp(-((i-N/2)^2 + (j-N/2)^2)/(2*sigma^2))/(2*pi*sigma))
3- In your specific case, the 1D version is [1 2 1] (ie, both your x and y masks) since you can obtain the matrix you gave with the multiplication transpose([1 2 1]) * [1 2 1]. In general, you can directly build these 1D gaussians using the 1D gaussian formula which is similar as the one above : exp(-((i-N/2)^2)/(2*sigma^2)) (or the normalized version exp(-((i-N/2)^2)/(2*sigma^2)) / (sigma*sqrt(2*pi)))

Do randomly generated 2D points clump together, and how do I stop it?

Say you have a 2D area and you want to generate random points within it, by setting
x = random() * width
y = random() * height
do the points clump around the centre of the area? I remember reading something saying they would, but I can't quite figure out why, and how to prevent it.
Yes. The fewer points you have, the more they will appear to form clusters.
To avoid this, you can use "stratified sampling". it basically means you divide your surface evenly in smaller areas and place your points in there.
For your example, you would divide the square in n*n subsquares. Each point would be placed randomly inside it's subsquare. You can even adjust the randomness factor to make the pattern more or less random/regular:
// I assume random() return a number in the range [0, 1).
float randomnessFactor = 0.5;
int n = 100;
for(int ySub=0; ySub<n; ++ySub){
for(int xSub=0; xSub<n; ++xSub){
float regularity = 0.5 * (1-randomnessFactor);
x = regularity + randomnessFactor * random() + xSub / (float) (n-1);
y = regularity + randomnessFactor * random() + ySub / (float) (n-1);
plot(x, y);
}
}
The reason this works is that you don't actually want randomness. (Clumps are random.) You want the points evenly spread, but without the regular pattern. Placing the points on a grid and offsetting them a bit hides the regularity.
Truly random points will create clusters (or clumps) - it's the effect that can cause confusion when plotting real world data (like cancer cases) and lead to people thinking that there are "hot spots" which must be caused by something.
However, you also need to be careful when generating random numbers that you don't create a new generator every time you want a new number - this will use the same seed value which will result in all the values clustering about a point.
It depends on the distribution of the random number generator. Assuming a perfectly even distribution, then the points are likely to be distributed in a reasonably uniform way.
Also, asking if they clump around the middle is pre-supposing that you don't have the ability to test this!
From my experience, randomly generated points do not clump in the center of the area since every pixel of your screen has the same probability of being selected.
While numbers generated with random() are not truely random, they will be sufficent for putting objects randomly on your screen.
If the random number generator's random() function yields a gaussian distribution, then yes.
You get a clump at the origin if you use polar coordinates instead of carthesian:
r = rand() * Radius;
phi = rand() * 2 * Pi;
The reason is that statistically, the circle r=[0,1] will contain as many points as the ring r=[1,2] even though the ring is three times larger.
Pseudorandom points won't necessarily clump "around the center" of an area, but they will tend to cluster in various random points in an area; in fact these clumps often occur more frequently than people think. A more even distribution of space is often achieved by using so-called quasirandom or low-discrepancy sequences, such as the Sobol sequence, whose Wikipedia article shows a graphic illustrating the difference between Sobol and pseudorandom sequences.
They will not clump, but will form various interesting patterns, in 2d or 3d, depending on the generator you use.

Resources