Parse a matrix and array of doubles to la4j object - java

I have experimented and I can't find a way to parse an array of Integers and a Matrix of doubles to a la4j matrice/vector object.
public void fillData(int[][] data2D, int height, int width) throws IOException{
int[] data = initializeData(height, width);
double [][] coordinates = initializeDataCoordinates(height, width);
Matrix a = new Basic2DMatrix();
int index1d = 0;
for(int row = 0; row < height; row++){
for(int col = 0; col < width; col++){
int y = col+1;
int x = row+1;
//System.out.println("Current X: " + x);
//System.out.println("Current Y: " + y);
double xPow = Math.pow(x, 2);
double yPow = Math.pow(y, 2);
coordinates[row][0] = xPow*yPow;
coordinates[row][1] = x*yPow;
coordinates[row][2] = yPow;
coordinates[row][3] = xPow*y;
coordinates[row][4] = x*y;
coordinates[row][5] = y;
coordinates[row][6] = xPow;
coordinates[row][7] = x;
coordinates[row][8] = 1;
a.add((double)data2D[row][col]);
data[index1d] = data2D[row][col];
index1d++;
}
}
}
As you can see, I try to use the add method of the la4j lib but the matrice stays empty. My goal is to parse the whole content of double[][] coordinates and int[] data to la4j matrice and vector, respectivelly.
I have also tried parsing these to a CSV file but the scientific notation (due to extremely big numbers in my coordinates matrix) I can't parse it properly.
Any tips and ideas?

Here is the thing. First, you create 0x0 matrix with just call to the constructor new Basic2DMatrix(). Second, matrix.add is addition operation not insertion into the matrix (like matrix plus other matrix, or matrix plus value in your case). Calling matrix.add(value) adds given value to all the cells. In your case there is no cells in your matrix = nothing happened. All you need to do is call the constructor and pass the coordinates array there.
Matrix a = new Basic2DMatrix(coordinates); // easy-peasy
You can also use public access methods like get/set to manually set every element.

Related

Problem with Scan-Line Polygon Filling algorithm in java

