splitting/merging matrices in OpenCV - c++

I am trying to split a Matrix into segments, perform some manipulation of the segments and then merge the segments into a complete matrix again.
To split, I'm doing:
for(int j = 0; j < segments; ++j)
{
Rect r;
if(j == lastSegment)
{
r = Rect(j * segmentWidth, 0, lastWidth, origHei);
}
else
{
r = Rect(j * segmentWidth, 0, segmentWidth - 1, origHei);
}
tmpFrame(r).copyTo(segmentMats[j]);
}
Then to merge them I try:
Mat fullFrame;
for(int i = 0; i < maxSegments; ++i)
{
int segNum = i % segments;
Rect r;
if( segNum == 0) // 1st segment of frame
{
fullFrame.create(origWid, origHei, segmentMats[i].type());
r = Rect(0, 0, segmentWidth - 1, origHei);
}
else if (segNum == lastSegment)
{
r = Rect((i * segmentWidth), 0, lastWidth, origHei);
}
else
{
r = Rect((i * segmentWidth), 0, segmentWidth - 1, origHei);
}
segmentMats[i].copyTo(fullFrame(r));
}
But I keep getting a failed assertion,
OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x
+ roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in Mat
I don't see how this code could set borders outside the assertion values. Can someone see my error?
Thanks.
Edit:
Thanks for the replies. To clarify my variables, I've listed how they are computed below.
origWid and origHei are the height and width of the entire frame
segments = the number of vertical segments a frame is divided into. So segments = 2 means the frame is divided in half vertically.
lastSegment = segments - 1; since they are 0-inclusive indexed, that last segment has this index
segmentWidth = origWid / segments; this floors in case origWid is not evenly divisible by segments
lastWidth = origWid - (lastSegment * segmentWidth); this takes care of the case that origWid is not evenly divisible by segments and captures the number of columns left over in the last segment
segmentMats is an array of segments Mats
segNum = the order of the segment. So if segments == 2, segNum == 0 is the left half of the frame and segNum == 1 is the right half of the frame

Related

How to fix error with cv::boundingRect in OpenCV

