I have to design functional rubik cube as part of my homework. I am not using openGL directly, but a framework that was provided. ( All functions that do not belong to openGL and do not have their body listed here will be presumed correct)
Functionalities: all faces need to be rotated if selected by pressing a key.
The whole cube must rotate.
The rotation of the whole cube is correct and does not make the subject of this question.
In order to do this, I created the rubik cube from 27 smaller cubes(cube size is 3) and, at the same time, a tridimensional array. A replica of the cube that contains small cubes indexes.
In order to better understand this :
if initially one face was:
0 1 2
3 4 5
6 7 8
after a rotation it should be:
6 3 0
7 4 1
8 5 2
I can rotate the cubes relative to axis X or Y an indefinite number of times and it works perfectly.
However, if I combine the rotations( alternate X rotations with Y rotations in a random way) there appear cases when the cube deforms.
As this happens inconsistently, it is difficult for me to find the cause.
This is how I am creating the cube :
int count = 0;
for (int i = -1; i < 2; i++)
for(int j = -1; j < 2; j++)
for(int k = -1; k < 2; k++) {
RubikCube.push_back(drawCube());
RubikCube.at(count)->translate(4*i,4*j,4*k);
CubIndici[j+1][k+1][i+1] = count;
count++;
}
The function drawCube() effectively draws a cube of size 4 with the center positioned in origin.
CubIndici is the 3D array that I use to store the positions of the cube.
This is the function that I am using to rotate a matrix in the 3D array. (I have double checked it so it should be correct, but perhaps I am missing something).
void rotateMatrix(int face_index, int axis) {
if (axis == 0 )
{
for ( int i = 0; i < 3; i++)
for( int j = i; j < 3; j++)
{
swap(&CubIndici[i][j][face_index],&CubIndici[j][i][face_index]);
}
for (int i = 0; i < 3; i++)
for(int j = i; j < 3; j++)
{
swap(&CubIndici[i][j][face_index],&CubIndici[2-i][j][face_index]);
}
}
if (axis == 1 )
{
for ( int i = 0; i < 3; i++)
for( int j = i; j < 3; j++)
{
swap(&CubIndici[face_index][i][j],&CubIndici[face_index][j][i]);
}
for (int i = 0; i < 3; i++)
for(int j = i; j < 3; j++)
{
swap(&CubIndici[face_index][i][j],&CubIndici[face_index][2-i][j]);
}
}
}
The CubIndici 3d array is global, so I need the axis parameter to determine what kind of rotation to performe( relative to X, Y or Z)
on pressing w key I should rotate a( hardcoded, for now) face around axis X
for (int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
RubikCube.at(CubIndici[i][j][1])->rotateXRelativeToPoint(
RubikCube.at(CubIndici[1][1][1])->axiscenter, 1.57079633);
rotateMatrix(1,0);
CubIndici11 should always contain the cube that is in the center of the face CubIndici[*][*]1.
Similarly,
for (int i = 0; i < 3; i++)
for(int j = 0; j < 3; j++)
RubikCube.at(CubIndici[2][i][j])->rotateYRelativeToPoint(
RubikCube.at(CubIndici[2][1][1])->axiscenter, 1.57079633);
rotateMatrix(2,1);
for rotating on axis Y.
1.57079633 is the radian equivalent of 90 degrees
For a better understanding I add the detailed display of rotating the left face on X axis and the top down one on Y axis.
The first block of coordinates is the initial cube face. ( The CubIndici index matrix is unmodified)
pre rotatie - coordinates and indexes for each of the cubes of the face.
post rotatie - coordiantes and indexes after rotating the objects. ( The matrix was not touched )
post rotatie matrice - after rotating the matrix aswell. If you compare the indexes of "pre rotatie" with "post rotatie matrice" you will notice 90 degrees turn.
This is the first rotation ( rotate the left face around X) and it is entirely correct.
On the next rotation however, the cubes that should be contained in the top down face ( as well as in the left one) should be 2,5,8. However, they appear as 2,5,6.
If you look at the first "post rotatie matrice" 2,5,8 are indeed the top row.
This is the issue that deforms the cube and I don't know what causes it.
If anything is unclear please let me know and I will edit the post or reply to the comment!
The formula of a PI/2 rotation clockwise for a cell at position <x;y> in a slice of the cube is:
x' = 2 - y
y' = x
similarily, for a counter clockwise rotation:
x' = y
y' = 2 - x
but these are rotations, and you want to do in-place modification of your arrays.
We can replace a rotation by a combination of 2 mirror symmetries.
clockwise:
<x;y> -> <y;x>
<x;y> -> <2-x;y>
and counter clockwise is the opposite composition of these functions.
Given these formulas, you can write your rotation function like this:
void rotateMatrix_X_CW(int face_index) {
int i,j;
for ( i = 0; i < 2; i++)
for( j = i; j < 3; j++)
{
swap(CubIndici[i][j][face_index],CubIndici[2-i][j][face_index]);
}
for ( i = 0; i < 2; i++)
for( j = i; j < 3; j++)
{
swap(CubIndici[i][j][face_index],CubIndici[j][i][face_index]);
}
}
void rotateMatrix_X_CCW(int face_index) {
int i,j;
for ( i = 0; i < 2; i++)
for( j = i; j < 3; j++)
{
swap(CubIndici[i][j][face_index],CubIndici[j][i][face_index]);
}
for ( i = 0; i < 2; i++)
for( j = i; j < 3; j++)
{
swap(CubIndici[i][j][face_index],CubIndici[2-i][j][face_index]);
}
}
You should be able to implement the other axes from there.
Related
I have a homework assignment where, given an array of points, we must find the number of point pairs that are less than or equal to a given distance epsilon apart. The first algorithm I wrote gives me the correct answer, which is here:
#pragma omp parallel for schedule(dynamic, CHUNK) num_threads(NB_THREADS) reduction(+:counter) private(dx, dy, distance)
for (int i = 0; i < N-1; ++i)
{
for (int j = i+1; j < N; j = ++j)
{
dx = (data[j].x - data[i].x);
dy = (data[j].y - data[i].y);
distance = (dx*dx) + (dy*dy);
if (distance <= epsilon_squared)
{
++counter;
}
}
}
The second algorithm makes use of distance from origin and trigonometry to perform the same operations. The problem is that the final result is off by a very small margin, typically between 2-4. The point array is sorted beforehand by distance from origin.
#pragma omp parallel for schedule(dynamic, CHUNK) num_threads(NB_THREADS) reduction(+:counter) private(a, b, theta, distance)
for (int i = 0; i < N-1; ++i)
{
//dfo = distance from origin
a = data[i].dfo;
for (int j = i+1; j < N; j = ++j)
{
b = data[j].dfo;
//find angle between point a, origin, point b
theta = acos(((data[i].x*data[j].x)+(data[i].y*data[j].y))/((sqrt(((data[i].x*data[i].x)+(data[i].y*data[i].y)))*(sqrt((data[j].x*data[j].x)+(data[j].y*data[j].y))))));
distance = (a*a) + (b*b) - (2*a*b*(cos(theta)));
if (distance <= epsilon_squared)
{
++counter;
} else {
if (abs(a-b)>epsilon)
{
break;
}
}
}
}
My Question: Can the operations in the second algorithm lead to a different distance result compared to the first algorithm? I have checked the results between the first and the second, and they seem to be completely identical. If there is a difference being created, what can I do to fix this? Thank you in advance.
I've come up with this code for applying a 3x3 kernel to my image:
double sum;
for(int i = 1; i < src.rows - 1; i++){
for(int j = 1; j < src.cols - 1; j++)
for (int k = 0; k < 3; k ++) {
sum = 0.0;
dst.at<cv::Vec3b>(i,j)[k] = 0.0;
for(int x = -1; x <= 1; x++){
for(int y = -1; y <=1; y++){
sum += (Kernel_Matrix[y+1][x+1]*src.at<cv::Vec3b>(i - x, j - y)[k]);
}
}
dst.at<cv::Vec3b>(i,j)[k] = cv::saturate_cast<uchar>(sum);
}
}
Now I got 2 questions:
By reading https://en.wikipedia.org/wiki/Kernel_(image_processing), there's various matrix for various filter, let's say I want my Blur filter to increase intensity, via a gui Slider that gives a value from x to whatever, what kind of operation should I make to my Blur Matrix(make a sum, a multiplication...)?
(I wold like to do the same with sharpness)
is there a specific matrix for Noise Reduction?
If you also have any mods to suggest me on my algorithm please let me know!
thanks!
I am trying to implement laplacian filter for sharpening an image.
but the result is kinda grey , I don't know what went wrong with my code.
Here's my work so far
img = imread("moon.png", 0);
Mat convoSharp() {
//creating new image
Mat res = img.clone();
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
res.at<uchar>(y, x) = 0.0;
}
}
//variable declaration
//change -5 to -4 for original result.
int filter[3][3] = { {0,1,0},{1,-4,1},{0,1,0} };
//int filter[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
int height = img.rows;
int width = img.cols;
int **temp = new int*[height];
for (int i = 0; i < height; i++) {
temp[i] = new int[width];
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
temp[i][j] = 0;
}
}
int filterHeight = 3;
int filterWidth = 3;
int newImageHeight = height - filterHeight + 1;
int newImageWidth = width - filterWidth + 1;
int i, j, h, w;
//convolution
for (i = 0; i < newImageHeight; i++) {
for (j = 0; j < newImageWidth; j++) {
for (h = i; h < i + filterHeight; h++) {
for (w = j; w < j + filterWidth; w++) {
temp[i][j] += filter[h - i][w - j] * (int)img.at<uchar>(h, w);
}
}
}
}
//find max and min
int max = 0;
int min = 100;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (temp[i][j] > max) {
max = temp[i][j];
}
if (temp[i][j] < min) {
min = temp[i][j];
}
}
}
//clamp 0 - 255
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
res.at<uchar>(i, j) = 0 + (temp[i][j] - min)*(255 - 0) / (max - min);
}
}
//empty the temp array
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
temp[i][j] = 0;
}
}
//img - res and store it in temp array
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
//int a = (int)img.at<uchar>(y, x) - (int)res.at<uchar>(y, x);
//cout << a << endl;
temp[y][x] = (int)img.at<uchar>(y, x) - (int)res.at<uchar>(y, x);
}
}
//find the new max and min
max = 0;
min = 100;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (temp[i][j] > max) {
max = temp[i][j];
}
if (temp[i][j] < min) {
min = temp[i][j];
}
}
}
//clamp it back to 0-255
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
res.at<uchar>(i, j) = 0 + (temp[i][j] - min)*(255 - 0) / (max - min);
temp[i][j] = (int)res.at<uchar>(i, j);
}
}
return res;
}
And here's the result
as you can see in my code above , i already normalize the pixel value to 0-255. i still don't know what went wrong here. Can anyone here explain why is that ?
The greyness is because, as Max suggested in his answer, you are scaling to the 0-255 range, not clamping (as your comments in the code suggest).
However, that is not all of the issues in your code. The output of the Laplace operator contains negative values. You nicely store these in an int. But then you scale and copy over to a char. Don't do that!
You need to add the result of the Laplace unchanged to your image. This way, some pixels in your image will become darker, and some lighter. This is what causes the edges to appear sharper.
Simply skip some of the loops in your code, and keep one that does temp = img - temp. That result you can freely scale or clamp to the output range and cast to char.
To clamp, simply set any pixel values below 0 to 0, and any above 255 to 255. Don't compute min/max and scale as you do, because there you reduce contrast and create the greyish wash over your image.
Your recent question is quite similar (though the problem in the code was different), read my answer there again, it suggests a way to further simplify your code so that img-Laplace becomes a single convolution.
The problem is that you are clamping and rescaling the image. Look at the bottom left border of the moon: There are very bright pixels next to very dark pixels, and then some gray pixels right besides the bright ones. Your sharpening filter will really spike on that bright border and increase the maximum. Similarly, the black pixels will be reduced even further.
You then determine minimum and maximum and rescale the entire image. This necessarily means the entire image will lose contrast when displayed in the previous gray scale, because your filter outputted pixel values above 255 and below 0.
Looks closely at the border of the moon in the output image:
There is a black halo (the new 0) and a bright, sharp edge (the new 255). (The browser image scaling made it less crisp in this screenshot, look at your original output). Everything else was squashed by the rescaling, so what was previous black (0) is now dark gray.
Hello I have an image of text with bounding boxes on the text. I'm given all coordinates and I want to white or black out anything not in the bounding box (background stuff). So far I have something like this in OpenCV
for (int i = 0; i < image.rows; i++)
{
for (int j = 0; j < image.cols; j++)
{
for (int k = 0; k < coor.size(); k++)
{
if (!((j >= coor[k][0].x) && (j <= coor[k][2].x) && (i >= coor[k][0].y) && (i <= coor[k][1].y)))
{
image.at<Vec3b>(i, j) = 0;
}
}
}
}
Coor is a vector of vector of points that hold all corner points, and for now I'm checking whether or not a point is in there or not and altering the color. If i remove the NOT from the condition I am able to change pixel colors of whats inside the boxes, If i removed the not, every pixel changes :/. Any idea of what is going on?
I have N square matrices all of the same size MxM that have to be copied in a matrix that contains NxN matrices, arranged in a symmetrical way. The two halves, upper and lower, contain transposed version of the same matrices like in this scheme.
N = 4
m1 m2 m3 m4
m2'm1 m2 m3
m3'm2'm1 m2
m4'm3'm2'm1
The algorithm that produces data initially fills just the upper row and the first column, leaving the rest empty.
m1 m2 m3 m4
m2'0 0 0
m3'0 0 0
m4'0 0 0
I would like to find an efficient indexing scheme to fill all the big matrix starting from the elements of the line that has been already filled. Remember that m1...mn are square matrices of size MxM, and the matrix is arranged in column-major order. The matrix is not so big so no need to exploit much locality and cache-related things.
The trivial algorithm is like below, where X is the matrix.
int toX = 0, fromX = 0, toY = 0, fromY = 0;
for (int i = 1; i < N; ++i) {
for (int j = 1; j < N; ++j) {
for (int ii = 0; ii < M; ++ii) {
for (int jj = 0; jj < M; ++jj) {
fromX = (i - 1) * dim + ii;
fromY = (j - 1) * dim + jj;
toX = i * dim + ii;
toY = j * dim + jj;
X(toX, toY) = X(fromX, fromY);
}
}
}
}
Can you find a better way?
Depending on your application, it might be unnecessary to store all those transposed matrices. If m1 is symmetric, you could even cull the lower half of the m1 matrices.
In fact, it might even be feasible to leave all those matrices alone and do your matrix-operations block-wise (addition and multiplication with a scalar are simple, multiplication with a vector would be a bit more complicated)
If you really need the whole matrix, you might get a slightly lower operation count by filling the matrix diagonally, i.e. by doing something like this:
int toX = 0, fromX = 0, toY = 0, fromY = 0;
// m1 (note that this part can be sped up further if m1 is symmetric)
for (int ii = 0; ii<M; ii++){
for (int jj = 0; jj<M; jj++){
fromX = ii;
fromY = jj;
toX = fromX;
toY = fromY;
for (int k=1; k<N; k++){
toX += dim;
toY += dim;
X(toX, toY) = X(fromX, fromY);
}
}
}
// m2 to m(N-1)
for (int i = 2; i < N; i++){
for (int ii = 0; ii<M; ii++){
for (int jj = 0; jj<M; jj++){
fromX = i*dim+ii;
fromY = jj;
toX = fromX;
toY = fromY;
for (int k=i; k<N; k++){
toX += dim;
toY += dim;
X(toX, toY) = X(fromX, fromY);
X(toY, toX) = X(fromX, fromY);
}
}
}
}