I've got a lower triangular MatrixXd and I want to copy its lower values to the upper side as it'll become a symmetric matrix. How can I do it?
So far I've done:
MatrixXd m(n,n);
.....
//do something with m
for(j=0; j < n; j++)
{
for(i=0; i<j; i++)
{
m(i,j) = m(j,i);
}
}
Is there a fastest way to do it? I was thinking of some internal method that is able to "copy" the lower triangular matrix to the upper.
Say I've got this matrix, we call m:
1 2 3
4 5 6
7 8 9
what I need to obtain in m is :
1 4 7
4 5 8
7 8 9
I also know you can get the upper or the lower part of the matrix to do something:
MatrixXd m1(n,n);
m1 = m.triangularView<Eigen::Upper>();
cout << m1 <<endl;
1 2 3
0 5 6
0 0 9
But I can't yet get what I want...
I assume here that you are referring to working with the Eigen3 c++ library. This is not clear from your question. if not, you should consider it. In any case, within Eigen, there is no need to actually copy the triangular part, to get a selfadjoint matrix. Eigen has the concept of views, and you can use a self adjoint view in order to perform an operation like e.g.
using namespace Eigen;
MatrixXd m(m,n);
...
(generate uppper triangular entries in m)
...
VectorXd r(n), p(n);
r = m.selfadjointView<Upper>() * p;
here is a small example to illustrate using fixed size matrices:
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
int main()
{
Matrix2d m,c;
m << 1, 2,
0, 1;
Vector2d x(0,2), r;
// perform copy operation
c = m.selfadjointView<Upper>();
cout << c << endl;
// directly apply selfadjoint view in matrix operation
// (no entries are copied)
r = m.selfadjointView<Upper>() * x;
}
the output will be
[1, 2,
2, 1].
now, the result in r is the same as if you had used c * x instead. Just that there is no need for copying the values in the original matrix to make it selfadjoint.
In case the selfadjointView is not an option for you, the solution is to use triangularView on the destination matrix:
m.triangularView<Lower>() = m.transpose();
The simplest way I can think of is by copying the upper part of m matrix trasposed on the upper part:
m.triangularView<Upper>() = m.transpose();
For example, the following code:
MatrixXd m(3,3);
m << 1, 2, 3, 4, 5, 6, 7, 8, 9;
m.triangularView<Upper>() = m.transpose();
std::cout << m << std::endl;
Gives the output you asked for:
1 4 7
4 5 8
7 8 9
Regards.
Simply:
m = m.selfadjointView<Upper>();
I think you are doing it the right way. If you knew some details about the memory layout of data in the matrix you could use some low-level optimizations. One of the techniques is loop tiling.
If speed is a big issue, I would not copy anything just decorate/wrap the matrix object with a coordinate inverting object that would flip the (x,y) to (y,x). if you make the () operator an an inline function it will not incur any significant cost when you use it.
This works, you can cut something but you need at least n*m/2 (less something), so only of a 2x
edit: I see that you use this matrixd object... the syntax is different, but the algorithm is this, anyway
#include <stdio.h>
int main ( )
{
int mat [ 4 ] [ 4 ];
int i, j;
mat [ 0 ] [ 0 ] = 0;
mat [ 0 ] [ 1 ] = 1;
mat [ 0 ] [ 2 ] = 2;
mat [ 0 ] [ 3 ] = 3;
mat [ 1 ] [ 0 ] = 4;
mat [ 1 ] [ 1 ] = 5;
mat [ 1 ] [ 2 ] = 6;
mat [ 1 ] [ 3 ] = 7;
mat [ 2 ] [ 0 ] = 8;
mat [ 2 ] [ 1 ] = 9;
mat [ 2 ] [ 2 ] = 10;
mat [ 2 ] [ 3 ] = 11;
mat [ 3 ] [ 0 ] = 12;
mat [ 3 ] [ 1 ] = 13;
mat [ 3 ] [ 2 ] = 14;
mat [ 3 ] [ 3 ] = 15;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
printf ( "%02d", mat [ i ] [ j ] );
printf ( "\n" );
}
printf ( "\n" );
for ( i = 1; i < 4; i++ )
{
for ( j = 0; j < i; j++ )
mat [ j ] [ i ] = mat [ i ] [ j ];
}
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
printf ( "%02d ", mat [ i ] [ j ] );
printf ( "\n" );
}
printf ( "\n" );
scanf ( "%d", &i );
}
Related
I'm currently working on a small game to play in the console. I'm trying to make player movement, but when I try to replace a certain element within the level array, it deletes the rest of the array.
The only movement in the code right now is moving right (type 2 in the console to move right)
#include <iostream>
using namespace std;
#define con std::cout <<
#define newline std::cout << '\n'
#define text std::cin >>
#define end return 0
#define repeat while (true)
int width, height;
int rprog;
int x, y, z;
int playerpos;
int input;
double level[] =
{1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1,
1, 0, 2, 0, 0, 1,
1, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1};
const char *display[] = {" ", "[ ]", "[X]"};
int render () {
x = 1;
y = 1;
while (x < 37) {
z = level[x - 1];
con display[z];
x = x + 1;
y = y + 1;
if (y == 7) {
y = 1;
newline;
}
}
end;
}
int player () {
con "Please make your next move : w: 1, a: 2, s: 3, d: 4";
newline;
con "Current position: " << playerpos;
newline;
text input;
if (input == 2) {
level[playerpos] = 0;
playerpos = playerpos - 1;
level[playerpos] = 3;
}
end;
}
int main() {
playerpos = 15;
while (true) {
render ();
player ();
}
end;
}
I'm using this website for coding currently: https://www.programiz.com/cpp-programming/online-compiler/
This is the output:
[ ][ ][ ][ ][ ][ ]
[ ] [ ]
[ ] [X] [ ]
[ ] [ ]
[ ] [ ]
[ ][ ][ ][ ][ ][ ]
Please make your next move : w: 1, a: 2, s: 3, d: 4
Current position: 15
2
[ ][ ][ ][ ][ ][ ]
[ ] [ ]
[ ]
And then it cuts off rendering the level.
I'm confused. What am I doing wrong?
Arrays
Array indices start with 0 in C++.
You set the item at the new position to 3:
level[playerpos] = 3;
However, your array for the display types has only 3 elements (0, 1, 2):
const char *display[] = {" ", "[ ]", "[X]"};
Thus, you encounter undefined behaviour, as you have an out of bounds access.
Note also, that your initial array correctly uses a 2 for the player position, and thus works.
However, it also has a off-by-1 error: Your initialize the playerpos = 15, but place the 2 at index 14. Thus, the initial rendering is wrong. So the first movement will not be correct, and seem to stay on the same position.
Types
As #RemyLebeau mentions, why do you use a double array for the game state? Not only would other types be more appropriate, especially double can lead to serious, hard to debug probles. Not all integers are perfectly representable by a double, and type conversions could lead to different results.
Just for an example: if you add states 4 and 5, and imagine a double could not represent 5 exactely, but store it as 4.99999999999999999 instead. When accessing the array, integer conversion could render a state 4 instead.
Check this question and answer for details
Defines
As #KarenMelikyan mentioned in a comment, those #defines are a bad idea. It makes your code much harder to read for others, and is a bad a habit to develop. Better get aquainted with correct C++ syntax and use it.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I found an example of std::vector in http://www.cplusplus.com/reference/vector/vector/data/.
// vector::data
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
and the result is
myvector contains: 10 20 0 100 0
My question may be silly but I don't really understand what happened here. We got a direct pointer to the memory of the vector. Then we assign the value 10 for the first element (index 0), move to the second element and assign the value 20 to it (index 1). Finally, we assign the value 100 for the third element (index 2). Should the answer be as follow?
10 20 100 0 0
This picture might help explain
int* p = myvector.data();
[ ] [ ] [ ] [ ] [ ]
^
*p = 10;
[10 ] [ ] [ ] [ ] [ ]
^
++p;
[10 ] [ ] [ ] [ ] [ ]
^
*p = 20;
[10 ] [20 ] [ ] [ ] [ ]
^
p[2] = 100; // [2] is relative to where p is
[10 ] [20 ] [ ] [100] [ ]
^
The output of the example is right. Let me demonstrate it below -
std::vector<int> myvector (5); // creating vector with size 5, elements are 0,0,0,0,0
int* p = myvector.data(); //taking reference of the vector, p now points the first element of vector
*p = 10; // it means first element is now 10
++p; // p now points second element of the vector
*p = 20; // 2nd element is now 20
p[2] = 100; //p[2] is the 4th element now because of two position shifting and it is now 100
// vectors elements are now 10, 20, 0, 100, 0
std::vector<int> myvector (5); ==> [0,0,0,0,0]
int* p = myvector.data(); // p points to element 0
*p = 10; // element 0 is now 10
++p; // shift position of p to the next element
*p = 20; // element 1 is now 20
p[2] = 100; // Using p as reference, go 2 positions to right and assign the value of 100 to the element found at that position.
The output is correctly [10,20,0,100,0]
I'm tried to erase all elements from a vector. In fact, I wrote that:
#include<iostream>
#include<vector>
std::vector<int> foo(std::vector<int> v)
{
std::vector<int> result;
std::cout << "Initial size = " << v.size() << std::endl;
for(int i = 0; i < v.size(); i++)
{
std::cout << "Size = " << v.size() << std::endl;
v.erase(v.begin() + i);
}
return result;
}
int main()
{
int a[] = {1 ,2, 5, 8, 213, 2};
std::vector<int> v;
v.assign(a, a+6);
foo(v);
}
DEMO
Why does that program prints
Initial size = 6
Size = 6
Size = 5
Size = 4
Where is
Size = 3
Size = 2
Size = 1
?
After third erasure you have i == 3 and v.size() == 3 and for exits
You should learn to use the appropriate loop for what you want to achieve, or simply use them appropriately.
You can use a for loop when you know in advance how many iterations you need to do, but be careful with how you use the index.
What you're doing inside the cycle is changing the size of the vector, so every iteration v.size() becomes smaller. When i == 3, the vector size has been reduced to 3 and the loop ends earlier than you expected.
There are some alternatives to what you want to achieve,
// Store the size of the array so it doesn't change midway in the loop
for(int i = 0, iEnd = v.size(); i < iEnd; i++)
{
std::cout << v.size() << std::endl;
//v.erase( v.begin() );
v.pop_back(); // pop_back is quicker but erases from the end
}
Or
// More appropriate, since you don't even need to know the size
while ( !v.empty() ) {
std::cout << v.size() << std::endl;
v.pop_back();
}
In these loops I assume that you don't care about any specific elements and just want to erase them. If you do care about specific elements other answers already mention that.
But really you should be using
v.clear();
because the STL already does that for you.
To remove all elements from a vector use std::vector::clear
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<int> v(10);
cout << v.size() << endl;
v.clear();
cout << v.size();
cin.get();
return 0;
}
When the 1st element is deleted v.size() is also updated.So when it reaches size 3 its size is also 3 so it exits the for loop.
Note: try not to use the update condition (the middle condition of for loop ) as something that changes as the loop proceed unless you are sure about doing it.
You can understand the problem easy if you consider this abstract loop
size_t N = v.size();
size_t i = 0;
size_t j = N;
while ( i < j )
{
i++;
j--;
}
Thus you will delete exactly ( N + 1 ) / 2 elements in the vector or more precisely ( v.size() + 1 ) / 2 elements .:)
To remove all elements in the vector you could use member function clear().
if you want to remove elements of the vector selectively you could write
for ( auto it = v.begin(); it != v.end(); )
{
if ( need_to_delete ) it = v.erase( it );
else ++it;
}
where need_to_delete is any condition you want to use.
Because after the 3 erasures (when Size = 4), v.size() is 3 and i is 3, so i < v.size() is no longer true and you break out of the for loop, for(int i = 0; i < v.size(); i++) and return from the function.
If you just want to erase all elements of a vector, try v.clear().
You may be aware of the concept of "iterator invalidation", and you are using size_t i to avoid this. Unfortunately, what you're using is still essentially an iterator and erasing an element from a vector invalidates all iterators not just the ::iterator typed ones :).
invalidate is a carefully chosen term that has subtle nuances. It implies that the iterators didn't stop working, and that you may sometimes find they still work. But you shouldn't trust them to.
So invalidate doesn't mean they are broken or wrong, it means that you should reconsider them. For example, if you have captured vec.begin() and you have caused the vector to relocate it's data, the value of vec.begin() may no-longer be valid. It typically isn't, but you've been warned :)
std::vector is implemented over a simple contiguous array:
[ 0 ][ 1 ][ 2 ][ 3 ]
When you erase an element, the object it contains is destructed and then all of the elements to the right are moved left, physically resituated in memory.
[ 0 ][~~~~~][ 2 ][ 3 ] sz=4
[ 0 ][ 2 << 2 ][ 3 ] sz=4
[ 0 ][ 2 ][ 3 << 3 ] sz=4
[ 0 ][ 2 ][ 3 ][?????] sz=4
Then the vector reduces size by the count of elements removed, in this case 1:
[ 0 ][ 2 ][ 3 ] sz=3
You can see that the overall process of erase(), then, is expensive when the objects are not simple or when the vector is large, but I'll come back to that.
The problem with your implementation is that you increase i, and the size shrinks, so you wind up deleting every second element.
i=0
[ 0 ][ 1 ][ 2 ][ 3 ] sz=4
erase(i);
i=0
[~~~~~][ 1 ][ 2 ][ 3 ] sz=3
[ 1 << 1 ][ 2 ][ 3 ] sz=3
[ 1 ][ 2 << 2 ][ 3 ] sz=3
[ 1 ][ 2 ][ 3 << 3 ] sz=3
[ 1 ][ 2 ][ 3 ][?????] sz=3
[ 1 ][ 2 ][ 3 ] sz=3
i=0
i++;
i=1
[ 1 ][ 2 ][ 3 ] sz=3
erase(i);
i=1
[ 1 ][~~~~~][ 3 ] sz=3
[ 1 ][ 3 << 3 ] sz=3
[ 1 ][ 3 ][?????] sz=3
[ 1 ][ 3 ] sz=2
i=1
i++;
i=2
[ 1 ][ 3 ] sz=2
break;
std::vector provides clear to empty an array, but if you are interested in understanding how to perform such an operation yourself:
Option 1: delete from back
while (!vec.empty())
vec.pop_back();
What this does is destruct the last element and then reduce size. It's very cheap.
[ 0 ][ 1 ][ 2 ][ 3 ] sz=4
pop_back();
[ 0 ][ 1 ][ 2 ][~~~~~] sz=4
[ 0 ][ 1 ][ 2 ] sz=3
Option 2: Erase a range of elements
std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
vec.erase(vec.begin() + 2, vec.begin() + 5);
vec.erase(vec.begin(), vec.end());
Option 3: Shrink the array:
vec.resize(0);
Option 4: Clear
This is the preferred and normal way to empty a vector
vec.clear();
I would like to implement a local thresholding algorithm and I require your expertise.
my images are resized to 600x400, grayscale.
Basic Thought process on localizing:
Segment the images using a 9x9 ROI taken at each pixel and calculating the maximum intensity in the region.
create a 9x9 Kernel.
condition:
if the center pixel of the mask is above 50% of the maximum intensity, set the center pixel true.(apply mask)
my question to you:
How should I pick my kernel/mask ?
cv::Mat ROI;
cv::Mat mask(input.size(),CV_8UC1, cv::Scalar::all(0)); // create mask of 0s at first
const int kerneldepth = 1;
const int kernelsize = 9;
cv::Mat kernel = cv::Mat::ones( kernelsize, kernelsize, CV_8UC1 );
//take ROI of 9x9 and apply a threshold
for( double x = 9; x < input.cols -9; x++ ){
for( double y = 9 ; y < input.rows - 9 ; y++ ){
try{
double x_left = x - 4;
double x_right = x + 4;
double y_up = y + 4;
double y_down = y - 4;
double maxVal;
double minVal;
cv::Point anchor(kernelsize/2,kernelsize/2);
cv::Rect ROI = cv::Rect(x_left,y_down,9,9);
cv::Mat ROI_Mat = input(ROI); // a new matrix for ROI
cv::Scalar avgPixelIntensity = cv::mean( ROI_Mat ); // calculate mean
cv::minMaxLoc(ROI_Mat,&minVal,&maxVal);
if( input.at<uchar>(x,y) >= 0.5*maxVal){
cv::filter2D(input,mask,-1,kernel,anchor,0);
} else { break;}
}
catch (cv::Exception &e){
e.what();
}
}
*****************************UPDATED CODE: ******************************************
applyLocalThresh(cv::Mat &src, cv::Mat& out){
double maxVal, minVal;
cv::Mat output;
int top, bottom, left , right;
int borderType = cv::BORDER_CONSTANT;
cv::Scalar value;
top = (int) (9); bottom = (int) (9);
left = (int) (9); right = (int) (9);
output = src;
out = src;
value = 0;
cv::copyMakeBorder(src,output,top,bottom,left,right,borderType,value);
for(int y = 9; y < src.rows; y++) {
for(int x = 9; x < src.cols; x ++) {
cv::Mat ROI = src(cv::Rect(cv::Point(x-4,y-4),cv::Size(9,9)));
cv::minMaxLoc(ROI,&minVal,&maxVal);
if(src.at<uchar>(cv::Point(x-4,y-4)) >= 0.6*maxVal){
out.at<uchar>(cv::Point(x-4,y-4)) = 255;
}else{
out.at<uchar>(cv::Point(x-4,y-4));
}
}
}
}
You can do this with a dilation followed by a comparison in OpenCV;
im = load image here;
di = dilate im with a 9x9 kernel;
bw = im > (di * 0.5); // in OpenCV, pixels of bw are set to 255 or 0
A simple example to illustrate this with a 4x6 image and a 3x3 kernel in Matlab/Octave:
im =
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
di =
3 4 5 6 7 7
4 5 6 7 8 8
5 6 7 8 9 9
5 6 7 8 9 9
th = di * .5
th =
1.5000 2.0000 2.5000 3.0000 3.5000 3.5000
2.0000 2.5000 3.0000 3.5000 4.0000 4.0000
2.5000 3.0000 3.5000 4.0000 4.5000 4.5000
2.5000 3.0000 3.5000 4.0000 4.5000 4.5000
bw = im > th
bw =
0 0 1 1 1 1
0 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
I fear this approach is not entirely correct. Let me explain: for operations involving a kernel, one must be careful to place the center of the kernel on top of the pixel that is going to be transformed. That's because a 3x3, 5x5, 7x7, 9x9 (...) kernel just computes the value for one pixel in the image, which is the one positioned at the center [0,0] of the kernel.
If you think about how to compute the value for the first pixel of the image, the center of a 9x9 kernel is going to be placed at coordinate [0,0]. That means that 3/4 of the kernel are going to be placed at negative coordinates, i.e. coordinates that refers to pixels that don't exist:
[-4,-4][-3,-4][-2,-4][-1,-4][ 0,-4][ 1,-4][ 2,-4][ 3,-4][ 4,-4]
[-4,-3][-3,-3][-2,-3][-1,-3][ 0,-3][ 1,-3][ 2,-3][ 3,-3][ 4,-3]
[-4,-2][-3,-2][-2,-2][-1,-2][ 0,-2][ 1,-2][ 2,-2][ 3,-2][ 4,-2]
[-4,-1][-3,-1][-2,-1][-1,-1][ 0,-1][ 1,-1][ 2,-1][ 3,-1][ 4,-1]
[-4, 0][-3, 0][-2, 0][-1, 0][ 0, 0][ 1, 0][ 2, 0][ 3, 0][ 4, 0]
[-4, 1][-3, 1][-2, 1][-1, 1][ 0, 1][ 1, 1][ 2, 1][ 3, 1][ 4, 1]
[-4, 2][-3, 2][-2, 2][-1, 2][ 0, 2][ 1, 2][ 2, 2][ 3, 2][ 4, 2]
[-4, 3][-3, 3][-2, 3][-1, 3][ 0, 3][ 1, 3][ 2, 3][ 3, 3][ 4, 3]
[-4, 4][-3, 4][-2, 4][-1, 4][ 0, 4][ 1, 4][ 2, 4][ 3, 4][ 4, 4]
This is always going to happen with pixels near the border of the image. So for the computation of the first pixel, we would have to restrict the computation to 1/4 of the kernel, which refers to valid coordinates in the target image:
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ 0, 0][ 1, 0][ 2, 0][ 3, 0][ 4, 0]
[ ][ ][ ][ ][ 0, 1][ 1, 1][ 2, 1][ 3, 1][ 4, 1]
[ ][ ][ ][ ][ 0, 2][ 1, 2][ 2, 2][ 3, 2][ 4, 2]
[ ][ ][ ][ ][ 0, 3][ 1, 3][ 2, 3][ 3, 3][ 4, 3]
[ ][ ][ ][ ][ 0, 4][ 1, 4][ 2, 4][ 3, 4][ 4, 4]
So the problem with your current approach is that at some point you will setup a ROI that is going to have negative coordinates, and when these instructions are executed you will see a nice crash:
cv::Mat ROI_Mat = input(ROI); // crash
The solution is not to use a ROI and just implement that algorithm yourself. I just can't see this custom computation working with cv::filter2D(). Here's a little something to help you get started:
void local_threshold(const cv::Mat& input, cv::Mat& output)
{
if (input.channels() != 1)
{
std::cout << "local_threshold !!! input image must be single channel" << std::endl;
return;
}
output = cv::Mat(input.rows, input.cols, CV_8UC1);
double min_val = 0, max_val = 0;
for (int i = 0; i < input.rows; i++)
for (int j = 0; j < input.cols; j++)
{
cv::Mat kernel = Mat::zeros(9, 9, output.type());
// Implement logic to fill the 9x9 kernel with
// values from the input Mat, respecting boundaries.
cv::Scalar avg_intensity = cv::mean(kernel);
cv::minMaxLoc(kernel, &min_val,&max_val);
if (input.at<uchar>(i,j) > (max_val / 2))
output.at<unsigned char>(i,j) = 255;
else
output.at<unsigned char>(i,j) = 0;
}
}
After further thinking and finding out how to utilize my basic knowledge in programming, I came up with this code that isn't the most efficient but gets the job done.
What was the main problem with my approach? :
Boundary pixels where one of the main problems and the whole indexing operation between kernel and mask caused a slight headache.
What was my approach in solving that matter?:
My threshold says it needs a relative high intensity level to set true pixels. Therefore I filled the image with some imaginary negative pixels and made my algorithm start at the first pixel of the original. And saved the results to a mask.
Result:
SUCCESS!
Code:
double maxVal, minVal;
cv::Mat output;
int top, bottom, left , right;
int borderType = cv::BORDER_CONSTANT;
cv::Scalar value;
top = (int) (4); bottom = (int) (4);
left = (int) (4); right = (int) (4);
output = src;
out = src;
value = 0;
cv::copyMakeBorder(src,output,top,bottom,left,right,borderType,value);
for(int y = 4; y < output.rows - 4; y++) {
for(int x = 4; x < output.cols - 4; x ++) {
// apply local ROI
cv::Mat ROI = output(cv::Rect(cv::Point(x-4,y-4),cv::Size(9,9)));
cv::minMaxLoc(ROI,&minVal,&maxVal); // extract max intensity values in the ROI
if(src.at<uchar>(cv::Point(x-4,y-4)) >= 0.5*maxVal){ // apply local threshold w.r.t highest intensity level
out.at<uchar>(cv::Point(x-4,y-4)) = 255; // change pixel value in mask if true
}else{
out.at<uchar>(cv::Point(x-4,y-4)) = 0;
}
}
}
}
it needs some clean up I know but hopefully this would help others to get some idea.
I'd like to use the following function to return a transposed pointer to a multidimensional array.
Code
float** Matrix3f::Transpose( void )
{
float matrix[MATRIX3_DIMS][MATRIX3_DIMS] =
{
{ mMatrix[ 0 ][ 0 ], mMatrix[ 1 ][ 0 ], mMatrix[ 2 ][ 0 ] },
{ mMatrix[ 0 ][ 1 ], mMatrix[ 1 ][ 1 ], mMatrix[ 2 ][ 1 ] },
{ mMatrix[ 0 ][ 2 ], mMatrix[ 1 ][ 2 ], mMatrix[ 2 ][ 2 ] }
};
float** ret = new float*[ MATRIX3_DIMS ];
for ( int i = 0; i < MATRIX3_DIMS; i++ )
{
for ( int j = 0; j < MATRIX3_DIMS; j++ )
{
( *ret )[ i ][ j ] = matrix[ i ][ j ];
}
}
return ret;
}
Description
As shown, I declare a multidimensional array using initialization syntax(using the class-member matrix - mMatrix - to create a transposed version of the matrix itself. I then assign a multidimensional pointer to an array (ret) and loop through, assigning each member of the local array - matrix - to the ret pointer array.
The error I receive is the following:
error: invalid types ‘float[int]’ for array subscript
Question
What exactly am I doing wrong, and how can I accomplish this task?
ret is a pointer to pointer to float. When you dereference it, like this: (*ret), you get a pointer to float. When you take an index on that, like this: ( *ret )[ i ], that gives you a float. When you take an index on that, like this: ( *ret )[ i ][ j ], well, you're trying to index off of a float. That's not legal.
Putting my disgust for this style of coding aside, the first thing you're doing wrong is you are not allocating the sub-arrays. The compiler error though, refers to the error I illustrated in the first paragraph. Just remove the dereferencing of ret to fix that. You end up with this:
for ( int i = 0; i < MATRIX3_DIMS; i++ )
{
ret[i] = new float[MATRIX3_DIMS];
for ( int j = 0; j < MATRIX3_DIMS; j++ )
{
ret[ i ][ j ] = matrix[ i ][ j ];
}
}
This is totally not exception safe though, and you should be using a class that properly manages memory in an exception safe way, like std::vector.