I am using OpenCV version 4.0.0. I am trying to stitch some images together and trim the resulting image and while I am able to stitch the images, I am not able to trim the resulting image.
My program keeps aborting with the following error:
libc++abi.dylib: terminating with uncaught exception of type cv::Exception: OpenCV(4.0.0) /Users/RAR/opencv/modules/core/src/umatrix.cpp:545: error: (-215:Assertion failed) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in function 'UMat'
Abort trap: 6
The error occurs at the line stitched = stitched(cv::boundingRect(c)); in the code below.
while (cv::countNonZero(sub) > 0) {
cv::erode(minRect, minRect, cv::Mat()); // Erode the minimum rectangular mask
cv::subtract(minRect, thresh, sub); // Subtract the thresholded image from the minmum rectangular mask (count if there are any non-zero pixels left)
std::vector<std::vector<cv::Point>> cnts4;
cv::findContours(minRect.clone(), cnts4, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
c = cnts4[0];
for (auto iter = cnts4.begin(); iter != cnts4.end(); ++iter) {
if (cv::contourArea(*iter) > cv::contourArea(c)) { // Finds the largest contour (the contour/outline of the stitched image)
c = *iter;
}
}
stitched = stitched(cv::boundingRect(c)); // Extract the bounding box and use the bounding box coordinates to extract the final stitched images
}
Why am I getting this error?
From OP's comments:
stitched: cols: 4295 rows: 2867 bounding rect[4274 x 2845 from (11, 12)]
stitched: cols: 4274 rows: 2845 bounding rect[4272 x 2843 from (12, 13)]
In the first case, the rectangle is trying to extract a size of (4274, 2845) from (11, 12) in the stitched image. This means that it is taking pixels from (11, 12) to (4285, 2857), which is within the bounds of the stitched image since the stitched image has a size of (4295, 2867). No problem.
In the second case, the rectangle is trying to extract a size of (4272, 2843) from (12, 13) in the stitched image. This means that it is taking pixels from (12, 13) to (4284, 2856), which is out of bounds of the stitched image since the stitched image has a size of (4274, 2845). Problem.
The sub-image you are trying to extract is much bigger than the bigger image.
(-215:Assertion failed) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows
The error message also indicates this. roi in the error message refers to the sub-image you are trying to extract using cv::boundingRect(c) and m is the stitched image. The coordinates of this rectangle are beyond the size of the stitched image.
You can test this by setting the coordinates of the rectangle manually.
You should not get an error with stitched(cv::Rect(11, 12, cv::Size(4274, 2845)
You will get the error with stitched(cv::Rect(12, 13, cv::Size(4272, 2843)
Last iteration is the problem, as it won't find any contours.
Maybe you can try something like so :
int nonZeroCount = 1;
while (nonZeroCount)
{
cv::erode(minRect, minRect, cv::Mat());
cv::subtract(minRect, thresh, sub);
nonZeroCount = cv::countNonZero(sub);
if (nonZeroCount)
{
std::vector< std::vector<cv::Point> > cnts4;
cv::findContours(minRect.clone(), cnts4, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
c = cnts4[0];
for (auto iter = cnts4.begin(); iter != cnts4.end(); ++iter)
{
if (cv::contourArea(*iter) > cv::contourArea(c))
{
c = *iter;
}
}
stitched = stitched(cv::boundingRect(c));
}
}

Extract sub-image from image using OpenCV and C++

I'm trying to get a sub-image from a RGB image in openCV and C++. I've seen the other threads on this topic but it didn't worked for me.
This is the code that I use:
Mat src = imread("Images/00011_00025.ppm");
Rect crop(1, 1, 64, 67);
Mat rez = src(crop);
The image a 64x67 dimension, so I don't understand why I get the following error in the console:
Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows)
Any ideas of what is the cause of this error?
Rect crop(1, 1, 64, 67);
The rectangles top left corner is at position (1,1) and its size is set to 64x67.
Mat rez = src(crop);
When using this rectangle to crop the image you're running out of bounds, since the rectangle has an offset of one pixel but the same size as the image to crop.
You could either manually account for the offset on width and height, or, and this is my preferred solution for cropping, make use of a cv::Range.
With ranges you could define a row and column span to perform cropping:
cv::Range rows(1, 64);
cv::Range cols(1, 67);
Mat rez = src(rows, cols);

SIFT orientations in OpenCV implementation

In the OpenCV implementation of SIFT, keypoints has (angles) in degrees (ranging from 180 to -180), which represents the calculated orientations for these keypoints. Since SIFT assign the dominant orientation of a keypoint using 10 degrees bins in a histogram, how we can get this range of angles? shouldn't the values be in 10 degrees steps?
Is that so because of the histogram smoothing?
This is the code where the keypoint.angle is assigned a value, can you help me understanding how we got this value?
float omax = calcOrientationHist(gauss_pyr[o*(nOctaveLayers+3) + layer],
Point(c1, r1),
cvRound(SIFT_ORI_RADIUS * scl_octv),
SIFT_ORI_SIG_FCTR * scl_octv,
hist, n);
float mag_thr = (float)(omax * SIFT_ORI_PEAK_RATIO);
for( int j = 0; j < n; j++ )
{
int l = j > 0 ? j - 1 : n - 1;
int r2 = j < n-1 ? j + 1 : 0;
if( hist[j] > hist[l] && hist[j] > hist[r2] && hist[j] >= mag_thr )
{
float bin = j + 0.5f * (hist[l]-hist[r2]) / (hist[l] - 2*hist[j] + hist[r2]);
bin = bin < 0 ? n + bin : bin >= n ? bin - n : bin;
kpt.angle = 360.f - (float)((360.f/n) * bin);
if(std::abs(kpt.angle - 360.f) < FLT_EPSILON)
kpt.angle = 0.f;
keypoints.push_back(kpt);
}
}
I think that I found the answer to my question.
A parabola is fit to the 3 histogram values closest to each peak to interpolate the peak position for better accuracy. That's why we can get continues range of values instead of 10 step values.
This is a link of how we can fit a parabola to 3 points:
Curve fitting

Path-finding algorithm for a game

I have this assigment in university where I'm given the code of a C++ game involving pathfinding. The pathfinding is made using a wave function and the assigment requires me to make a certain change to the way pathfinding works.
The assigment requires the pathfinding to always choose the path farthest away from any object other than clear space. Like shown here:
And here's the result I've gotten so far:
Below I've posted the part of the Update function concerning pathfinding as I'm pretty sure that's where I'll have to make a change.
for (int y = 0, o = 0; y < LEVEL_HEIGHT; y++) {
for (int x = 0; x < LEVEL_WIDTH; x++, o++) {
int nCost = !bricks[o].type;
if (nCost) {
for (int j = 0; j < 4; j++)
{
int dx = s_directions[j][0], dy = s_directions[j][1];
if ((y == 0 && dy < 0)
|| (y == LEVEL_HEIGHT - 1 && dy > 0)
|| (x == 0 && dx < 0)
|| (x == LEVEL_WIDTH - 1 && dx > 0)
|| bricks[o + dy * LEVEL_WIDTH + dx].type)
{
nCost = 2;
break;
}
}
}
pfWayCost[o] = (float)nCost;
}
}
Also here is the Wave function if needed for further clarity on the problem.
I'd be very grateful for any ideas on how to proceed, since I've been struggling with this for quite some time now.
Your problem can be reduced to a problem known as minimum-bottle-neck-spanning-tree.
For the reduction do the following:
calculate the costs for every point/cell in space as the minimal distance to an object.
make a graph were edges correspond to the points in the space and the weights of the edges are the costs calculated in the prior step. The vertices of the graph corresponds to the boundaries between cell.
For one dimensional space with 4 cells with costs 10, 20, 3, 5:
|10|20|3|5|
the graph would look like:
A--(w=10)--B--(w=20)--C--(w=3)--D--(w=5)--E
With nodes A-E corresponding to the boundaries of the cells.
run for example the Prim's algorithm to find the MST. You are looking for the direct way from the entry point (in the example above A) to the exit point (E) in the resulting tree.

Drawing pool table ball trajectory w/o containers

The statement of the problem follows:
Description:
Write a C++ program that reads the dimensions of a pool table, and prints with 0's the trajectory of a ball after hitting the table in the upper left corner with an angle of 45ยบ.
Input:
Input consists of several cases, each with the number of rows and the number of columns. Both numbers are, at least, 2.
Output:
Print every pool table as shown in the examples.
Observation:
The expected solution doesn't use vectors or alike. This includes vectors, strings, arrays, etc. Mathematically speaking, the expected solution uses O(1) memory in the worst case.
Example:
Sample input:
7 4
10 16
Sample output:
######
#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 #
# 0 0 0 0 0 #
# 0 0 0 0 0 #
# 0 0 0#
##################
The solution to this problem would be fairly easy if you could use for instance a matrix to keep marking the position of the ball after each movement, and following its trajectory until it hits a corner. But they expect you to not use such data structures (it's an introductory programming course, just to practise), so it's a little bit more difficult.
I've thought of a solution which prints the output pool table line per line, keeping track of the ball position, but the main problem I encountered was being able to predict the position of the ball in cases like the 2nd one (10, 16) where when you print the first line you already need to know that the ball will eventually reach it again twice after some collisions with the table.
Any idea on how to solve it?
int positiveMod(int x, int y)
{
return ((x % y) + y) % y;
}
int main()
{
int x,y,sx,sy;
int startX;
int minStartX = 0;
cin >> sy >> sx;
startX = 0;
// compute the various start points on x with y=0, keep the smallest to identify the repeating stride
do
{
startX = (startX + 2 * (sy - 1)) % (2 * (sx - 1));
if ((minStartX == 0) || (startX < minStartX) && (startX != 0))
{
minStartX = startX;
}
}
while (startX != 0);
for(y=0; y < sy; y++)
{
for(x=0; x < sx; x++)
{
if (
(minStartX == 0) && (x == y) || //identity line
(minStartX != 0) && positiveMod(x - y, minStartX) == 0 || // top-left quadrant
(minStartX != 0) && positiveMod( (2 * (sx - 1) - x) - y, minStartX) == 0 || // mirror against y axis
(minStartX != 0) && positiveMod( x - (2 * (sy - 1)) - y, minStartX) == 0 // mirror against x axis
)
{
cout << '0';
}
else
{
cout << ' ';
}
}
cout << endl;
}
}
It still needs the border, and needs fixing for cases where y>x. You can just flip the x/y logic in that case. Hints taken from comments.
The simplest would be to pre-allocate the buffer of the strings to display. Either:
an array of std::strings, string[y + some].
a two dimensional array, char[y + some][x + some].
or a simple char array, char[(x + some)*(y + some)].
+some is there for the borders, the '\0' terminals, etc...
You probably want it dynamically allocated with new so you can resize your buffer for each table. Or just allocate something larger that covers the largest table.
Then, fill the buffer with spaces, and draw the border in the array. Start the ball at (0,0), iterate while your not done, putting the '0's in the buffer. Once done, print the whole buffer, line by line.
Silly implementation of Jeffreys suggestion. Computationally silly, probably easier to do this mathematically but it answers the question...
bool SimulateBallUntil(int width, int height, int x, int y)
{
// start off heading down right
int xInc = 1;
int yInc = 1;
// Start off at pos 0,0
int curX = 0;
int curY = 0;
// Run the path...
for(int iter=0;;++iter)
{
// Check if hit point
if(curX == x && curY == y)
{
return true;
}
// Check if hit corner (ignoring the first iteration which is the left corner)
if(iter && ((curY == 0) || (curY == height-1)) && ((curX == 0) || (curX == width-1)))
{
return false;
}
// Bounce off walls
if(curX + xInc == width || ((curX + xInc)==-1))
{
xInc *= -1;
}
if(curY + yInc == height || (curY + yInc==-1))
{
yInc *= -1;
}
// Move it
curX += xInc;
curY += yInc;
}
}