|
1 | | -Visualizing af::array with Forge {#forge_visualization} |
2 | | -=================== |
3 | | - |
4 | | -Arrayfire as a library aims to provide a robust and easy to use platform for |
5 | | -high-performance, parallel and GPU computing. |
6 | | - |
7 | | -[TOC] |
8 | | - |
9 | | -The goal of [Forge](https://github.com/arrayfire/forge), an OpenGL visualization |
10 | | -library, is to provide equally robust visualizations that are interoperable |
11 | | -between Arrayfire data-structures and an OpenGL context. |
12 | | - |
13 | | -Arrayfire provides wrapper functions that are designed to be a simple interface |
14 | | -to visualize af::arrays. These functions perform various interop tasks. One in |
15 | | -particular is that instead of wasting time copying and reformatting data from |
16 | | -the GPU to the host and back to the GPU, we can draw directly from GPU-data to |
17 | | -GPU-framebuffers! This saves 2 memory copies. |
18 | | - |
19 | | -Let's see exactly what visuals we can illuminate with forge and how Arrayfire |
20 | | -anneals the data between the two libraries. |
21 | | - |
22 | | -# Setup {#setup} |
23 | | -Before we can call Forge functions, we need to set up the related "canvas" classes. |
24 | | -Forge functions are tied to the af::Window class. First let's create a window: |
25 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
26 | | -const static int width = 512, height = 512; |
27 | | -af::Window window(width, height, "2D plot example title"); |
28 | | -
|
29 | | -do{ |
30 | | -
|
31 | | -//drawing functions here |
32 | | -
|
33 | | -} while( !window.close() ); |
34 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
35 | | - |
36 | | -We also added a drawing loop, so now we can use Forge's drawing functions to |
37 | | -draw to the window. |
38 | | -The drawing functions present in Forge are listed below. |
39 | | - |
40 | | -# Rendering Functions {#render_func} |
41 | | - |
42 | | -Documentation for rendering functions can be found [here](\ref gfx_func_draw). |
43 | | - |
44 | | -## Image {#image} |
45 | | -The af::Window::image() function can be used to plot grayscale or color images. |
46 | | -To plot a grayscale image a 2d array should be passed into the function. |
47 | | -Let's see this on a static noise example: |
48 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
49 | | -array img = constant(0, width, height); //make a black image |
50 | | -array random = randu(width, height); //make random [0,1] distribution |
51 | | -img(random > 0.5) = 1; //set all pixels where distribution > 0.5 to white |
52 | | -
|
53 | | -window.image(img); |
54 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
55 | | -<img src="gfx_docs_images/noise.png" alt="Forge image plot of noise" width="20%" /> |
56 | | -Tweaking the previous example by giving our image a depth of 3 for the RGB values |
57 | | -allows us to generate colorful noise: |
58 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
59 | | -array img = 255 * randu(width, height, 3); //make random [0, 255] distribution |
60 | | -window.image( img.as(u8) ); |
61 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
62 | | -<img src="gfx_docs_images/color_noise.png" alt="Forge image plot of color noise" width="20%" /> |
63 | | -Note that Forge automatically handles any af::array type passed from Arrayfire. |
64 | | -In the first example we passed in an image of floats in the range [0, 1]. |
65 | | -In the last example we cast our array to an unsigned byte array with the range |
66 | | -[0, 255]. The type-handling properties are consistent for all Forge drawing functions. |
67 | | - |
68 | | -## Plot {#plot} |
69 | | -The af::Window::plot() function visualizes an array as a 2d-line plot. Let's see |
70 | | -a simple example: |
71 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
72 | | -array X = seq(-af::Pi, af::Pi, 0.01); |
73 | | -array Y = sin(X); |
74 | | -window.plot(X, Y); |
75 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
76 | | - |
77 | | -<img src="gfx_docs_images/sin_plot.png" alt="Forge 2d line plot of sin() function" width="30%" /> |
78 | | -The plot function has the signature: |
79 | | - |
80 | | -> **void plot( const array &X, const array &Y, const char * const title = NULL );** |
81 | | -
|
82 | | -Both the x and y coordinates of the points are required to plot. This allows for |
83 | | -non-uniform, or parametric plots: |
84 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
85 | | -array t = seq(0, 100, 0.01); |
86 | | -array X = sin(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5)); |
87 | | -array Y = cos(t) * (exp(cos(t)) - 2 * cos(4 * t) - pow(sin(t / 12), 5)); |
88 | | -window.plot(X, Y); |
89 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
90 | | - |
91 | | -<img src="gfx_docs_images/butterfly_plot.png" alt="Forge 2d line plot of butterfly function" width="30%" /> |
92 | | - |
93 | | -## Plot3 {#plot3} |
94 | | -The af::Window::plot3() function will plot a curve in 3d-space. |
95 | | -Its signature is: |
96 | | -> **void plot3 (const array &in, const char * title = NULL);** |
97 | | -The input array expects xyz-triplets in sequential order. The points can be in a |
98 | | -flattened one dimensional (*3n x 1*) array, or in one of the (*3 x n*), (*n x 3*) matrix forms. |
99 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
100 | | -array Z = seq(0.1f, 10.f, 0.01); |
101 | | -array Y = sin(10 * Z) / Z; |
102 | | -array X = cos(10 * Z) / Z; |
103 | | -
|
104 | | -array Pts = join(1, X, Y, Z); |
105 | | -//Pts can be passed in as a matrix in the from n x 3, 3 x n |
106 | | -//or in the flattened xyz-triplet array with size 3n x 1 |
107 | | -window.plot3(Pts); |
108 | | -//both of the following are equally valid |
109 | | -//window.plot3(transpose(Pts)); |
110 | | -//window.plot3(flat(Pts)); |
111 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
112 | | -<img src="gfx_docs_images/spiral_plot3.png" alt="Forge 3d line plot" width="40%" /> |
113 | | - |
114 | | -## Histogram {#histogram} |
115 | | -The af::Window::hist() function renders an input array as a histogram. |
116 | | -In our example, the input array will be created with Arrayfire's histogram() |
117 | | -function, which actually counts and bins each sample. The output from histogram() |
118 | | -can directly be fed into the af::Window::hist() rendering function. |
119 | | - |
120 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
121 | | -const int BINS = 128; SAMPLES = 9162; |
122 | | -array norm = randn(SAMPLES); |
123 | | -array hist_arr = histogram(norm, BINS); |
124 | | -
|
125 | | -win.hist(hist_arr, 0, BINS); |
126 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
127 | | -In addition to the histogram array with the number of samples in each bin, the |
128 | | -af::Window::hist() function takes two additional parameters -- the minimum and |
129 | | -maximum values of all datapoints in the histogram array. This effectively sets |
130 | | -the range of the binned data. The full signature of af::Window::hist() is: |
131 | | -> **void hist(const array & X, const double minval, const double maxval, const char * const title = NULL);** |
132 | | -<img src="gfx_docs_images/norm_histogram.png" alt="Forge 3d scatter plot" width="40%" /> |
133 | | -
|
134 | | - |
135 | | -## Surface {#surface} |
136 | | -The af::Window::surface() function will plot af::arrays as a 3d surface. |
137 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
138 | | -array Z = randu(21, 21); |
139 | | -window.surface(Z, "Random Surface"); //equal to next function call |
140 | | -//window.surface( seq(-1, 1, 0.1), seq(-1, 1, 0.1), Z, "Random Surface"); |
141 | | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
142 | | -<img src="gfx_docs_images/rand_surface.png" alt="Forge random surface plot" width="30%" /> |
143 | | -There are two overloads for the af::Window::surface() function: |
144 | | -> **void surface (const array & S, const char * const title )** |
145 | | -> // Accepts a 2d matrix with the z values of the surface |
146 | | -
|
147 | | -> **void surface (const array &xVals, const array &yVals, const array &S, const char * const title)** |
148 | | -> // accepts additional vectors that define the x,y coordinates for the surface points. |
149 | | -
|
150 | | -The second overload has two options for the x, y coordinate vectors. Assuming a surface grid of size **m x n**: |
151 | | - 1. Short vectors defining the spacing along each axis. Vectors will have sizes **m x 1** and **n x 1**. |
152 | | - 2. Vectors containing the coordinates of each and every point. |
153 | | - Each of the vectors will have length **mn x 1**. |
154 | | - This can be used for completely non-uniform or parametric surfaces. |
155 | | - |
156 | | -# Conclusion {#conclusion} |
157 | | -There is a fairly comprehensive collection of methods to visualize data in Arrayfire. |
158 | | -Thanks to the high-performance gpu plotting library Forge, the provided Arrayfire |
159 | | -functions not only make visualizations as simple as possible, but keep them as |
160 | | -robust as the rest of the Arrayfire library. |
| 1 | +robust as the rest of the ArrayFire library. |
0 commit comments