How to reduce or-tools cpsat model complexity? - or-tools

Our team is trying out the or-tools cp-sat solver for a geometric puzzle. Here we have a 2D matrix with n x n size where rectangles of varying horizontal size and a fixed vertical size, are placed on. These rectangles have certain constraints i.e. only 2 of a certain size can be placed next to each other or the joints between rectangles cannot be placed above each other.
When we setup and run our model, if the matrix size becomes large > 20x20 rows/columns, performance drops exponentially. This is only with a 2D interval constraint. We are curious if this is too large of a problem for the cp solver to complete in a reasonable time or that we have setup our model incorrectly.
Our model is setup in such a way that there are more rectangles than could be needed in the matrix. As such rectangles can take a horizontal size 0. The other horizontal sizes are 2,3 and 4. The vertical size of each rectangle is always 1. So if we have 20x20 rows/columns of the matrix our number of rectangles is rows*(columns/2) = 200. Now an IntVar of the horizontal size, start column, end column and start row is created. Furthermore, horizontal and vertical interval vars are created.
The constraints are then:
model.AddNoOverlap2D(horizontal_intervals, vertical_intervals)
model.Add(LinearExpr.Sum(rectangle_sizes) == (columns * rows))
Solving this problem, where the matrix is filled with rectangles of size 4, already takes 20 seconds to complete.

Related

An gridded area is divided into several sub-areas. How to track each grid's membership?

I have a square that is grid into many small cells. Each cell has a size of 0.1*0.1. Several zigzag lines are drawn to divided that square into sub-area. The zigzag lines only follow the cell edges.
The vertices that these zigzag lines cross are calculated and stored in a different matrix. In this case, there are 6 zigzag lines that meet at the center, thus there are 6 matrix that store the coordinated of the lines.
The center of each cell, as well as the four vertices, are calculated and store in a big matrix. Now, if I want to track to which sub-area each of the cell belongs, what looping algorithm should I use?
Say, we mark the top left area as 1, and count it clockwise. Then the cells in the top left area should be marked 1. Cells in the top right area should be marked 2, and so on.
From the given example, we can infer that the areas are "sectors" with a common center and the radial lines meeting the outline.
You can get the starting edges (on the outline) of the zigzag lines from their respective array. They each separate two cells belonging to different areas. By computing the angles and sorting them, you can number the areas increasingly and associate them a starting cell.
Now "draw" the zigzag lines in the big matrix (every cell having two flags that indicate the presence of an edge to the right or below it). Then, starting from the cell of every area, use a seed filling algorithm. You will need to modify the basic algorithm to account for the presence of the edges.

Area integral invariant computation

Area integral invariant is a type of signature used in image processing. Does anyone know the algorithm for the computation of AII?
i.e. I want to calculate the area enclosed by a boundary and the intersected circle...
the boundary is not a curve with a equation but from a arbitrary profile. The image below is just a schematic drawing. The real boundary can be much more complex with the enclosed area in various positions of the boundary, i.e. top, bottom, left side...
The red area. I am using MATLAB and the image is mostly binary ones.
If you know the equation of the circle and the line then its quite easy, if you are doing this in an image.
Select the pixels that are inside the circle (easily done with the equation of the circle). If you need to compute the AII as a ratio, then count the pixels you have.
Separate the pixels above and below the line. You can do this easily if you know the equation of the line, or the value of the line in each column. Go column by column and discard the pixels that are above the value of the line. Count the result.
That's it! If you want the AII without a ratio, then the number of pixels in 2 is the result. If you want it as a ratio, divide the number of pixels of 2 by the number of pixels of 1.
If you only have the image and no equations, you can still select all the pixels you want by giving your algorithm one pixel in the area you want to calculate and then recusivly check all neighbors and add them to you area, if they are white. When you are done, just count the pixels you have. The result is in some sense the are of the region you wanted.

How to determine Boundary Cut Utilization MATLAB?

