Comparing two bitmaps against each other for match

2019-07-28 23:49发布

问题:

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.

回答1:

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.



回答2:

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.



回答3:

For the actual comparison, there's BitmapData.compare which returns the number 0 if the BitmapData objects are equivalent.