Archive

Math


> let doit x y = x(x(y))
> let arnold x = x ++ "aauuugh"
> putStrLn $ arnold "Get to da choppa"
Get to da choppaaauuugh
> putStrLn ( doit arnold "Nauuugh" )
Nauuughaauuughaauuugh

My advisor last week assigned me the simple task of finding a dataset on which to test the machine learning code I'd been running. Simple enough. There were numerous publications on automatic vehicle labeling and automatic traffic flow analysis. As the existence of this short rant no doubt indicates, the task proved to be significantly more difficult than it appeared in first light. The first twenty or so papers I found which dealt with the subject were behind paywalls. I finally came across the University of Southern California's dataset and KIT-IPF's dataset. USC's dataset, unfortunately, did not contain ground truth, and KIT-IPF's images were taken too close to the targets. After some more digging, I found a reference to the Fort Hood vehicle dataset, which seemed to contain both ground truth and data which is similar to the materials I've been studying so far. The images are black and white, and taken from a great distance. The average vehicle should be around 12 pixels, and the images themselves should be around 1200 pixels, minimum. My task is to train a network to find the appropriate tiny black dots and label them as vehicles. The FH dataset, while provided as a link in the paper, had gone dead. A quick hoop jump through the wayback machine showed a more aged version which linked to a publicly available dataset. If it's as I hope, I'll provide some example excerpts in a later update.

https://www.sdms.afrl.af.mil/index.php?collection=public-data&page=public-data-list

Ahh. Data at last.

A friend of mine was playing with some shadow casting. He requested help with a bit of the math to cast a line from the center of a light to a point to the edge.

In short, here's a picture:

Shadow cast from a point light to a point.

Shadow cast from a point light to a point.

There's no need to use trigonometry to solve this problem. All we need to do is solve some simple vector math problems. I'll try and run through step by step, then give the code at the end. For those with programming inclination, when I say, foo.xy /= 3, that means foo.x /= 3 and foo.y /= 3. When I say foo.xy + bar.xy, it means foo.x + bar.x and foo.y + bar.y.

Let's begin.

The distance between the light and the point forms a line. The line can be represented as a vector. We can take the vector, found by point.xy - light.xy, and stretch it from the point to the edge of the light.

point.xy - light.xy translates the point into a zero-centered coordinate system. That is, instead of having a light at <123, 456> and a point at <124, 457>, we're assuming the light is at zero and moving the light appropriately. That is, the light would be at <0,0> and the point at <1,1>. It means we can use a few neat math tricks like 'normalization'.

So why not just take that vector (found with e.xy - l.xy) and apply it again? "Because it doesn't reach the edge then! Or it stretches past!"

shadow_unnormalized

Ah! So we normalize it so that the slope is the same (e.xy - l.xy)/magnitude(e.xy-l.xy) and then multiply by the magnitude of the distance between the edge of the circle and the point. c.xy = magnitude(l.radius - magnitude(e.xy-l.xy))*(e.xy-l.xy)/magnitude(e.xy-l.xy);

"Whoa. Wait. How's that again?"

Intuitively, imagine a line from the center of the light to a point that's exactly one unit away. Assume the center is at (0,0).

L.........P
0.........1.........2.........3

If the 'light radius' is 3, then all you have to do is multiply the 'unit length' by three to reach the edge. Since our point is already one unit away from the center, we just have to multiply by (3 - 1) = 2!

L-------->P------------------>|
0.........1.........2.........3

If we treat the distance from the light to the point as 'normalized' (as though it were 1), then we can multiply it by the distance from the point to the edge of the circle and it will fill exactly that space.

That's all there is to it. Apply these steps and you can cast a line from a point to the edge of a circle.

shadow_renormalized

Here's the full source:

import javax.swing.*;
import java.awt.*;

/**
 * Created by jcatrambone on 2013/12/20.
 */
public class MainApp extends JFrame {
	public Vector2f lightCenter;
	public float lightRadius;
	public float lightSize = 3.0f; // This is just for display purposes.  How 'big' the light appears.
	public Vector2f entityCenter;
	public float entitySize = 1.0f;