(please don't mark this question as not clear, I spent a lot of time posting it ;) )
Okay, I am trying to make a simple 2d java game engine as a learning project, and part of it is rendering a filled polygon as a feature.
I am creating this algorithm my self, and I really can't figure out what I am doing wrong.
My though process is something like so:
Loop through every line, get the number of points in that line, then get the X location of every point in that line,
Then loop through the line again this time checking if the x in the loop is inside one of the lines in the points array, if so, draw it.
Disclaimer: the Polygon class is another type of mesh, and its draw method returns an int array with lines drawn through each vertex.
Disclaimer 2: I've tried other people's solutions but none really helped me and none really explained it properly (which is not the point in a learning project).
The draw methods are called one per frame.
FilledPolygon:
#Override
public int[] draw() {
int[] pixels = new Polygon(verts).draw();
int[] filled = new int[width * height];
for (int y = 0; y < height; y++) {
int count = 0;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
count++;
}
}
int[] points = new int[count];
int current = 0;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
points[current] = x;
current++;
}
}
if (count >= 2) {
int num = count;
if (count % 2 != 0)
num--;
for (int i = 0; i < num; i += 2) {
for (int x = points[i]; x < points[i+1]; x++) {
filled[x + y * width] = 0xffffffff;
}
}
}
}
return filled;
}
The Polygon class simply uses Bresenham's line algorithm and has nothing to do with the problem.
The game class:
#Override
public void load() {
obj = new EngineObject();
obj.addComponent(new MeshRenderer(new FilledPolygon(new int[][] {
{0,0},
{60, 0},
{0, 60},
{80, 50}
})));
((MeshRenderer)(obj.getComponent(MeshRenderer.class))).color = CYAN;
obj.transform.position.Y = 100;
}
The expected result is to get this shape filled up.(it was created using the polygon mesh):
The actual result of using the FilledPolygon mesh:
You code seems to have several problems and I will not focus on that.
Your approach based on drawing the outline then filling the "inside" runs cannot work in the general case because the outlines join at the vertices and intersections, and the alternation outside-edge-inside-edge-outside is broken, in an unrecoverable way (you can't know which segment to fill by just looking at a row).
You'd better use a standard polygon filling algorithm. You will find many descriptions on the Web.
For a simple but somewhat inefficient solution, work as follows:
process all lines between the minimum and maximum ordinates; let Y be the current ordinate;
loop on the edges;
assign every vertex a positive or negative sign if y ≥ Y or y < Y (mind the asymmetry !);
whenever the endpoints of an edge have a different sign, compute the intersection between the edge and the line;
you will get an even number of intersections; sort them horizontally;
draw between every other point.
You can get a more efficient solution by keeping a trace of which edges cross the current line, in a so-called "active list". Check the algorithms known as "scanline fill".
Note that you imply that pixels[] has the same width*height size as filled[]. Based on the mangled output, I would say that they are just not the same.
Otherwise if you just want to fill a scanline (assuming everything is convex), that code is overcomplicated, simply look for the endpoints and loop between them:
public int[] draw() {
int[] pixels = new Polygon(verts).draw();
int[] filled = new int[width * height];
for (int y = 0; y < height; y++) {
int left = -1;
for (int x = 0; x < width; x++) {
if (pixels[x + y * width] == 0xffffffff) {
left = x;
break;
}
}
if (left >= 0) {
int right = left;
for (int x = width - 1; x > left; x--) {
if (pixels[x + y * width] == 0xffffffff) {
right = x;
break;
}
}
for (int x = left; x <= right; x++) {
filled[x + y * width] = 0xffffffff;
}
}
}
return filled;
}
However this kind of approach relies on having the entire polygon in the view, which may not always be the case in real life.

Error related to prediction function using SVM in OpenCV Android

I am trying to use an SVM in Android using OpenCV's Android SDK. Everything seems to work correctly besides the predict() function.
I get the following error:
svm CvException error: (-215) samples.cols == var_count && samples.type() == CV_32F in function virtual float cv::ml::SVMImpl::predict(cv::InputArray, cv::OutputArray, int) const ]
I am rather certain that the dimensions and types are correct, but I have a feeling I am overlooking something simple. Below is the description of my code with the relevant code.
I have 60 training examples with 150 features each. All examples and labels are in a 2D float array of dimension 60x151 called dataset_2Darr. The right-most column has the labels stored as -1, 0, +1 for the three classes.
I first place the 60x150 sub-matrix in the Mat object X.
Then, I place the labels in the 60x1 Mat object Y.
X is float - CV_ 32FC1
Y is int - CV_32SC1
The relevant code is executed in 3 parts of the overall program. Here are the three parts:
Part 1: Global Variables in top of MainActivity.java:
static int M = 60; // Rows - examples
static int N = 150; // Cols - features
public static Mat X; // Data
public static Mat Y; // Labels
// Instantiate SVM object globally
static SVM classifier = SVM.create();
Part 2: Inside OnCreate():
// SVM Stuff:
classifier.setKernel(SVM.LINEAR);
classifier.setType(SVM.C_SVC);
classifier.setGamma(0.5);
classifier.setNu(0.5);
classifier.setC(1);
//classifier.setTermCriteria(criteria);
// Dataset stuff:
Y = new Mat(new Size(1,M),CvType.CV_32SC1); // Integer {-1, 0, +1}
int Y_rows = Y.rows(); // 60
int Y_cols = Y.cols(); // 1
X = new Mat(new Size(N,M),CvType.CV_32FC1); // Float
int X_rows = X.rows(); // 60
int X_cols = X.cols(); // 150
Part 3: Inside method that executes code:
for (int i=0; i < 60; i++) {
for(int j=0; j < 150; j++) {
X.put(i, j, dataset_2Darr[i][j]); // Copy 2D array into mat object
}
}
// Iterate down rows of right-most column
for (int i = 0; i < 60; ++i)
Y.put(i,0, (int)dataset_2Darr[i][150]); // Copy right most column into label array
// Train the model using X and Y
classifier.train(X, Ml.ROW_SAMPLE, Y);
// Create 1x150 feature vector to test:
Mat x = new Mat(new Size(150, 1),CvType.CV_32FC1); // Float
int x_rows = x.rows(); // 1
int x_cols = x.cols(); // 150
// Place dummy values inside matrix x
for (int i = 0; i < 150; i++) {
x.put(0, i, 0.2f);
}
//Mat outMat = new Mat();
//float response = classifier.predict(x, outMat, 0);
float prediction = classifier.predict(x);
I met the same problem recently. The shape and type of test data are fine, but somehow the SVM model cannot work with the test data.
The solution is that you need to make sure the dimension of test data is the same as the training data.
Note that the dimension of [1,2,3] is 1, and the dimension of [[1,2,3]] is 2.