Working on 2D Rectangular Nesting. Need to find the utilization percentage of the material. Assuming i have the length, breadth, left-bottom position of each rectangle. What is the best way to determine the Boundary-Cut Utilization?
Objective:- To find the AREA under the RED Line.
Sample images attached to depict what i have done and what i need.
What i have done
what i need
Another Example image of rectangles packed with allowance
If you're interested in determining the total "area" underneath the red line, one suggestion I have is if you have access to the Image Processing Toolbox, simply create a binary image where we draw all of the rectangles on the image at once, fill all of the holes, then to determine the area, just determine the total sum of all of the binary "pixels" in the image. You said you have the (x,y) positions of the bottom-left corner of each rectangle, as well as the width and height of each rectangle. To make this compatible in an image context, the y axis is usually flipped so that the top-left corner of the space is the origin instead of the bottom-left. However, this shouldn't affect our analysis as we are simply reflecting the whole 2D space downwards.
Therefore, I would start with a blank image that is the same size as the grid you are dealing with, then writing a loop that simply sets a rectangular grid of coordinates to true for each rectangle you have. After, use imfill to fill in any of the holes in the image, then calculate the total sum of the pixels to get the area. The definition of a hole in an image processing context is any black pixels that are completely surrounded by white pixels. Therefore, should we have gaps that are surrounded by white pixels, these will get filled in with white.
Therefore, assuming that we have four separate variables of x, y, width and height that are N elements long, where N is the number of rectangles you have, do something like this:
N = numel(x); %// Determine total number of rectangles
rows = 100; cols = 200; %// Define dimensions of grid here
im = false(rows, cols); %// Declare blank image
%// For each rectangle we have...
for idx = 1 : N
%// Set interior of rectangle at location all to true
im(y(idx)+1:y(idx)+height(idx), x(idx)+1:x(idx)+width(idx)) = true;
end
%// Fill in the holes
im_filled = imfill(im, 'holes');
%// Determine total area
ar = sum(im_filled(:));
The indexing in the for loop:
im(y(idx)+1:y(idx)+height(idx), x(idx)+1:x(idx)+width(idx)) = true;
Is a bit tricky to deal with. Bear in mind that I'm assuming that y accesses the rows of the image and x accesses the columns. I'm also assuming that x and y are 0-based, so the origin is at (0,0). Because we access arrays and matrices in MATLAB starting at 1, we need to offset the coordinates by 1. Now, the beginning index for the row starts from y(idx)+1. We end at y(idx) + height(idx) because we technically start at y(idx)+1 but then we need to go up to height(idx) but then we also subtract by 1 as your coordinates begin at 0. Take for example a line with the width of 20, from x = 0 to x = 19. This width is 20, but we draw from 0, up to 20-1 which is 19. Because of the indexing starting at 1 for MATLAB, and the subtraction of 1 due to the 0 indexing, the +1 and -1 cancel, which is why we are just left with y(idx) + height(idx). The same can be said with the x coordinate and the width.
Once we draw all of the rectangles in the image, we use imfill to fill up the holes, then we can sum up the total area by just unrolling the whole image into a single vector and invoking sum. This should (hopefully) get what you need.
Now, if you want to find the area without the filled in holes (I suspect this is what you actually need), then you can skip the imfill step. Simply apply the sum on the im, instead of im_filled, and so:
ar = sum(im(:));
This will sum up all of the "white" pixels in the image, which is effectively the area. I'm not sure what you're actually after, so use one or the other depending on your needs.
Boundary-Cut Area without using Image Processing Toolbox.
The Detailed question description and answer could be found here
This solution is applicable only to Rectangular parts.

How to make "well" a ridge-shape from a given 2d line? (gaussian, matlab)

My goal is to make a ridge(mountain)-like shape from the given line. For that purpose, I applied the gaussian filter to the given line. In this example below, one line is vertical and one has some slope. (here, background values are 0, line pixel values are 1.)
Given line:
Ridge shape:
When I applied gaussian filter, the peak heights are different. I guess this results from the rasterization problem. The image matrix itself is discrete integer space. The gaussian filter is actually not exactly circular (s by s matrix). Two lines also suffer from rasterization.
How can I get two same-peak-height nice-looking ridges(mountains)?
Is there more appropriate way to apply the filter?
Should I make a larger canvas(image matrix) and then reduce the canvas by interpolation? Is it a good way?
Moreover, I appreciate if you can suggest a way to make ridges with a certain peak height. When using gaussian filter, what we can do is deciding the size and sigma of the filter. Based on those parameters, the peak height varies.
For information, image matrix size is 250x250 here.
You can give a try to distance transform. Your image is a binary image (having only two type of values, 0 and 1). Therefore, you can generate similar effects with distance transform.
%Create an image similar to yours
img=false(250,250);
img(sub2ind(size(img),180:220,linspace(20,100,41)))=1;
img(1:200,150)=1;
%Distance transform
distImg=bwdist(img);
distImg(distImg>5)=0; %5 is set manually to achieve similar results to yours
distImg=5-distImg; %Get high values for the pixels inside the tube as shown
%in your figure
distImg(distImg==5)=0; %Making background pixels zero
%Plotting
surf(1:size(img,2),1:size(img,1),double(distImg));
To get images with certain peak height, you can change the threshold of 5 to a different value. If you set it to 10, you can get peaks with height equal to the next largest value present in the distance transform matrix. In case of 5 and 10, I found it to be around 3.5 and 8.
Again, if you want to be exact 5 and 10, then you may multiply the distance transform matrix with the normalization factor as follows.
normalizationFactor=(newValue-minValue)/(maxValue-minValue) %self-explanatory
Only disadvantage I see is, I don't get a smooth graph as you have. I tried with Gaussian filter too, but did not get a smooth graph.
My result:

Inpainting pixels between regions with nearest color in MATLAB

Is there an efficient way to fill in pixels with a value of zero between pixels with non-zero values with the nearest non-zero value, while leaving the rest of pixels at zero untouched?
To clarify, I am looking to inpaint those pixels whose closest distance to a non-zero pixel is lower than a given value (e.g. 4 pixels).
The image is initially represented as a matrix of uint32 integers.
In the example above, all the thin cracks between the colored regions should be filled with the surrounding color, while large black regions should remain the same (i.e. the routine should inpaint the pixels between the colored regions).
I imagine there is a way to do this via interpolation. In either case, I am looking for a relatively efficient solution.
Given an input matrix A:
b = imclose(A==0,ones(3,3)) %only the big zero regions
c = imdilate(A,ones(3,3)) %inpainting all neighboring pixels
d = zeros(size(A));
d(b==0) = c(b==0); %copy the inpainting only in places where there are no big regions
I haven't tested it, so there may be some problems with the code. (if you made changes to the code to make it work please edit my answer)