So a few years ago I spent quite a while using Java to dismantle images from a video feed to detect motion. Using some of the tricks I learned there, I started porting the concept to PHP. Some of my current goals here include but are not limited to the following:
Merging/blending images together.
Finding motion/changes between two or more images.
Reporting said motion/changes as a center coordinate, bounding rectangle, or best yet a vector.
Download
If you're anything like me and don't want to read all my mumbo-jumbo, then you can just go ahead and checkout and download the code on Github here.
Breakdown
First a break down of the main classes... What do they do:
SimpleImage
A class that represents an image. Has functions that help load images from files, stream images to a client, crop, resize, merge/overlay another image, etc.
State
Basically a wrapper for a 2D array of numbers. Provides functions for determining the average, standard-deviation and some other interesting things about said array of numbers. Also some manipulators to filter or change the numbers into other meaningful data. States can be derived from images, or functions of other states.
Code Examples
Blending images together.
What for?
Artificial super long exposure photography.
Part of my process to display motion detection in a feed of images from a webcam.
include "SimpleImage.php";
include "Util.php";
// get a list of images from a subdirectory
$imagePath = "./img/3/";
$files = listFilesInDirectory($imagePath);
// setup an image to work with
$baseImage = new SimpleImage($imagePath.$files[0]);
// setup an array of all other images
$images = array();
for ($i = 1; $i < count($files); $i++)
$images[] = new SimpleImage($imagePath.$files[$i]);
// merge the latter images into the first image.
$baseImage->merge($images);
// stream image to client
$baseImage->output();
The above process was run on some images like this:
The result looking like this:
Motion/Change detection
In the following example, the actual change is determined within the first few lines. The second half of the code is just there to display results of said detection.
include "SimpleImage.php";
include "State.php";
// setup two images to work with
$i1 = new SimpleImage("./img/4/IMG_0392.JPG");
$i2 = new SimpleImage("./img/4/IMG_0393.JPG");
// setup the states that will work with and interpret the numbers
$state = new State(15, 8, $i1);
$state = $state->difference(new State(15, 8, $i2), rgbColorDistance);
$state->abs()->denoiseStdDev()->scale(10)->round(0);
// for purposes of visual debugging, merge the two images together
$i1->merge($i2);
// using the merged image, layer on a visual of state differences
$result = $state->drawImageIndicator($i1);
// $box will hold an array (x,y,w,h) that indicates location of change
$box = $state->getBoundingBox($i1->getWidth(), $i1->getHeight());
$color = imagecolorallocate($result->getImage(), 10, 255, 10);
imagerectangle($result->getImage(), $box["x"]-1, $box["y"]-1,
$box["x"]+$box["w"]+1, $box["y"]+$box["h"],
$color);
// $cog will hold an array (x,y) indicating center of change
$cog = $state->getCenterOfGravity($i1->getWidth(), $i1->getHeight());
imagearc($result->getImage(),
$cog["x"], $cog["y"], 7, 7, 0, 360,
imagecolorallocate($result->getImage(), 255, 255, 0));
imagearc($result->getImage(),
$cog["x"], $cog["y"], 9, 9, 0, 360,
imagecolorallocate($result->getImage(), 255, 0, 0));
// stream image to client
$result->output();
The above process was run on these two images:
The result looking like this:
Goals for my next version
Add edge detection and island detection (multiple hotspots of change) in one image.
Removing non-still objects from a set of images to produce one still image. (ie: Remove tourists from my picture of some famous monument)
Herein lies details on how to find the Chinese Visa office in Hong Kong from the metro/mrt. It is not difficult to find if you know where it is.
The first time I went I ended up walking around in circles because I didn't know exactly what I was looking for. Following is a description of the fastest route I found to the office from the metro.
* Take the blue line on the metro to Wan Chai Station.
* Go out Exit A5.
* Walk straight out the exit and follow signs toward the Convention Centre.
* Follow the walkway over about 3 roads.
* Before entering Immigration Tower, turn right and go down stairs.
* Walk 50 meters through courtyard, keeping the road on your right. You should approach the corner where there is a crossing.
* Go over the road towards the bridge.
* Once over the road, keep left and go under bridge, not up the stairs.
* Once under the bridge, cross over the road twice and you'll be right there by the entrance to the Visa Office.
Further warnings and info:
* No big bags are allowed through the front door. So basically, if it's got wheels, it's probably too big. Back packs and hand bags are okay.
* You need to pass any small bag you have through a security scanner so obviously don't take anything too dubious with you.
* At the elevator go to the 7th floor.
* On the 7th floor, walk in and turn right and tell the guy you want a visa. He'll give you an application which you need to fill in completely (he will check).
* Once application is filled in take it back to the chap that gave it to you and he'll give you a number.
* Once you have this number you wait for your turn to hand in your application at the front.
Hope that helps someone, someday.
The visa office is in that shorter white building in the middle.
I present to the world my latest invention, FBChatAT. A Facebook Chat Inline Auto Translation tool for Google Chrome. (If you don't use Chrome then click here, install, and be set free.)
When you receive a message in Facebook Chat, the extension will automatically translate that message into your native language, then insert the translated text underneath the original message. This allows you to review/read the original messages and translation simultaneously while you chat.
Secondly.. To type in your native language and have it automatically translated out: An extra textbox is provided at the bottom left of the screen. Type into this box your text will be translated and shown in the space provided above. If/when you are happy with your outgoing message, press 'enter'. This will push the translated text into the current active chat flyout/window. Press 'enter' a second time to push the message into the chat stream.
The default native and foreign languages are English and Traditional Chinese respectively. You can set your preferred languages in the options page of the extension. (Right click FB button in toolbar and choose options).
You may find the full source for this extension on GitHub.
This extension uses Google Translate for the translation.
This idea stemmed from something I've wanted to try for quite a while. That is to train a pet to do something, maybe even something convoluted or unnecessary, to get food or a treat.
Well I finally have the opportunity to build such a contraption. We recently adopted an orphan cat, and have also recently acquired a lot of spare time. So here's the goal. A small machine that dispenses treats when the cat pushes a button. Some design goals:
Large container for cat pellets that empties FIFO style.
Some controlled mechanism of dispensing above-mentioned pellets.
Sensor feedback to indicate when pellets had left the machine.
UI feedback to indicate state of machine. (Ready, Dispensing, Done)
Easy UI for animal to prompt pellet dispensation.
It ended up looking like this..
The cat is meant to press the paddle and then wait for their surprise to pop out the hole. The machine body is made from a cake box and cardboard. Everything was stuck together with cello-tape. Not the best building materials I know but that's all I had at the time.
I thought it was going to be really easy to teach my cat to interface with the machine... Turns out he got impatient quite quickly, and was probably more fascinated with the sound of the spinning motor, than the treats popping out the front.
A breakdown of the electrical components I used:
Arduino Nano
ULN2004A Darlington Array
Some colored LEDS
Resistors. I think anything between 0.5k to 2k should be fine.
Photoresistor.
Stepper motor of your choice
Power source suited to your motor
The following is what I cooked up around the Arduino. A lot of this was trial and error as I am a programmer and not an electrician. Needless to say this was all a large learning curve (which is what I wanted).
The final Arduino Sketch ended up looking like the below. It wasn't all that I'd hoped it would be; I had gotten fed up several times with trying to monitor time based operations on the Arduino. My sketch always seemed to end up dying after a few hours?.. After a while of hopeless debugging I resigned to just removing the offending bits of code. Sad I know, but actually not too bothered since this is all for the cat. The initial more-feature-complete-sketch can be found here. That still has the photoresistor feedback and some other time based functions in it.
int motorPin1 = 2; int motorPin2 = 3; int motorPin3 = 4; int motorPin4 = 5; int spinDelay = 25; // the delay between motor steps int spinAmount = 220; // how many steps should the motor turn? int motorState = 0; boolean motorDirection = true; // used to alternate between motor directions
int redLight = 6; int greenLight = 8;
int buttonPin = 12; // the pin that the pushbutton is attached to int buttonState = 0; // current state of the button
Pushing a button or paddle turned out to be way complicated. I thought a nice big paddle was going to be easy for the cat to just stomp on with his feet. I don't think I could have been more wrong. As intuitive as buttons are to humans, they make no sense to animals. Next time I would place the push button in or on the area where the pellets exit the machine. For a -long- time my cat tried to extract pellets out the machine by pushing his paw in the exit hole. This makes a lot of sense now looking back.
I certainly wouldn't use cardboard and cello-tape to build again. The hardest part to manufacture was a device to let pellets out of the store in a controlled fashion. Moreover, a machine like this needs to be built out of something solid and heavy; More than once we came through to the living room to see the machine knocked over with pellets everywhere.
This class is designed on the assumption that your barcode scanner hardware will act like a keyboard. As a barcode is scanned a series of keypress events will be generated by the device. If these key events are in fast enough succession (the order of milliseconds), then it can be assumed that a scanner device pushed the series of key events. Otherwise it is just normal human input and will be ignored by the barcode reader class.
How to use
Include the following code in the head of your web page.