Grid element stacking in fixed area with fixed width and height elements - algorithm

I’m trying to figure out a solution of stacking or “packing” a series of rectangles and squares into blocks of 3x1 or 6x2 so that there isn’t a block with a protruding element and an uneven end. The width of the blocks can be a maximum of 3, before it has to break on another line. Image link below.
I have tried using 3 systems of measurements, Width + Height, Space (Num of single blocks an element occupies) + Width, Space + Height.
There are 5 possible elements that the grid can use. Image link below.
Using the S + H paradigm they are:
Name | Space x Height
Large - 4 x 2
Fullwidth - 3 x 1
Horizontal - 2 x 1
Vertical - 2 x 2
Item(Single) - 1 x 1
So far the logic has taken me to the situation that a block will always be either 3x1 or 6x2. If the spaces taken exceed 3, it means the block must be at least 2 blocks tall, e.g if there is 2 elements with a total of 4 spaces the remaining elements must occupy only 2 spaces.
I've excluded the possibility of 9x3 for simplicity.
Horizontal + Item
Horizontal = 2 x 1
2 spaces 1 Tall.
Doesn’t fill out a row so we need another element.
Item = 1 x 1
2 + 1 = 3 Spaces
1 = 1 = 1 Tall
Horizontal + Item = 3x1.
Item + Item + Item
1x1 = 1 Space 1 Tall
1x1 + 1x1 = 2 Spaces 1 Tall
1x1 + 1x1 + 1x1 = 3 Spaces 1 Tall
Item + Item + Item = 3x1.
Horizontal + Horizontal + Vertical
2x1 = 2 Space 1 Tall
2x1 + 2x1 = 4 Space 1 Tall
Spaces are > 3, therefore the block must be 6x2 in the end. There are 4 spaces which means there must be elements added so they occupy 2 more spaces and be 2 tall.
2x1 + 2x1 + 2x2 = 6 Spaces 2 Tall
I’m not sure if I’m close to a solution or way off.
The actual order of which elements are put in first doesn’t matter as I’m using an external library to place them in coherent blocks which handles that logic.
E.g Horizontal + Horizontal + Vertical == Horizontal + Vertical + Horizontal.
The logic will be written in PHP if that helps.
Image link here

Related

How to get max sum of k 2x1 or 1x2 tiles in Nx3 matrix

