Basically, I want to get the most common ARGB value that appears in a BitmapData. That is, I want to know which exact pixel colour is the most abundant in the image. I tried going through every pixel of the image and counting whenever a colour that already exists comes up, but that's way too slow, even with relatively small images. Does anybody know a faster method for this, maybe using the BitmapData.histogram() function or something?
Ideally the process should be near instantaneous for images around at least 1000x1000 pixels.
Run through bitmapData.getVector() with a Dictionary to hold numbers, then sort that Dictionary's key-value pairs by value and get the key of maximum.
var v:Vector.<uint>=yourBitmapData.getVector(yourBitmapData.rect);
var d:Dictionary=new Dictionary();
for (var i:int=v.length-1; i>=0;i--) {
if (d[v[i]]) d[v[i]]++; else d[v[i]]=1;
}
var maxkey:String=v[0].toString();
var maxval:int=0;
for (var k:String in d) {
if (d[k]>maxval) {
maxval=d[k];
maxkey=k;
}
}
return parseInt(maxkey); // or just maxkey
I haven't worked with shaders at all, but I think you might be able to get faster results. Looping through pixels is faster at the shader level.
I'd try by creating essentially the same loop in the shader, and paint the entire resulting bitmap with the most used colour and sample that (unless you can get a variable directly out of the shader)
this should be significantly faster
Related
I'm working on a simple image crop where the user draws a line with the mouse around an area that they want to keep. When they confirm, the rest of the image will be cropped out. Here's how I'm currently handling said cropping:
var data = c.getImageData(0,0,canvas.width,canvas.height);
for (var x = 0; x < data.width; x++) {
for (var y = 0; y < data.height; y++) {
if (!c.isPointInPath(x,y)) {
var n = x + (data.width * y);
var index = n*4;
data.data[index+3] = 0;
}
}
}
However, this can bog down really quickly. The less of the image you try to retain, the faster it goes, but even saving 30% of the image (canvas is 800x800) causes it to hang for several seconds. Is there a faster way to go about this?
I don't really understand why you are diving into pixel details to manipulate your cropping image functionality. It's understandable as bigger the image is get as more time is needed for cropping out the rest of the image, because practically with iterating over a two dimensional array of pixels the processing time needed for the operation is exponentially increasing with the increasing in size of the pixels map.
So my suggestion would be to try to remake the function without to even touch the getImageData and putImageData function. It's useless. I would make in the following way:
Obtain the pixel coordinates at the mouse down.
Create an event listener for the mouse move.
Create a semi-transparent image over the original image and use the fillRect function to draw into the created canvas.
Create an event listener for mouse up.
Obtain the pixel coordinates at the mouse up.
Calculate the coordinates of the resulting square.
Draw the resulting image into the canvas using as parameters the square coordinates.
As a final step draw the content of the canvas to an image.
This way you will save a lot of overhead on image cropping processing.
Here is a script for your reference: https://github.com/codepo8/canvascropper/blob/master/canvascrop.js
There is no real way to speed it up when you have to use a user defined shape, but the bogging down can be handled with a worker.
Some ideas:
Restrict getImageData to the bounding box of the polygon the user draws.
Put data.height, data.width etc. used inside the loop in a variable.
Maybe you can split up inside/outside tests and setting the imagedata alpha value.
Maybe even draw the polygon to a black and white imagedata object, then get the difference between the two?
Can you share the isPointInPath(x,y) function?
Let's say I have this glutIdleFunc going in the background of an OpenGL scene containing a little creature with multiple, radially arranged legs that "pulsate":
void PulsateLegs(void)
{
lowerLegsRot = (lowerLegsRot + 1)%360;
glutPostRedisplay();
}
...where the lowerLegsRot value is used like this in the display function:
glRotatef((GLfloat)lowerLegsRot, 1.0, 0.0, 0.0);
It's hard to visualize without seeing what the little fellow actually looks like, but it's clear that this function is making the legs spin all the way around repeatedly. I want to limit this spin to a certain range (say, -15 to 50 degrees), and, furthermore, to make the legs go back and forth within the range, like a pendulum.
Since I'm going for a 65 degree swath, I tried just changing "%360" to "%65" as a first step. But this made the legs go way too fast, and I cannot use a lower increment value if I want to use modulus, which only works on ints.
Is there another way to achieve the desired first-step behavior? More importantly, how can I make the legs go back and forth? It's kind of hard to conceptualize with a function that is getting called multiple times (vs. just using a loop structure that takes care of everything, which I tried before I realized this!)
and I cannot use a lower increment value if I want to use modulus, which only works on ints.
The % operator is broken anyway. You should not use integers, but floats, and use the fmod (double) or fmodf (float) function.
I am making an achtung die kurve-like game in AS3.0. So far I've done the movements of the 4 different players, and it works alright.
I am now to make collision detection, in order to test if a 'worm'-so to speak, is colliding with eachother or its own tail.
As I understand it, if I use hitTestObject(); it will use the registration area of the whole object, which would be a huge problem, seeing since this registration makes a 4-sided registration that contains all of the object. So if this is used, it will 'collide' just by entering this rectangle instead of hitting the actual worm. Is this correctly understood?
I've been looking through different methods of collision detection, and can't seem to find an optimal one for my project.
My thought were to check if the 'worms' are drawing their new sprites on a white background. if they aren't, then it must have hit something.
You can see how I used my code here: code in .as format linked to an .fla file
Sorry for my ill-formulated question, hope it makes somewhat sense.
Any help is greatly appreciated!!
Best regards - Jesper
Try this function if you want a Pixel Perfect Collision Detection with efficient CPU usage:
trace("Collided: " + (areaOfCollision(mc1, mc2) != null));
trace("Where: " + areaOfCollision(mc1, mc2));
function areaOfCollision(object1:DisplayObject, object2:DisplayObject, tolerance:int = 255):Rectangle {
if (object1.hitTestObject(object2)) {
var limits1:Rectangle = object1.getBounds(object1.parent);
var limits2:Rectangle = object2.getBounds(object2.parent);
var limits:Rectangle = limits1.intersection(limits2);
limits.x = Math.floor(limits.x);
limits.y = Math.floor(limits.y);
limits.width = Math.ceil(limits.width);
limits.height = Math.ceil(limits.height);
if (limits.width < 1 || limits.height < 1) return null;
var image:BitmapData = new BitmapData(limits.width, limits.height, false);
var matrix:Matrix = object1.transform.concatenatedMatrix;
matrix.translate(-limits.left, -limits.top);
image.draw(object1, matrix, new ColorTransform(1, 1, 1, 1, 255, -255, -255, tolerance));
matrix = object2.transform.concatenatedMatrix;
matrix.translate(-limits.left, -limits.top);
image.draw(object2, matrix, new ColorTransform(1, 1, 1, 1, 255, 255, 255, tolerance), BlendMode.DIFFERENCE);
var intersection:Rectangle = image.getColorBoundsRect(0xFFFFFFFF, 0xFF00FFFF);
if (intersection.width == 0) return null;
intersection.offset(limits.left, limits.top);
return intersection;
}
return null;
}
After a successful preliminary hitTestObject(), this function backgroundly takes a snapshot from the shapes of both objects painted with different colors each, then overlays them intersecting the colors on a new one, returning the Rectangle of the resulting shape. So cool.
To learn more about Pixel Perfect Collision Detection you can google Collision Detection followed by one of these names: "The ActionScript Man", "Troy Gilbert", "Boulevart (wim)", "Grant Skinner (gSkinner)" or "Senocular". Those guys are awesome AS3 references by the way.
The problem you discribe is a very common problem for collission detection because the object has a set width and height and therefor defines a rectangle as the object.
There is a solution however to make a colission detection system on pixel level I have found this on the official site and this made me able to make collission detection for bitmaps on pixel level.
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d55.html
hope it helps you out in the same way.
Looking at the screenshots of that game, I think the best model would be to describe each worm as a chain of circles. Then divide the world/level in a grid with cells somewhat larger than the circle radii.
The collision check would then be:
clear grid
place each circle into the 1 or more grid cells it falls in
iterate over all cells, for each cell:
for each pair of circles (partially) in this cell, check if they intersect. If they do; collision.
Note that this may result in more than 1 collision occurrence between circle A and B, so you'd also need to check that to avoid duplicates.
Step 1 and 2 can be optimized by not clearing the grid, and instead of step 2, updating each circle's cell after it moves. If you size your cells like 5x the size of a circle, a circle can stay in the same cell for a few frames, avoiding excessive add/remove operations.
I'm doing something similar in a project of mine right now, except with space ships! My grid cells are currently 256x256 (too big for your project I think) and my units have radii of about 20.
I'm trying to position an image on top of another image based upon the make-up of the smaller image. The smaller image is a cut-out of a larger image and I need it to be positioned exactly on the larger image to make it look like a single image, but allow for separate filters and alphas to be applied. As the images are not simple rectangles or circles, but complex satellite images, I cannot simply redraw them in code. I have quite a few images and therefore do not feel like manually finding the position of each image every and hard setting them manually in actionscript. Is there any way for me to sample a small 5-10 sq. pixel area against the larger image and set the x and y values of the smaller image if a perfect match is found? All the images are in an array and iterating through them has already been set, I just need a way to sample and match pixels. My first guess was to loop the images pixel by pixel right and down, covering the whole bitmap and moving to the next child in the array once a match was found, leaving the matched child where it was when the perfect match was found.
I hope I understood your question correctly.
There may be an option that uses copypixels to achieve what you want. You can use the bitmapdata.rect value to determine the size of the sample you want, and loop through the bigger bitmap using thet rectangle and a moving point. Let's see if I can code this out...
function findBitmapInBitmap(tinyimg:BitmapData, largeimg:BitmapData):Point {
var rect:Rectangle = tinyimg.rect;
var xbound:uint = largeimg.rect.width;
var ybound:uint = largeimg.rect.height;
var imgtest:BitmapData = new BitmapData(tinyimg.rect.width, tinyimg.rect.height);
for (var ypos:uint = 0, y <= ybound, y++) {
for (var xpos:uint = 0, x <= xbound, x++) {
imgtest.copyPixels(largeimg, rect, new Point(xpos, ypos);
if (imgtest.compare(tinyimg) == 0) return new Point(xpos, ypos);
}
}
return new Point(-1,-1); // Dummy value, indicating no match.
}
Something along those lines should work - I'm sure there's room for code elegance and possible optimization. However, it seems like something like this method would be very slow, since you'd have to check each pixel for a match.
There is a better way. Split your big image into layers, and use the blitting technique to composite them at runtime. In your case, you could create a ground texture without satellites, and then create the satellites separately, and use the copyPixels method to place them whereever you want. Google "blitting in as3" to find some good tutorials. I'm currently working on a game project that uses this technique and it's a very good method.
Good luck!
Edit: Forgot to code in a default return statement. Using this method, you'd have to return an invalid point (like (-1,-1)) and check for it outside the function. Alternatively, you could just copy your small bitmap to the big one within the function, which would be much more logical, but I don't know your requirements.
You need to find pixel sequence in the big image. BitmapData.getPixel gives you pixel value. So get first pixel from small image, find it in big image, then continue comparing until you find full match. If you have trouble to code that, feel free to ask.
For the actual comparison, there's BitmapData.compare which returns the number 0 if the BitmapData objects are equivalent.
This is a very general question that's not related to a specific language. I'm having this array of int's:
int[100][100] map;
This contains just tile numbers, and is rendered as 256x256 tiles. So it's basically just a tile map or whatever it should be called. Thing is I want to be able to write anything to the map, anywhere, and it should stay there. For example be able to paint on stuff on the ground such as grass, flowers, stones and other stuff making the terrain more varied without having to render each of these sprites a huge number of times every time it renders. But making each tile contain it's own texture to write to would be terribly memory consuming at that would be 256x256x100x100 = 655360000 pixels to store. Would'nt that be like gigabytes of data or something!?
Does anyone know of a good general sulotion to make what I'm trying to do without killing too much memory?
If someone wonders I'm using C++ with HGE (Haaf's Game Engine).
EDIT: I've choosen to limit the amount of stuff on screen so that it can render. But look here so maybe you'll understand what I try to achieve:
Link to image because I'm not allowed to use image tags :(
If it's just tile based then you only store one instance of each unique tile and each unique "overlay" (flower, rock, etc.). You reference it by id or memory location as you have been doing.
You'd simply store a location (tile number and location on tile) and a reference to an overlay to "paint" it without consuming a lot of memory.
Also, I'm sure you know this but you only render what's on screen. So memory usage is pretty much constant once everything is loaded up.
I'm not exactly sure what you are trying to do, but you should probably have the tiles in separate layers. So say that for each "tile" you have a list of textures ordered bottom-up that you blend together, that way you only store the tile indexes.
Instead of storing just the tile number, store the overlay number and offset position also.
struct map_zone {
int tile; // tile number
int overlay; // overlay number (flower, rock, etc). In most cases will be zero
int overlay_offset_x; // draw overlay at X pixels across from left
int overlay_offset_y; // draw overlay at Y pixels down from top
}
map_zone[100][100] map;
And for rendering:
int x, y;
for(y = 0; y < 100; ++y) {
for(x = 0; x < 100; ++x) {
render_tile(map[y][x].tile)
render_overlay(map[y][x].overlay, map[y][x].overlay_offset_x, map[y][x].overlay_offset_y);
}
}
It's arguably faster to store the overlays and offsets in separate arrays from the tiles, but having each area on the map self-contained like this is easier to understand.
you have to use alpha maps..
you are going to paint a texture 256x256 which maps your whole terrain. for each channel r,g,b,a you will tile your terrain with your another texture..
r = sand.jpg
g = grass.jpg
b = water.jpg
a = soil.jpg
in shader, you will check the color of alpha map and paint with these textures..
i am doing such a thing now and i did like that