Single array to store multiple variables in each element

EDIT: to clarify, one of my requirements is to use a single array.
I am having trouble storing multiple variables to a single element in an array. We are creating a really simple program to mimic Microsoft Paint. One of the requirements is to store each element I draw in to an array so that the 'paint' method repaints the drawings each time the windows is minimized and then redisplayed. Here are the requirements
We are to assume a max size for the array is 20.
Each element should include 5 variables:
char shape (l for line, r for rectangle, c for circle)
Start x value
Start y value
width (rectangle), or ending x (line), or radius (circle)
height (rectangle), or ending y (line), or radius (circle)
Here is my code for the array class:
class storeDraws {
final int MAXSIZE = 20;
static int S[];
static int n; //number of draws user makes
static char shape;
static double px, py, w, h;
storeDraws () {
S = new int [MAXSIZE];
n = 0;
shape = 'l';
px = 0;
py = 0;
w = 0;
h = 0;
}
}
I have read a few places that I can input the array as (using the mouseReleased(MouseEvent e) method:
storeDraws[] input = new storeDraws{value, value, value, value, value};
But I don't think that would work for what I am trying to do with the 'paint' method to redraw the shapes. I thought I could somehow pass it using the standard format of S[n] = (char, double, double, double, double), but I get warning that this is illegal.
Edit 8:30 am
I got this part working. In my class here is my code now.
class storeDraws {
static char shape;
static int px, py, w, h;
storeDraws () {
shape = 'l';
px = 0;
py = 0;
w = 0;
h = 0;
}
}
I then declared this in the DrawPanel class:
private storeDraws[] store = new storeDraws[20];
private int n = 0;
And mouseReleased method of DrawPanel:
public void mouseReleased(MouseEvent e) {
if (drawShape == "line") {
store[n].shape = 'l';
store[n].px = p1.x;
store[n].py = p1.y;
store[n].w = p3.x;
store[n].h = p3.y;
n++;
}
And paint:
public void paint(Graphics g) {
for (int i = 0; i < n; i++) {
if (store[i].shape == 'l')
g.drawLine(store[n].px, store[n].py, store[n].w, store[n].h);
But if I draw 6 lines it only repaints the last line.
I think you need to separate some of the functionality you want. You can have a class for each of the elements and then store instances of the class in an array of DrawingElement objects.
So you'd do something like this:
DrawingElement[] drawing = new DrawingElement[20];
DrawingElement circle = new DrawingElement('c', 10, 10, 10, 10);
DrawingElement rect = new DrawingElement('r', 20, 10, 10, 10);
drawing[0] = circle;
drawing[1] = rect;
Note: If you need to be able to get the number of objects in the array (variable n in your code) you may want to use some implementation of
a Linked List (which has a size() method) and do some check when adding elements to make sure you don't add past the max of 20.
Example with LinkedList:
LinkedList<DrawingElement> drawing = new LinkedList<DrawingElement>();
DrawingElement circle = new DrawingElement('c', 10, 10, 10, 10);
DrawingElement rect = new DrawingElement('r', 20, 10, 10, 10);
drawing.add(circle);
drawing.add(rect);
int n = drawing.size(); //will be 2
The Drawing Element Class:
public class DrawingElement
{
char shape;
double px, py, w, h;
public DrawingElement(char shape, double px, double py, double w, double h)
{
this.shape = shape;
this.px = px;
this.py = py;
this.w = w;
this.h = h;
}
//Add getters and setters (accessors and mutators) for class variables
}
I think you should use collection for this purpose.Create array, store values
then add each array object in collection(list).
you can use arraylist instead of array. this will help you to store different variable.
If there is need of using only array you can use object array
Sample Code
object a[]= {'a',10,10.2,10.3,10.4,10.5}
Please refer ArrayList
In your case it would be better to use Java Collection(ArrayList) rather than Array.
First point, We cannot store different types of variables values into an Array.
An array is a container object that holds a fixed number of values of a single type.
Here you are trying to store multiple type of variables into integer array.
see this link:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
To overcome this drawback, We have Collection API introduced with JDK1.5
Refer this link:
http://docs.oracle.com/javase/tutorial/collections/index.html

Java 3d parametric surfaces drawing

i really need your help since that i am fighting with the unknown for some time now.
I am trying to draw a parametric surface on java 3d. The surface is being drawn if i a use a point array. Here is the code :
PointArray lsa=new PointArray(length, GeometryArray.COLOR_3|GeometryArray.NORMALS|GeometryArray.COORDINATES);
float maxV=(float) ((float) 2*Math.PI);
float maxU=(float) ((float) Math.PI);
Vector3f norm = new Vector3f();
for (float v = 0.01f; v < maxV; v+=0.03)
{
for (float u = 0.01f; u < maxU; u+=0.03)
{
vIndex++;
Point3f pt = new Point3f();
pt.x=(float) (Math.sin(u)*Math.cos(v));
pt.y=(float) (2*Math.sin(u)*Math.sin(v));
pt.z=(float) Math.cos(u);
lsa.setCoordinate(vIndex, pt);
lsa.setColor(vIndex, new Color3f(0.9f,0.0f,0.0f));
}
}
Shape3D shape = new Shape3D(lsa);
The problem that I have is that it's drawing only the points (dots) so it's not a full drawn surface. How can I draw this parametric surface with polygons or any surface? Are there any methods ?
I am searching the Web, bought Books but I still can not make it with java 3d.
Thank you very much.
Here's how I would do it.
I would define a
Point3f[][] points = new Point3f[(int)((umax-umin)/du)][(int)((vmax-vmin)/dv)];
Then use loops similar to the ones you have int i = 0; i<points.length; i++, int j = 0; j < points[0].length; j++. Define u = i * du + umin, v = j * dv + vmin.
and populate this array with Point3f corresponding to (u, v).
Loop int i = 0; i<points.length - 1; i++, int j = 0; j < points[0].length - 1; j++ and get the points at points[i][j], points[i+1][j], points[i][j+1], and points[i+1][j+1].
Then use the method given in this article to convert these points into a Polygon. Add it to your model / an array that you later add to your model.
Of course, this may not be the best way to do it and I have the feeling that it doesn't handle discontinuities very well, but it should at least make polygons.
Hello here is the solution, it draws a coons surface for example, it should work for any parametric surface x(s, t), y(s, t), z(s, t).
public static Shape3D getShape3D()
{
//Coons
int ns=100;
int nt=100;
float param0=1.0f;
float param1=3.0f;
float s=0.0f;
float t=0.0f;
if (ns>500) ns=500;
if (nt>500) nt=500;
Point3f[][] f=new Point3f[ns][nt];
int sizeOfVectors=0;
for (int i=0;i<ns;i++) //t -->s
{
for (int j=0;j<nt;j++) //u ---t
{
s=((float) i/ns);
t=((float) j/nt);
//System.out.println(" i "+ i + " j "+ j + " s "+ s + " t "+ t);
f[i][j]=new Point3f();
//f[i][j].x=s;
//f[i][j].y=2*t;
//f[i][j].z=10*t*(1-s);
f[i][j].x=param0*s;
f[i][j].y=param1*t;
f[i][j].z=(float) (0.5*((54*s*Math.sqrt(s)-126*Math.sqrt(s)+72*s-6)*t+(27*Math.sqrt(s)-27*s+6)));
/*f[i][j].x = (float) (Math.sqrt(s)*Math.cos(t));
f[i][j].y=(float) (Math.sqrt(s)*Math.sin(t));
f[i][j].z=s;*/
sizeOfVectors++;
sizeOfVectors++;
}
}
System.out.println("Total vectors "+sizeOfVectors);
Shape3D plShape = new Shape3D();
int vIndex=-1;
int k=0;
for (int i=0;i<(ns-1);i++)
{
k=i+1;
sizeOfVectors=nt*2;
vIndex=-1;
TriangleStripArray lsa=new TriangleStripArray(sizeOfVectors, GeometryArray.COLOR_3|GeometryArray.COORDINATES|GeometryArray.NORMALS, new int[] {sizeOfVectors});
for (int j=0;j<nt;j++)
{
vIndex++;
lsa.setCoordinate(vIndex, f[i][j]);
lsa.setColor(vIndex, new Color3f(0.9f,0.0f,0.0f));
vIndex++;
lsa.setCoordinate(vIndex, f[k][j]);
lsa.setColor(vIndex, new Color3f(0.9f,0.0f,0.0f));
}
plShape.addGeometry(lsa);
}
return plShape;
}
It works like a dream. Your guidance was the catalyst to finally make it.

Summed area table (integral image) returns nonsenses on rectangle sum

So here on wikipedia you can see an article describing how summed area table (integral image) works. It's a very important part of computer vision and image analysis.
I'm trying to implement it. The concept is really simple:
Make an array[imageheight][imagewidth]
Every array member should contain sum of all pixels before and above in the original image
To get sum on any rectangle, use A-B-C+D formula, where ABCD is this rectangle:
So I made this function to sum all pixels on BufferedImage:
public static double[][] integralImageGrayscale(BufferedImage image) {
//Cache width and height in variables
int w = image.getWidth();
int h = image.getHeight();
//Create the 2D array as large as the image is
//Notice that I use [Y, X] coordinates to comply with the formula
double integral_image[][] = new double[h][w];
//Sum to be assigned to the pixels
double the_sum = 0;
//Well... the loop
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
//Get pixel. It's actually 0xAARRGGBB, so the function should be getARGB
int pixel = image.getRGB(x, y);
//Extrapolate color values from the integer
the_sum+= ((pixel&0x00FF0000)>>16)+((pixel&0x0000FF00)>>8)+(pixel&0x000000FF);
integral_image[y][x] = the_sum;
}
}
//Return the array
return integral_image;
}
I also made a debug function and it's convincing me that it works:
Notice how the white areas influence the sum of the image
But if I make this test case:
//Summed area table (thing is BufferedImage)
double is[][] = ScreenWatcher.integralImageGrayscale(thing);
//Sum generated by a normal for loop
double ss = ScreenWatcher.grayscaleSum(thing);
//Height of the resulting array
int ish = is.length;
//Width of resulting array. Also throws nasty error if something goes wrong
int isw = is[is.length-1].length;
//Testing whether different methods give same results
System.out.println(
ss +" =? " +
//Last "pixel" in integral image must contain the sum of the image
is[ish-1][isw-1]+" =? "+
//The "sum over rectangle" with a rectangle that contains whole image
// A B C D
(+is[0][0] -is[0][isw-1] -is[ish-1][0] +is[ish-1][isw-1])
);
I get a sad result:
1.7471835E7 =? 1.7471835E7 =? 112455.0
Interesting thing is, that pure white image returns 0:
7650000.0 =? 7650000.0 =? 0.0 - this was 100x100 white image and 765 is 3*255 so everything seems right
I have no idea how to get to the bottom of this. Everything seems too clear to contain a mistake. So either there's a typo in the code above, or the logic is wrong. Any ideas?
Your problem is here:
//Extrapolate color values from the integer
the_sum+= ((pixel&0x00FF0000)>>16)+((pixel&0x0000FF00)>>8)+(pixel&0x000000FF);
integral_image[y][x] = the_sum;
What you should be doing is:
int A = (x > 0 && y > 0) ? integral_image[y-1][x-1] : 0;
int B = (x > 0) ? integral_image[y][x-1] : 0;
int C = (y > 0) ? integral_image[y-1][x] : 0;
integral_image[y][x] = - A + B + C
+ ((pixel&0x00FF0000)>>16)+((pixel&0x0000FF00)>>8)+(pixel&0x000000FF);
(with no the_sum variable).
Evaluating the sum for the portion of the image (minx, miny) -> (maxx, maxy) inclusively can now be done in constant time using the values in integral_image:
double A = (minx > 0 && miny > 0) ? integral_image[miny-1][minx-1] : 0;
double B = (minx > 0) ? integral_image[maxy][minx-1] : 0;
double C = (miny > 0) ? integral_image[miny-1][maxx] : 0;
double D = integral_image[maxy][maxx];
double sum = A - B - C + D;
Note that minx-1 and miny-1 are used because of the inclusivity on the minimum coordinates.

Categories

Resources