	public static void main(String[] args) {
		MainApp app = new MainApp();

		app.lightCenter = new Vector2f(200f, 200f);
		app.lightRadius = 200f;
		app.entityCenter = new Vector2f(280f, 280f);

		app.setSize(600, 600);
		app.setVisible(true);
	}

	@Override
	public void paint(Graphics g1d) {
		Graphics2D g = (Graphics2D)g1d;
		g.setColor(Color.black);
		g.fillRect(0, 0, 600, 600);

		// Draw the outside boundary of the light.
		g.setPaint(Color.yellow);
		g.drawOval((int)(lightCenter.x-lightRadius), (int)(lightCenter.y-lightRadius), (int)(lightRadius*2), (int)(lightRadius*2));

		// Draw the center of the light.
		g.setPaint(Color.yellow);
		g.drawOval((int) (lightCenter.x - lightSize), (int) (lightCenter.y - lightSize), (int) (lightSize * 2), (int) (lightSize * 2));

		// Draw the entity edge.
		g.setPaint(Color.green);
		g.drawOval((int)(entityCenter.x - entitySize), (int)(entityCenter.y - entitySize), (int)(entitySize*2), (int)(entitySize*2));

		// Draw the important shadow!
		// Shadow starts at the entity, so we only need to calculate the line from the entity to the edge.
		// Translate the entity into the -1,1 range, centered at zero.
		Vector2f entityLocalSpace = entityCenter.minus(lightCenter);
		// Normalize the edge to preserve the angle.
		Vector2f normalizedEdge = entityLocalSpace.getNormalized();
		// Now stretch this to the edge of the circle.  Since the edge is normalized, it has length 1,
		// so all we have to do is multiply by the length of a line from the entity to the edge of the light.
		Vector2f shadowLine = normalizedEdge.multiply(lightRadius - entityLocalSpace.getMagnitude());
		// c.xy = magnitude(l.xy-e.xy)*(e.xy-l.xy)/magnitude(e.xy-l.xy);
		// Whoops.  That first magnitude should be magnitude(l.radius - magnitude(e.xy-l.xy))
		g.setPaint(Color.green);
		g.drawLine((int)entityCenter.x, (int)entityCenter.y, (int)(entityCenter.x+shadowLine.x), (int)(entityCenter.y+shadowLine.y));
	}
}

class Vector2f {
	public float x, y;

	public Vector2f() {
		x=0; y=0;
	}

	public Vector2f(float x, float y) {
		this.x = x;
		this.y = y;
	}

	public Vector2f getNormalized() {
		float mag = this.getMagnitude();
		return new Vector2f(this.x/mag, this.y/mag);
	}

	public float getMagnitude() {
		return (float)Math.sqrt(x*x + y*y);
	}

	public Vector2f add(Vector2f v) {
		return new Vector2f(this.x + v.x, this.y + v.y);
	}

	public Vector2f multiply(float scalar) {
		return new Vector2f(this.x * scalar, this.y * scalar);
	}

	public Vector2f minus(Vector2f v) {
		// foo.minus(bar) = foo - bar
		return new Vector2f(this.x - v.x, this.y - v.y);
	}
}

I've made JavaRBM available to the public on BitBucket: https://bitbucket.org/JosephCatrambone/javarbm

It's not yet licensed, which means there's an implicit non-commercial personal-educational-use license, but I'll run through the code again adding license info at the top when I have time.

Hummus is Mad Delicious and Crazy Easy

  • 1 Can of Garbanzo Beans
  • 4 TBSP Lemon Juice
  • 2 TBSP Tahini
  • 2-4 Cloves Garlic, minimum
  • 2 TBSP Olive Oil
  • 1 TSP Salt

Open and drain garbanzo beans. Do not rinse.
Add everything to the food processor and maul that shit.
Chill like a motherfucker. Tell your hummus, "Bitch, be cool."
Eat with pita bread.

Hummus was invented in the year 2525 by the Norse god Odin.  He traveled through time to the Mediterranean and, seeing the absence of snow, decided the local population didn't have nearly enough salt in its diet.  Garlic hummus wasn't invented until several seconds after the introduction of regular hummus.  Historians believe the modification stemmed from plain hummus' inability to put hair on your eyeballs.  Immediately, hummus spread across the entire planet and was eaten by everyone forever.  The end.

Auxiliary status update: Behind schedule.  7/1000 Math.