I have a problem where I have a N x 3 matrix with int values. I need to tile it with K 2x1 or 1x2 tiles so that they do not overlap and that I get the maximum sum with the use of dynamic programming.
What would the best way be to solve such a problem?
Example 5 x 3 matrix, K = 5:
2 6 2
6 5 6
2 6 2
1 1 1
1 1 1
Good tiles: (6,2), (6,2), (6,2), (6,5), (2,1)
Result = 38
And an example with an edge case:
2 x 3 Matrix, K = 2
0 4 1
3 4 1
Good tiles: (4,1), (4,3)
Result = 12
Let's define the state of a row as the cells that are covered by some of the K bricks. You have 8 combinations (2^3) from 000 (everything is not covered) to 111 (everything is covered) (you can use binary to encode the state for efficiency).
The dynamic programming matrix will be a[row][tiles][state]. Where row is the row we are processing, going top to bottom, tiles is how many tiles you placed already, state is the state as we defined above and the value is the current maximum sum.
To fill it we go top to bottom. We simplify things by only allowing a vertical tile to be placed on the current and the row above (not below). You can iterate through tile placement combinations between the rows (some are mutually exclusive). You have 3 vertical options and 2 horizontal options on the current row (5 options, for a total of 12 combinations, if I've done the math right). Also iterate through the possible values of 'titles'. For each combination look for all possible combination that allow it's placement on the previous row (so that the vertical tiles don't overlap) take the maximum and update the dynamic matrix. Some combinations are very strict (3 vertical tiles require 000 in the row above), while some are very relaxed (1 horizontal tile allows for every posibility). Do this on paper a few times to see how it works.
As an optimization note that you only need to know the values from the previous row, as the ones above that don't factor into so you can keep only the previous row and current row.
Algorithm should look something like this
For i from 0 to N
for tiles from 0 to K
for each combination
if tiles - combination.tiles < 0: continue
m = -1
for each state compatible with combination.previous_row
m = max(m, a[i-1][tiles - combination.tiles][state])
if m > 0
a[i][tiles][combination.state] = max(a[i][tiles][combination.state], m)
The solution is the maximum between the states on last row with tiles=K.
Complexity will be N*K* 12 combinations * 2^3 states so O(N*K). Memory can be O(K) with the trick I've mentioned above.

Is there a way in MATLAB to compute which discrete image regions enclose or are enclosed by another region?

Given the following image:
I'd like to identify which colored regions are enclosed by or enclose which other colored regions. How might this be computed? Is there a way to create a sort of tree or table that shows this information?
Example: All the red pixels are within the yellow region.
There's no built-in function I know of that can perform this calculation, but here's an idea for how you might get at the information you want...
First, you'll want to take your RGB image from above and turn it into an indexed image and a color map. Here's one way to do it:
img = double(imread('nested_regions.png'))./255; % Load the RGB image
map = unique(reshape(img, [], 3), 'rows'); % Find the unique colors
labelImage = rgb2ind(img, map); % Get a labeled (i.e. indexed) image
nColors = size(map, 1);
Next, you'll want to loop over each labeled region, create a mask, then fill any "holes" in that mask using imfill. If the filled regions contain label values that the rest of the image doesn't, then those regions are completely contained by the region you filled. The code below does this using the setdiff function:
contains = cell(nColors, 1); % Storage for the contained region labels
str=' # | contains\n---+------------\n'; % String for displaying output
for iColor = 1:nColors
maskImage = (labelImage == iColor-1); % Mask of the current region
filledImage = imfill(maskImage, 'holes'); % Mask with holes filled
holeImage = (filledImage & ~maskImage); % Mask of the filled holes
contains{iColor} = setdiff(unique(labelImage(holeImage)), ...
unique(labelImage(~holeImage))).'; %.'
str = [str ' ' num2str(iColor-1) ' | ' num2str(contains{iColor}) '\n'];
end
imshow(labelImage, map, 'InitialMagnification', 60); % Display image
colorbar(); % with a colorbar
fprintf(str); % Create some formatted text output
After running the above, you will get the following:
# | contains
---+------------
0 | 1 2 3 4 5 6 7 8 9
1 | 3 4 5 7 9
2 | 3 4 5 7 9
3 |
4 | 3
5 | 3 4
6 |
7 | 3 4 5
8 |
9 | 3 4 5 7
For example, the red pixels (labeled as region 7) surround all the pixels in labeled regions 3, 4, and 5 (gray-blue, purple, and lime, respectively). Some regions don't form closed contours, like 6 (light purple) and 8 (orange). Region 1 (green) actually isn't fully contained by region 2 (blue) since a spurious pixel or two of green is outside the blue region.
Hope this gives you some ideas!

How to pad an image to match another image's size using padarray in MATLAB

I am trying to use padarray to increase the size of image2, which is 256 x 256 to the size of image1, which is of size 384 x 512, but I get that the new image3 is of size 1024 x 1280. Why and what is wrong?
This is the code I wrote:
Image1 = rgb2gray(imread('pillsetc.png'));
Image2 = (imread('rice.png'));
[height1, width1] = size(Image1);
[height2, width2] = size(Image2);
image3 = padarray(Image2,[height1, width1]);
Your error is arising from the fact that you're misunderstanding how padarray works. The second element specifies how many elements you want to pad along the border of the image for each dimension. For example, doing out = padarray(im, [2 1]); will specify a border of 2 zeroes vertically and 1 zero horizontally.
Example:
>> im = [1 2; 3 4]
im =
1 2
3 4
>> padarray(im, [2 1])
ans =
0 0 0 0
0 0 0 0
0 1 2 0
0 3 4 0
0 0 0 0
0 0 0 0
Take note that the padding is symmetric. So the 2 in the first dimension means that you see a 2 pixel zero border on top of the image and on the bottom. The 1 in the second dimension means that you see a 1 pixel zero border to the left and right of the image. You are specifying the total width and height instead, which isn't correct. In addition, if you have a colour image, width1 and width2 would actually become width*3 where width is the original width of either image.
If you want to do this correctly, you'll need to calculate the correct padding size for the width and height of the image, and you'll also need to get the correct width and height from the two images:
Image1 = rgb2gray(imread('pillsetc.png'));
Image2 = (imread('rice.png'));
height1 = size(Image1,1); %// Change
width1 = size(Image1,2); %// Change
height2 = size(Image2,1); %// Change
width2 = size(Image2,2); %// Change
image3 = padarray(Image2,[(height1-height2)/2, (width1-width2)/2]); %// Change
height1-height2 and width1-width2 finds the difference in height and width, which is the total number of zeroes required in both dimensions. However, because the padding is done symmetrically, what you have to do is divide each value by 2 so half of the difference has this many zeroes on one side and the rest gets placed on the other side for each dimension. In effect, you are placing the smaller image in the centre, and are padding around the centre of the image. Also, bear in mind that this only works for even sized dimensions between both images. If you don't have this, you'll want to perhaps use floor.

Neighboring gray-level dependence matrix (NGLDM) in MATLAB

I would like to calculate a couple of texture features (namely: small/ large number emphasis, number non-uniformity, second moment and entropy). Those can be computed from Neighboring gray-level dependence matrix. I'm struggling with understanding/implementation of this. There is very little info on this method (publicly available).
According to this paper:
This matrix takes the form of a two-dimensional array Q, where Q(i,j) can be considered as frequency counts of grayness variation of a processed image. It has a similar meaning as histogram of an image. This array is Ng×Nr where Ng is the number of possible gray levels and Nr is the number of possible neighbours to a pixel in an image.
If the image function f(i,j) is discrete, then it is easy to computer the Q matrix (for positive integer d, a) by counting the number of times the difference between each element in f(i,j) and its neighbours is equal or less than a at a certain distance d.
Here is the example from the same paper (d = 1, a = 0):
Input (image) matrix and output matrix Q:
I've been looking at this example for hours now and still can't figure out how they got that Q matrix. Anyone?
The method was originally created by C. Sun and W. Wee and was described in a paper called: "Neighboring gray level dependence matrix for texture classification" to which I got access, but can't download (after pressing download the page reloads and that's it).
In the example that you have provided, d=1 and a=0. When d=1, we consider pixels in an 8-pixel neighbourhood. When a=0, this means that we look for pixels that have the same value as the centre of the neighbourhood.
The basic algorithm is the following:
Initialize your NGLDM matrix to all zeroes. The total number of rows corresponds to the total number of possible intensities / values in your image. The total number of columns corresponds to how many pixels are in your neighbourhood plus 1. As such for d=1, we have an 8-pixel neighbourhood and so 8 + 1 = 9. Because there are 4 possible intensities (0,1,2,3), we thus have a 4 x 9 matrix. Let's call this matrix M.
For each pixel in your matrix, take note of this pixel. This goes in the Ng row.
Write out how many valid neighbours there are that surround this pixel.
Count how many times you see the neighbouring pixels matching that pixel in Step #1. This is your Nr column.
Once you figure out the numbers in Step #1 and Step #2, increment this location by 1.
Here's a slight gotcha: They ignore the border locations. As such, you don't do this procedure for the first row, last row, first column or last column. My guess is that they want to be sure that you have an 8-pixel neighbourhood all the time. This is also dictated by the distance d=1. You must be able to grab every valid pixel given a centre location at d=1. If d=2, then you would have to make sure that every pixel in the centre of the neighbourhood has a 25 pixel neighbourhood and so on.
Let's start from the second row, second column location of this matrix. Let's go through the steps:
Ng = 1 as the location is 1.
Valid neighbours - Starting from the top left pixel in this neighbourhood, and scanning left to right and omitting the centre, we have: 1, 1, 2, 0, 1, 0, 2, 2.
How many values are equal to 1? Three times. Therefore Nr = 3
M(Ng,Nr) += 1. Access row Ng = 1, and access row Nr = 3, and increment this spot by 1.
Want to know how I figured out they don't count the borders? Let's do the bottom left pixel. That location is 0, so Ng = 0. If you repeat the algorithm that I just said, you would expect Ng = 0, Nr = 1, and so you would expect at least one entry in that location in your matrix... but you don't! If you do similar checks around the border of the image, you'll see that entries that are supposed to be there... aren't. Take a look at the third row, fifth column. You would think that Ng = 1 and Nr = 1, but we don't see that in the matrix.
One more example. Why is M(Ng,Nr) = 4, Ng = 2, Nr = 4? Well, take a look at every pixel that has a 2 in it. The only valid locations where we can capture an 8 pixel neighbourhood successfully are the row=2, col=4, row=3, col=3, row=3, col=4, row=4, col=3, and row=4, col=4. By applying the same algorithm that we have seen, you'll see that for each of those locations, Nr = 4. As such, we see this combination of Ng = 2, Nr = 4 four times, and that's why the location is set to 4. However, in row=3, col=4, this actually is Nr = 5, as there are five 2s in that neighbourhood at that centre. That's why you see Ng = 2, Nr = 5, M(Ng,Nr) = 1.
As an example, let's do one of the locations. Let's do the 2 smack dab in the middle of the matrix (row=3, col=3):
Ng = 2
What are the valid neighbouring pixels? 1, 1, 2, 0, 2, 3, 2, 2 (omit the centre)
Count how many pixels equal to 2. There are four of them, so Nr = 4
M(Ng,Nr) += 1. Take Ng = 2, Nr = 4 and increment this spot by 1.
If you do this with the other valid locations that have 2, you'll see that Nr = 4 each time with the exception of the third row and fourth column, where Nr = 5.
So how would we implement this in MATLAB? What you can do is use im2col to transform each valid neighbourhood into columns. What I'm also going to do is extract the centre of each neighbourhood. This is actually the middle row of the matrix. We will then figure out how many pixels for each neighbourhood equal the centre, sum them up, and this will determine our Nr values. The Ng values will be the middle row values themselves. Once we do this, we can compute a histogram based on these values just like how the algorithm is doing to get our matrix. In other words, try doing this:
% // Your example
A = [1 1 2 3 1; 0 1 1 2 2; 0 0 2 2 1; 3 3 2 2 1; 0 0 2 0 1];
B = im2col(A, [3 3]); %//Convert neighbourhoods to columns - 3 x 3 means d = 1
C = bsxfun(#eq, B, B(5,:)); %//Figure out a logical matrix where each column tells
%//you how many elements equals the one in each centre
D = sum(C, 1) - 1; %// Must subtract by 1 to discount centre pixel
Ng = B(5,:).' + 1; % // We must make this into a column vector, and we also must
% // offset by 1 as MATLAB starts indexing by 1.
%// Column vector is for accumarray input
Nr = D.' + 1; %// Do the same for Nr. We could have simply left out the + 1 here and
%// took out the subtraction of -1 for D, but I want to explicitly show
%// the steps
Q = accumarray([Ng Nr], 1, [4 9]); %// 4 unique intensities, 9 possible locations (0-8)
... and here is our matrix:
Q =
0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0
0 0 0 0 4 1 0 0 0
0 1 0 0 0 0 0 0 0
If you check this, you'll see this matches with Q.
Bonus
If you want to be able to accommodate for the algorithm in general, where you specify d and a, we can simply follow the guidelines of your text. For each neighbourhood, you find the difference between the centre pixel and all of the other pixels. You count how many pixels are <= a for any positive integer d. Note that this will create a 2*d + 1 x 2*d + 1 neighbourhood we need to examine. We can also make this into a function. Without further ado:
%// Set A up yourself, then use a and d as inputs
%// Precondition - a and d are both integers. a can be 0 and d is positive!
function [Q] = calculateGrayDepMatrix(A, a, d)
neigh = 2*d + 1; % //Calculate rows/columns of neighbourhood
numTotalNeigh = neigh*neigh; % //Calculate total number of pixels in neighbourhood
middleRow = ceil(numTotalNeigh / 2); %// Figure out which index the middle row is
B = im2col(A, [neigh neigh]); %// Make into columns
Cdiff = abs(bsxfun(#minus, B, B(middleRow,:))); %// For each neighbourhood, subtract with its centre
C = Cdiff <= a; %// For each neighbourhood, figure out which differences are <= a
D = sum(C, 1) - 1; % //For each neighbourhood, add them up
Ng = B(middleRow,:).' + 1; % // Determine Ng and Nr, and find Q
Nr = D.' + 1;
Q = accumarray([Ng Nr], 1, [max(Ng) numTotalNeigh]);
end
We can recreate the scenario we showed above with the example matrix by:
A = [1 1 2 3 1; 0 1 1 2 2; 0 0 2 2 1; 3 3 2 2 1; 0 0 2 0 1];
Q = calculateGrayDepMatrix(A, 0, 1);
Q is thus:
Q =
0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0
0 0 0 0 4 1 0 0 0
0 1 0 0 0 0 0 0 0
Hope this helps!

Matrix linear indexing

I need to traverse a rectangular grid in continuous manner. Here is an example of what I want, the number means sequence:
+ x
y 0 1 2
5 4 3
6 7 8
At each step I know the index in matrix. Is there any way to calculate the coordinates? The inverse mapping for [x + y * width] doesn't help, beacuse it creates "steps" or "jumps". Is there any solution?
Here is explanation for "steps" mentioned above:
+ x
y 0 1 2
3 4 5 //at this moment the X coordinate changes by 3, thus create step
6 7 8
y = index / width
if( y % 2 == 0 )
x = index % width
else
x = width - index % width - 1
I think that should do it. It's a single modification of the standard way of calculating with "steps" as you call them. You are only changing the way the calculation is done based upon the row.
so you need to first increase the "x" component and then decrease right - so that you get a kind of snake-behavior? You will need an if statement (or some kind of modulo - magic). Let my try the magic:
y := floor(i/columnCount)
x = (y mod 2)*(i - y*columCount) + ((y+1) mod 2)*((columnCount -1) - (i - y*columnCount))

Resources