Trace boundary using an image pixel array with NodeJS - javascript

I have this image which is completely black except for a white object in the middle (it can be anything but it is always completely white). What I would like to do with nodeJs, is trace the boundary of the object (I would like to find all the white points which are next to black) in the image (performance is key!)
With pngjs I can read an image which gives me an array in which each pixels has 4 values (RGBA). Its a one dimensional array. So, suppose the image is 1000 x 1000 pixels it gives me an array of 1000 x 1000 x 4 = 4000000 entries.
The below expression converts x and y into an array index
var idx = (1000 * y + x) << 2;
data[idx] = 243;
data[idx + 1] = 16;
data[idx + 2] = 16;
Anyway, I could traverse the whole array and register the points where black changes into white, but as I said, performance is very important. I can imagine that some kind of smart iterative search algorithm exists that can follow the boundary somehow :)
Maybe someone knows a library that can help, or an article about how to do this would be great too!!

Check out chain codes like Freeman Code. You need 1 contour point to start with. So just iterate through your lines until you hit your object. Then you walk around your object until you reach your starting point. You will get a code that describes the direction you took for every step. This code can be used to calculate various object features or to just draw the contour of your object.
Btw if your obect is always white and your background is always black you don't have to process 4 channels. Red, green or blue channels contain the same information. Just use either one of them.

Related

Dominant color in video for each frame

