I am building a particle simulation, and I want to display each particle's position as a dot in a 3D scatter plot using MathGL in C (not C++!). I am having trouble with the C interface.
So far I found two interesting examples:
A C++ example that seems to be close to what I want: http://mathgl.sourceforge.net/doc_en/Dots-sample.html (but this is in C++, I have been unable to find the C-equivalent)
This is a piece of C code that constructs a 3D surf plot with dots.
#include <mgl2/mgl_cf.h>
int main()
{
HMGL gr = mgl_create_graph(600,400);
HMDT a,x,y;
a = mgl_create_data_size(30,40,1);
x = mgl_create_data_size(30,1,1);
y = mgl_create_data_size(40,1,1);
mgl_data_modify(a,"pi*(1-2*x)*exp(-4*y^2-4*(2*x-1)^2)",0);
mgl_data_fill(x,-1.,1.,'x');
mgl_data_fill(y,0.,1.,'x');
mgl_rotate(gr,40.,60.,0.);
mgl_set_light(gr,1);
mgl_box(gr,1);
mgl_surf_xy(gr,x,y,a,".","");
mgl_delete_data(a);
mgl_delete_data(y);
mgl_delete_data(x);
mgl_write_frame(gr,"test.png","");
mgl_delete_graph(gr);
return 0;
}
The example 2 is close to what I want to do, but it is annoying that a is not a linear array of just N particles. It also has to take a function to evaluate the values for a (z-axis) whereas I just want to pass the z-coordinate manually for each dot).
My data is just a 1D array of structs, similar to this:
struct particle {
double x, y, z, velocity;
};
How do I plot these particles as dots in a 3D (scatter) plot with MathGL in C? I guess I have to use mgl_dots, but how does it read from my array of values? (I could use velocity as color coding, but that is optional)
I was right about using mgl_dots, and the data can be prepared using mgl_create_data_sizeand mgl_data_put_val, e.g.:
HMDT z,x,y;
int N = 1000;
x = mgl_create_data_size(N,1,1);
z = mgl_create_data_size(N,1,1);
y = mgl_create_data_size(N,1,1);
for(int i=0; i < N; i++) {
// Set position of particle[i]
printf("%lf\n", i/(double) N);
mgl_data_put_val(x, i/(double) N, i, 0, 0);
mgl_data_put_val(y, i/(double) N, i, 0, 0);
mgl_data_put_val(z, i/(double) N, i, 0, 0);
}
Related
Given a list of spheres described by (xi, yi, ri), meaning the center of sphere i is at the point (xi, yi, 0) in three-dimensional space and its radius is ri, I want to compute all zi where zi = max { z | (xi, yi, z) is a point on any sphere }. In other words, zi is the highest point over the center of sphere i that is in any of the spheres.
I have two arrays
int **vs = (int **)malloc(num * sizeof(int *));
double **vh = (double **)malloc(num * sizeof(double *));
for (int i = 0; i < num; i++){
vs[i] = (int *)malloc(2 * sizeof(int)); // x,y
vh[i] = (double *)malloc(2 * sizeof(double)); r,z
}
The objective is to calculate the maximum z for each point. Thus, we should check if there are larger spheres over each x,y point.
Initially we see vh[i][1]=vh[i][0] for all points, which means that z is the r of each sphere. Then, we check if these z values are inside larger spheres to maximize the z value.
for (int i = 0; i < v; i++) {
double a = vh[i][0] * vh[i][0]; // power of the radius of sphere #1
for (int j = 0; j < v; j++) {
if (vh[i][0] > vh[j][1]) { // check only if r of sphere #1 is larger than the current z of #2
double b = a - (vs[j][0] - vs[i][0]) * (vs[j][0] - vs[i][0])
- (vs[j][1] - vs[i][1]) * (vs[j][1] - vs[i][1]);
// calculating the maximum z value of sphere #2 crossing sphere #1
// (r of sphere #1)**2 = (z of x_j,y_j)**2 + (distance of two centers)**2
if (b > vh[j][1] * vh[j][1]) {
vh[j][1] = sqrt(b);// update the z value if it is larger than the current value
}
}
}
}
it works perfectly, but the nested loop is very slow when the number of points increases. I look for a way to speed up the process.
An illustration for the clarification of the task
When you say
The objective is to calculate the maximum z for each point.
I take you to mean, for the center C of each sphere, the maximum z coordinate among all the points lying directly above C (along the z axis) on any of the spheres. This is fundamentally an O(n2) problem -- there is nothing you can do to prevent the computational expense scaling with the square of the number of spheres.
But there may be some things you can do to reduce the scaling coeffcient. Here are some possibilities:
Use bona fide 2D arrays (== arrays of arrays) instead arrays of pointers. It's easier to implement, more memory-efficient, and better for locality of reference:
int (*vs)[2] = malloc(num * sizeof(*vs));
double (*vh)[2] = malloc(num * sizeof(*h));
// no other allocations needed
Alternatively, it may help to use an array of structures, one per sphere, instead of two 2D arrays of numbers. It would certainly make your code clearer, but it might also help give a slight speed boost by improving locality of reference:
struct sphere {
int x, y;
double r, z;
};
struct sphere *spheres = malloc(num * sizeof(*spheres));
Store z2 instead of z, at least for the duration of the computation. This will reduce the number of somewhat-expensive sqrt calls from O(v2) to O(v), supposing you make a single pass at the end to convert all the results to zs, and it will save you O(v2) multiplications, too. (More if you could get away without ever converting from z2 to z.)
Pre-initialize each vh[i][1] value to the radius of sphere i (or the square of the radius if you are exercising the previous option, too), and add j != i to the condition around the inner-loop body.
Sorting the spheres in decreasing order by radius may help you find larger provisional z values earlier, and therefore to make the radius test in the inner loop more effective at culling unnecessary computations.
You might get some improvement by checking each distinct pair only once. That is, for each unordered pair i, j, you can compute the inter-center distance once only, determine from the relative radii which height to check for a possible update, and go from there. The extra logic involved might or might not pay off through a reduction in other computations.
Additionally, if you are doing this for large enough inputs, then you might be able to reduce the wall time consumed by parallelizing the computation.
Note, by the way, that this comment is incorrect:
// (r of sphere #1)**2 = (r of sphere #2)**2 + (distance of two centers)**2
. However, it also not what you are relying upon. What you are relying upon is that if sphere 1 covers the center of sphere 2 at all, then its height, z, above the center of sphere 2 satisfies the relationship
r12 = z2 + d1,22
. That is, where you wrote r of sphere #2 in the comment, you appear to have meant z.
I have a function that successfully reads rgb values from a ppm and a function that successfully writes to a ppm. What I am trying is a function called denoiseImage that changes rgb values from a ppm using mean filtering with a frame window size n by n where n is odd. My intent is to go through each pixel, using it as the center point for the window n by n that surrounds it. I then take the mean values for each color (r,g,b) and divide by the number of pixels in the window and assign those new values to the rgb of every pixel in the window. However, I am unable to implement a check for the cases where the frame does not fully fit into pixels (for example, the frame center point is the top right pixel, a window of 3x3 will go to non existent points.) When it does not fit fully, I intend to use the available pixels that fit and take the mean of those numbers instead. So far, my code will only work for cases where the frame fully fits. My function:
RGB *denoiseImage(int width, int height, const RGB *image, int n)
{
int firstPos, lastPos, i = 0, j = 0, k, numofPix;
int sumR=0,sumG=0,sumB=0;
numofPix = (width * height);
RGB *pixels = malloc(numofPix * sizeof(RGB));
if (n == 1) //Case where the window size is 1 and therefore the image does not get changed.
{
return pixels;
}
for (j=0;j < numofPix;j++)
{
firstPos = (j - width) - ((n - 1)/2);
lastPos = (j + width) + ((n - 1)/2);
//Need to check boundary cases to prevent segmentation fault
for (k=firstPos;k<=lastPos;k++) //Seg fault. Unable to shrink frame to compensate for cases where the frame does not fit.
{
sumR+=image[k].r;
sumG+=image[k].g;
sumB+=image[k].b;
i++;
if (i = n) //Used to skip elements not in frame
{
j += (width-n);
i = 0;
}
}
sumR = sumR/(n*n); //Calculating mean values
sumG = sumG/(n*n);
sumB = sumB/(n*n);
for (k=firstPos;k<=lastPos;k++) //Assigning the RGB values with the new mean values.
{
pixels[k].r=sumR;
pixels[k].g=sumG;
pixels[k].b=sumB;
printf("%d %d %d ",pixels[k].r, pixels[k].g, pixels[k].b);
}
}
return pixels;
}
int main()
{
RGB *RGBValues;
int width, height, max;
int j = 0,testemp=3; //test temp is a sample frame size
char *testfile = "test.ppm";
char *testfile2 = "makeme.ppm";
RGBValues = readPPM(testfile, &width, &height, &max); //Function reads values from a ppm file correctly
RGBValues = denoiseImage(width,height, RGBValues, testemp,testing);
writePPM(testfile2,width,height,max,RGBValues); //Function writes values to a ppm file correctly
}
How would I implement a way to check if the frame fits or not?
This is a great question and luckily known in the image processing community.
Edges are always treated differently when it comes to 2D filtering.
One way to look at it is to extend the space in 2D and to fill the edges with extrapolated values from the middle.
For example, you may look into the http://www.librow.com/articles/article-1 and search for a media filter.
I am sure that you will find solution soon, since you are going into right direction.
I'm not sure if my Perlin Noise generator is functioning properly, the noise it generates looks very different from the images I see online. Mine looks too homogeneous (these are three different images):
Whereas what I usually see is something like:
My code is basically:
/* Get the coord of the top-left gradient of the grid (y, x) falls in */
int j = floor(x);
int i = floor(y);
/* Get the distance (y, x) is from it */
double dx = x-j;
double dy = y-i;
/* Influence of (g)radient(i)(j) (starting at the top-left one) */
double g00 = dot(grad(hashes, hsize, grads, i, j), dy, dx);
double g01 = dot(grad(hashes, hsize, grads, i, j+1), dy, dx-1);
double g10 = dot(grad(hashes, hsize, grads, i+1, j), dy-1, dx);
double g11 = dot(grad(hashes, hsize, grads, i+1, j+1), dy-1, dx-1);
/* Interpolate the influences using the blending function */
/* Linear interpol the top 2 */
double lt = lerp(g00, g01, fade(dx));
/* Linear interpol the bottom 2 */
double lb = lerp(g10, g11, fade(dx));
/* Linear interpol lb lt, completing the bilienear interpol */
return lerp(lt, lb, fade(dy));
Complete code. It's based mainly on this tutorial. I'm using this script to draw the csv file.
I understand the basics, but after reading several "tutorials" that usually contradict each other and the "reference implementation" which is not very readable I have a few doubts. The (x, y) points being interpolated should be in what interval? As I understand it, it should be [0, GRID_SIZE-1] (e.g. [0, 255] if using a pre-computed table with 256 random values). However, my code only results in reasonably good looking images when (x, y) is mapped to [0, 1], and I see some implementations online that map it to [0, 255] no matter the grid size. I'm also unsure if I'm picking the gradients correctly from the table.
You normalize your pixel coordinates to the whole image. You should normalize it to the size of your simplex grid.
So instead of your code for the inner loop:
double x = j/(double)w;
double y = i/(double)h;
do:
double x = j / gridsize;
double y = i / gridsize;
where the grid size is an additional parameter, for example:
double gridsize = 32.0;
(It should probably be chosen to fit evenly into the image dimensions.)
How can I access an RGB mat as a 1D array? I looked at the documentation but couldn't find how the 3 channel data is laid out in that case.
I'm trying to loop over each pixel with 1 for loop going from n=0 to n = img.rows*img.cols - 1, and access R, G, and B values at each pixel.
Any help would be greatly appreciated.
I don't really understand why you really need only 1 loop, so I will propose you several options (including 1 or 2 for-loops) that I know by experience to be efficient.
If you really want to iterate over all the values with only one loop in a safe way, you can reshape the matrix and turn a 3-channel 2D image into a 1-channel 1D array using cv::Mat::reshape(...) (doc):
cv::Mat rgbMat = cv::imread(...); // Read original image
// As a 1D-1 channel, we have 1 channel and 3*the number of pixels samples
cv::Mat arrayFromRgb = rgbMat.reshape(1, rgbMat.channels()*rgbMat.size().area());
There are two caveats:
reshape() returns a new cv::Mat reference, hence its output needs to be assigned to a variable (it won't operate in-place)
you are not allowed to change the number of elements in the matrix.
OpenCV stores the matrix data in row-major order.
Thus, an alternative is to iterate over the rows by getting a pointer to each row start.
This way, you will not do anything unsafe because of possible padding data at the end of the rows:
cv::Mat rgbMat = cv::imread(...);
for (int y = 0; y < rgbMat.size().height; ++y) {
// Option 1: get a pointer to a 3-channel element
cv::Vec3b* pointerToRgbPixel = rgbMat.ptr<cv::Vec3b>(y);
for (int x = 0; x < rgbMat.size().width; ++x, ++pointerToRgbPixel) {
uint8_t blue = (*pointerToRgbPixel )[0];
uint8_t green = (*pointerToRgbPixel )[1];
uint8_t red = (*pointerToRgbPixel )[2];
DoSomething(red, green, blue);
}
// Option 2: get a pointer to the first sample and iterate
uint8_t* pointerToSample = rgbMat.ptr<uint8_t>(y);
for (int x = 0; x < rgbMat.channels()*rgbMat.size().width; ++x) {
DoSomething(*pointerToSample);
++pointerToSample;
}
}
Why do I like the iteration over the rows ?
Because it is easy to make parallel.
If you have a multi-core computer, you can use any framework (such as OpenMP or GCD) to handle each line in parallel in a safe way.
Using OpenMP, it as easy as adding a #pragma parallel for before the outer loop.
Yes it is referenced over there in the documentation.
And why don't you see the snippet below:
template<int N>
void SetPixel(Mat &img, int x, int y, unsigned char newVal) {
*(img.data + (y * img.cols + x) * img.channels() + N) = newVal;
}
int main() {
Mat img = Mat::zeros(1000, 1000, CV_8UC4);
SetPixel<0>(img, 120);
SetPixel<1>(img, 120);
SetPixel<2>(img, 120);
imwrite("out.jpg", img);
return 0;
}
But it is not the safe way, it assumes mat data lays continuously in the momory (and there is no space in bytes between its rows). So better check Mat::isContinous() before using this snippet.
//C++ Code Below
//your RGB image
cv::Mat image;
//your 1D array
cv::Mat newimage;
//the function to convert the image into 1D array
image.reshape(0, 1).convertTo(newimage, CV_32F);
//http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-reshape
I've got an array of strings that I'd like to draw as a giant spiral. I only have a very, very rough idea of where to begin. First, I will probably need to break the strings into an array of individual characters? Next, I will probably need to apply the following geometry in order to generate the spiral shape?
float r = 0;
float theta = 0;
void setup() {
size(200,200);
background(255);
}
void draw() {
float x = r * cos(theta);
float y = r * sin(theta);
noStroke();
fill(0);
ellipse(x+width/2, y+height/2, 6, 6);
theta += 0.01;
r += 0.05;
}
However, I don't know how to step through my array of characters in order to draw them in a spiral-like format. I apologize for the lack of clarity. Any suggestions would be awesome! I'm very new to all of this (clearly).
Your code for creating the spiral is a good idea. One way to create rotated text would be using rotate(), combined with text(). You would have a for loop, iterate through your character array, increment the radius, and draw your text that way. Note that rotate() has a cumulative effect. Something like:
String str = "asdflkkjsahfdlkadshflkahdslkfajsdf";
float radius = 0;
//so we are rotating around the center, rather than (0,0):
translate(width/2, height/2);
for (int i = 0; i < str.length(); i++) {
radius += 2;
// taken out because of non-constant spacing at large radius:
//rotate(0.5);
// this should give constant spacing, no matter the radius
// change 10 to some other number for a different spacing.
rotate(10/radius);
// drawing at (0,radius) because we're drawing onto a rotated canvas
text(str.charAt(i), 0, radius);
}
You may want to have the angle change be a function of radius, because at large radii, the letters are spaced very far apart. One way to do this would be using the equation s = rθ, where s is the arclength (in this case, distance between letters), r is radius, and θ is the angle change. If you want a constant distance between letters, regardless of radius, then θ would have to be proportional to 1/r. And of course, you can tweak the hard-coded values to your liking.
Also: the rotate() and translate() methods are undone at the end of draw(), so if you aren't doing anything after this code, then it's okay to leave it as is. If you do want to draw more stuff after, then you'll have to undo the rotation and translation manually before you draw anything else.
Edit: I just realized that I assumed you wanted the letters to be rotated as well, and not just positioned in a spiral but still oriented normally. In that case, you could use your existing code and replace the ellipse(...) with text(str.charAt(...)...), with appropriate parameters of course.