I want to analyze a video (mp4) on flashing of a LED.
The background is usually grey but the color of the LED may vary.
The LED is in the video close enough so the LED-light is the biggest part of the frame.
I found Color-Thief but it's just for images and not for video.
Because the frequency of the flashing may vary too, I need to check each frame of the video for the dominant color.
If anyone has any ideas, I'd greatly appreciate some assistance. Thanks in advance for your time.
EDIT:
Two screenshots of the video (first red LED off; second red LED on) (had to remove the link for color-thief for the two screenshot links)
This is the function which gets called when the video starts playing and should analyze the video. I tried to do it via the average color but that's useless because that's usually some sort of grey/brown.
function processFrame(e) {
var video = document.getElementById("video");
if (video.ended){
//dauer();
console.log("Ende");
//alert("Ende");
}
if (video.paused || video.ended) {
return;
}
var bufferCanvas = document.getElementById("buffer");
var displayCanvas = document.getElementById("display");
var buffer = bufferCanvas.getContext("2d");
var display = displayCanvas.getContext("2d");
buffer.drawImage(video, 0,0, bufferCanvas.width, displayCanvas.height);
var frame = buffer.getImageData(sx, sy, sw, sh);
var length = frame.data.length / 4;
for (var i = 0; i < length; i++) {
var r = frame.data[i * 4 + 0];
var g = frame.data[i * 4 + 1];
var b = frame.data[i * 4 + 2];
average= average +((r+g+b)/3)
}
averagecolor[i]=average
display.putImageData(frame, 0, 0);
setTimeout(processFrame, 0);
}
It's a bit broad what you're asking as you need to do this in several steps - but it's fully possible to do. To shorten down I'll just present the steps you need to take in order to be able to analyze the LEDs.
You can do this fully automatic or semi-automatic be predefining the areas in the video frame.
The steps for automatic detection is as follows and is used once per session in case camera is moved or zoom is changed. Lighting condition can affect the detection as well but here I will assume the lighting conditions are the same and as in the images you are showing. It's also specific for these images and may not work if you change setup of the routers/camera.
Initial step to auto-detect areas:
Scan horizontal lines half way and start registering regions when all RGB values = 255 (that's the white center of the leds). Set a flag that you are in a region and count number of pixels when you start to register based on a threshold (for example 7-10 pixels that needs to be white in a row). This is to eliminate single pixels that way be white.
When you cannot find any white pixels on a line (based on threshold) end region and prepare for new registration.
When at bottom of first half (i would set a max height shorted than actual height), start over scanning from middle to the right edge.
After this you should have six regions registered (use a "calibration" frame where all LEDs are lit - this can be ran manually before running live).
For next step which will be the one running constantly you will use these regions as anchor regions and to sample points only on one side and only a few pixels in height.
Use the region as anchor and define a sample region based on that with an offset x + width of region + 2 pixels as start X (this is just suggestion for an initial offset - you may have to fine-tune this). Offset Y + 10 and set width and height to 10 pixels. This should give you a sample region of 100 points right next to the led.
Run statistics on this small region by using getImageData. You need to check all three components as you need to filter away light-grey. Find a threshold (for instance if r > 230 && b < 200 && g < 200 just to take some values) when kicks in you accumulate your red value (and another for green). This process require a calibration phase to find that threshold value you need to use. Run some tests. If camera changes f-stop you will probably need to re-calibrate.
Accumulate the green and red values to different variables. You do not not need to average them but you will need to find a threshold value for the total sum where you know the led is lit for the LED with that color (use the initial test frame from region detection for this as well). Add some tolerance to the values by comparing the regions when the LEDs are off.
This will give you in total only 600 points to scan maybe less if you can fine-tune it.
For the manual method you skip the region setting as described in first step but use a frame and set the regions manually by measuring pixels of the white top. If you change the camera position you will need to do it over.
As you understand there is a bit code that need to be written for this and there are many factors that will affect the final code making it very specific for this usage. And I believe it's in part outside the scope for SO but I hope this gives you some leads to get you going.

Connecting Rooms

I've created a simple algorithm for a game I'm working on that creates a cave like structure. The algorithm outputs a 2 dimensional array of bits that represent the open area's. Example:
000000000000000000000000
010010000000000111100000
011110000000011111111000
011111110000011111111100
011111111001111111111110
011000000000001111000000
000000000000000000000000
(0's represent wall, 1's represent open areas)
The problem is that the algorithm can sometimes create a cave that has 2 non connected sections (as in the above example). I've written a function that gives me an array of arrays that contain all the x, y positions of the open spots for each area
My question is, given a number of lists that contain all of the x,y coordinates for each open area what is the fastest way to "connect" these area's be a corridor that is a minimum of 2 thickness wide.
(I'm writing this in javascript but even just pseudo code will help me out)
I've tried comparing the distances from every point in one area to every other area in another area, finding the two points that have the closest distance then cutting out a path from those 2 two points but this approach is way to slow I'm hoping there is another way.
Given two caves A and B, choose a point x in A and y in B (at random will do, the two closest or locally closest is better). Drill a corridor of thickness 2 between A and B (use Bresenham's algorithm). If you have multiple disconnected caves, do the above for each edge (A,B) of the minimal spanning tree of the graph of all the caves (edge weight is the length of the corridor you'll drill if you choose this edge).
Edit for the edit: to approximate the distance between two caves, you can use hill climbing. It will return the global minimum for convex caves in O(n) rather than the naive O(n2). For non-convex caves, do multiple iterations of hill climbing with initial guess chosen in random.
If you need the exactly minimal solution, you can consider first building the frontiers of your caves and then applying O(nm) algorithm. This will eliminate the need to compare distances between interior points of your caves. Then as soon as you know the distances between each pair of caves, you build the minimal spanning tree, then you drill your tunnels.
Since I don't know too much from your description, here are some hints I would consider:
How do you look for the pair of nearest points? Do you use a naive brute-force approach and thus obtain a run time of O(n*n)? Or are you using a more efficient variant taking O(n log n) time?
If you have obtained the closest points, I'd use a simple line-drawing algorithm.
Another approach might be that you generate a structure that definitely has only one single connected area. Therefore you could do the following: First you take a random cell (x,y) and set it to 1. Then, you traverse all it's neighbours and for each of them you randomly set it to 1 or leave it at 0. For each cell set to 1, you do the same, i.e. you traverse it's neighbours and set them randomly to 1 or 0. This guarantees that you won't have two separate areas.
An algorithm to ensure this could be the following (in python):
def setCell(x,y,A):
if x>=len(A) or y>=len(A[0]) or x<0 or y<0:
return
A[x][y] = 1
def getCell(x,y,A):
if x>=len(A) or y>=len(A[0]) or x<0 or y<0:
return 1
return A[x][y]
def generate(height, width):
A = [[0 for _ in xrange(width)] for _ in xrange(height)]
from random import randint
import Queue
(x,y) = (randint(0, height-1), randint(0, width-1))
setCell (x,y,A)
q = Queue.Queue()
q.put((x,y))
while not q.empty():
(x,y) = q.get()
for (nx, ny) in [(x+1,y), (x-1,y), (x,y+1), (x,y-1)]:
if randint(0,8)<=6:
if getCell(nx,ny,A)==0:
setCell(nx,ny,A)
if randint(0,2)<=1:
q.put((nx,ny))
return A
def printField(A):
for l in A:
for c in l:
print (" " if c==1 else "X"),
print ""
Then printField(generate(20,30)) does the job. Probably you'll have to adjust the parameters for random stuff so it fits your needs.

Click detection in a 2D isometric grid?

I've been doing web development for years now and I'm slowly getting myself involved with game development and for my current project I've got this isometric map, where I need to use an algorithm to detect which field is being clicked on. This is all in the browser with Javascript by the way.
The map
It looks like this and I've added some numbers to show you the structure of the fields (tiles) and their IDs. All the fields have a center point (array of x,y) which the four corners are based on when drawn.
As you can see it's not a diamond shape, but a zig-zag map and there's no angle (top-down view) which is why I can't find an answer myself considering that all articles and calculations are usually based on a diamond shape with an angle.
The numbers
It's a dynamic map and all sizes and numbers can be changed to generate a new map.
I know it isn't a lot of data, but the map is generated based on the map and field sizes.
- Map Size: x:800 y:400
- Field Size: 80x80 (between corners)
- Center position of all the fields (x,y)
The goal
To come up with an algorithm which tells the client (game) which field the mouse is located in at any given event (click, movement etc).
Disclaimer
I do want to mention that I've already come up with a working solution myself, however I'm 100% certain it could be written in a better way (my solution involves a lot of nested if-statements and loops), and that's why I'm asking here.
Here's an example of my solution where I basically find a square with corners in the nearest 4 known positions and then I get my result based on the smallest square between the 2 nearest fields. Does that make any sense?
Ask if I missed something.
Here's what I came up with,
function posInGrid(x, y, length) {
xFromColCenter = x % length - length / 2;
yFromRowCenter = y % length - length / 2;
col = (x - xFromColCenter) / length;
row = (y - yFromRowCenter) / length;
if (yFromRowCenter < xFromColCenter) {
if (yFromRowCenter < (-xFromColCenter))--row;
else++col;
} else if (yFromRowCenter > xFromColCenter) {
if (yFromRowCenter < (-xFromColCenter))--col;
else++row;
}
return "Col:"+col+", Row:"+row+", xFC:"+xFromColCenter+", yFC:"+yFromRowCenter;
}
X and Y are the coords in the image, and length is the spacing of the grid.
Right now it returns a string, just for testing.. result should be row and col, and those are the coordinates I chose: your tile 1 has coords (1,0) tile 2 is(3,0), tile 10 is (0,1), tile 11 is (2,1). You could convert my coordinates to your numbered tiles in a line or two.
And a JSFiddle for testing http://jsfiddle.net/NHV3y/
Cheers.
EDIT: changed the return statement, had some variables I used for debugging left in.
A pixel perfect way of hit detection I've used in the past (in OpenGL, but the concept stands here too) is an off screen rendering of the scene where the different objects are identified with different colors.
This approach requires double the memory and double the rendering but the hit detection of arbitrarily complex scenes is done with a simple color lookup.
Since you want to detect a cell in a grid there are probably more efficient solutions but I wanted to mention this one for it's simplicity and flexibility.
This has been solved before, let me consult my notes...
Here's a couple of good resources:
From Laserbrain Studios, The basics of isometric programming
Useful article in the thread posted here, in Java
Let me know if this helps, and good luck with your game!
This code calculates the position in the grid given the uneven spacing. Should be pretty fast; almost all operations are done mathematically, using just one loop. I'll ponder the other part of the problem later.
def cspot(x,y,length):
l=length
lp=length+1
vlist = [ (l*(k%2))+(lp*((k+1)%2)) for k in range(1,y+1) ]
vlist.append(1)
return x + sum(vlist)

board game win situation - searching algorithm

I'm looking for possibly efficient algorithm to detect "win" situation in a gomoku (five-in-a-row) game, played on a 19x19 board. Win situation happens when one of the players manages to get five and NO MORE than five "stones" in a row (horizontal, diagonal or vertical).
I have the following data easily accessible:
previous moves ("stones") of both players stored in a 2d array (can be also json notation object), with variables "B" and "W" to difference players from each other,
"coordinates" of the incoming move (move.x, move.y),
number of moves each player did
I'm doing it in javascript, but any solution that doesn't use low-level stuff like memory allocation nor higher-level (python) array operations would be good.
I've found similiar question ( Detect winning game in nought and crosses ), but solutions given there only refer to small boards (5x5 etc).
A simple to understand solution without excessive loops (only pseudocode provided, let me know if you need more explanation):
I assume your 2-d array runs like this:
board = [
[...],
[...],
[...],
...
];
I.e. the inner arrays represent the horizontal rows of the board.
I also assume that the array is populated by "b", "w", and "x", representing black pieces, white pieces, and empty squares, respectively.
My solution is somewhat divide-and-conquer, so I've divided it into the 3 cases below. Bear with me, it may seem more complex than simply running multiple nested loops at first, but the concept is easy to understand, read, and with the right approach, quite simple to code.
Horizontal lines
Let's first consider the case of detecting a win situation ONLY if the line is horizontal - this is the easiest. First, join a row into a single string, using something like board[0].join(""). Do this for each row. You end up with an array like this:
rows = [
"bxwwwbx...",
"xxxwbxx...",
"wwbbbbx...",
...
]
Now join THIS array, but inserting an "x" between elements to separate each row: rows.join("x").
Now you have one long string representing your board, and it's simply a matter of applying a regexp to find consecutive "w" or "b" of exactly 5 length: superString.test(/(b{5,5})|(w{5,5})/). If the test returns true you have a win situation. If not, let's move on to vertical lines.
Vertical lines
You want to reuse the above code, so create a function testRows for it. Testing for vertical lines is exactly the same process, but you want to transpose the board, so that rows become columns and columns become rows. Then you apply the same testRows function. Transposing can be done by copying values into a new 2-d array, or by writing a simple getCol function and using that within testRows.
Diagonal lines
Again, we want to reuse the `testRows' function. A diagonal such as this:
b x x x x
x b x x x
x x b x x
x x x b x
x x x x b
Can be converted to a vertical such as this:
b x x x x
b x x x
b x x
b x
b
By shifting row i by i positions. Now it's a matter of transposing and we are back at testing for horizontals. You'll need to do the same for diagonals that go the other way, but this time shift row i by length - 1 - i positions, or in your case, 18 - i positions.
Functional javascript
As a side note, my solution fits nicely with functional programming, which means that it can be quite easily coded if you have functional programming tools with you, though it's not necessary. I recommend using underscore.js as it's quite likely you'll need basic tools like map, reduce and filter in many different game algorithms. For example, my section on testing horizontal lines can be written in one line of javascript with the use of map:
_(board).map(function (row) {return row.join("")}).join("x").test(/(b{5,5})|(w{5,5})/);
Even though this is a really old question I want to provide my answer because I took a deeper look into this problem today and solved it in a much (much) more efficient way.
I'm using a bit board, which is used in most of the board games and engines (chess engines) due to the efficiency, to represent my field.
You can do everything you need in this game with bitwise operations.
A bit can just have 2 states (0 and 1) however what we need are 3 states e.g. p1, p2 or empty.
To solve this problem we're going to have 2 boards instead, one for each player.
Another problem is that Gomoku has a lot of fields (19x19) and there is no number type that has that many bits to represent the field.
We will use an array of numbers to represent each line and just use the first lsb 15bits of it.
Vertical rows
A simplified board of player 1 could look like this
000000
101100
001000
011000
000000
Lets say we want to detect 3 in a row. We take the first 3 rows(0-2) and took at them.
000000
001100
101000
With the & (AND) operator you can check if there is a 1 in every row.
var result = field[player][0] & field[player][1] & field[player][2];
In this case the result will be 0 which means no winner. Lets continue... The next step is to take rows 1-3
101100
001000
011000
Apply the AND again and that we will get is 001000. We don't have to care what number this is, just if it's 0 or not. (result != 0)
Horizontal rows
Ok now we can detect vertical rows. To detect the horizontal rows we need to save another 2 boards, again one for each player. But we need to invert x and y axis. Then we can do the same check again to detect horizontal lines. Your array would then be:
//[player][hORv][rows]
var field[2][2][19];
Diagonals :)
The trickiest part are the diagonals of course but with a simple trick you can do the same check as above. A simple board:
000000
010000
001000
000100
000000
Basically we do the same as above but before we do that we need to shift the rows. Lets say we're at row 1-3.
010000
001000
000100
The first row stays as it is. Then you shift the second row one to the left and the third 2 to the left.
var r0 = field[0][0][i];
var r1 = field[0][0][i+1] << 1;
var r2 = field[0][0][i+2] << 2;
What you will get is:
010000
010000
010000
Apply AND you can have your win detection. To get the other diagonal direction just do it again, but instead of shifting to the left <<, shift to the right >>
I hopes this helps someone.
untested:
int left = max(0, move.x-5), right = min(width-1, move.x+5), top = max(0, move.y-5), bottom = min(width-1, move.y+5);
// check the primary diagonal (top-left to bottom-right)
for (int x = left, y = top; x <= right && y <= bottom; x++, y++) {
for (int count = 0; x <= right && y <= bottom && stones[x][y] == lastPlayer; x++, y++, count++) {
if (count >= 5) return true;
}
}
// check the secondary diagonal (top-right to bottom-left)
// ...
// check the horizontal
// ...
// check the vertical
// ...
return false;
alternatively, if you don't like the nested loops (untested):
// check the primary diagonal (top-left to bottom-right)
int count = 0, maxCount = 0;
for (int x = left, y = top; x <= right && y <= bottom; x++, y++) {
if (count < 5) {
count = stones[x][y] == lastPlayer ? count + 1 : 0;
} else {
return true;
}
}

Spatial Data Structure for Games

I need to implement a spatial data structure to store rectangles then be able to find all rectangles that intersect a given rectangle. This will be implemented in JavaScript.
So far I am developing a Quad Tree to cut down the search space but because it is for a game, all objects that move will need to update its position in the tree. Back to square one.
Are there any data-structures or methods to help? It will need to process around 10,000 objects so brute force isn't good enough.
A hash table works fairly well as an approximate intersection test. Hash tables are used as part of a more sophisticated algorithm for detecting collisions in ODE.
Logically, this test divides the space into a regular grid. Each grid cell is labeled with a list of objects that intersect that cell. The grid is initialized by scanning all objects. I don't know javascript, so I'll use python-ish pseudocode.
for each ob in objects:
for each x in [floor(ob.x_min / grid_size) .. floor(ob.x_max / grid_size)]:
for each y in [floor(ob.y_min / grid_size) .. floor(ob.y_max / grid_size)]:
hashtable[hash(x, y)].append(ob)
To find collisions with a given object, look up near-collisions in the hash table and then apply an exact collision test to each one.
near_collisions = []
for each x in [floor(ob.x_min / grid_size) .. floor(ob.x_max / grid_size)]:
for each y in [floor(ob.y_min / grid_size) .. floor(ob.y_max / grid_size)]:
near_collisions = near_collisions ++ hashtable[hash(x, y)]
remove duplicates from near_collisions
for each ob2 in near_collisions:
if exact_collision_test(ob, ob2):
do_something
You can still use quadtree even if you have moving objects – just remove and reinsert an object every time it moves or every time it crosses region boundary.
But quadtrees aren't very good at storing rectangles and I would recommend using an R-tree instead.

Categories

Resources