How to test for an image fully inside another?

BlitzPlus Forums/BlitzPlus Programming/How to test for an image fully inside another?

NetGamer(Posted 2005) [#1]
While I'm familiar (to some degree) with the imagescollide, imagesoverlap, imagerectoverlap, imagerectcollide functions, I'm lost as to how to determine if one image is fully inside another (where both have transparency around the outer portion).

For example, I can deal with two rectangles using their respective x,y,width,height. However, if the smaller object is not a simple rectangle, but rather a hexagon or circle image, I'm not sure how to proceed.

If the larger object is also not a simple rectangle, I'm further lost.

I'm trying to code picking up an irregularly shaped card (say a hexagon shaped card) with a number of circular tokens on it. I need to detect which tokens are fully on the hex shaped card.


sswift(Posted 2005) [#2]
Calculate the offset of the first image over the second, and then check each pixel underneath the first image to see if the pixel below it is solid or not. If any pixels are over transparent pixels in image 2, or any pixels are over areas not overed by image 2 at all, then image 1 is not completely inside image 2.

; Calculate offset of Image 1 over Image 2:
Xoff = I2x - I1x
YOff = I2y - I1y

;Now, for each pixel in image 1, add that offset to its ;location to determine its location in image 2.

LockBuffer ImageBuffer(Image1)
LockBuffer ImageBuffer(Image2)

Inside = True

For Y = 0 to ImageHeight(Image1)-1
   For X = 0 to ImageWidth(Image1)-1

      ; Calculate the pixel in image 2 this pixel in image 1 is above:
      X2 = X + XOff
      Y2 = Y + YOff

      ; If the pixel lies within image 2:
      If (X2 >= 0) AND (X2 < ImageWidth(Image2)) AND (Y2 >= 0) AND (Y2 < ImageHeight(Image2))

         ; Is this pixel of image1 opaque?
         If ReadPixelFast(Image1, X, Y) <> 0

            ; Is this pixel of image2 transparent?
            If ReadPixelFast(Image2, X2, Y2) = 0

              ; Pixel1 is outside Image2.  Exit both loops!
                Inside = False
                Y = ImageHeight(Image1)
                X = InageWidth(Image1)

            else
               ; There are pixels from both images at this location, and both are opaque.
            endif
         else
            ; This pixel of image 1 is transparent, so it doesn't matter what is beneath it.
         endif

      Else
         ; Pixel is outside Image2.  Exit both loops!
         Inside = False
         Y = ImageHeight(Image1)
         X = InageWidth(Image1)
      Endif
   next
next

UnlockBuffer ImageBuffer(Image1)
UnlockBuffer ImageBuffer(Image2)




Yan(Posted 2005) [#3]
Use ImagesCollide()...




Grey Alien(Posted 2005) [#4]
What about setting a centre point for both shapes and checking that without any graphic collision routines!


NetGamer(Posted 2005) [#5]
Grey,
If the underlying image is a closed filled rectangle, I can check to see if the outside edges of the top shape fall within those bounds. No problem.

something like
local x1, y1, w1, h1 ; upperleft corner x,y and width/height of first image
local x2,y2,w2,h2 ; upperleft corner x,y and width/height of second image

if (((x2>=x1) and (x2<=(x1+w1))) and ((y2>=y1)and(y2<=(y1+h1)))) ; upperleft corner of 2nd image is inside 1st image
    if ((((x2+w2)>=x1) and ((x2+w2)<=(x1+w1))) and (((y2+h2)>=y1)and((y2+h2)<=(y1+h1)))) ; lower right corner of 2nd image is inside 1st image
        return True ; 2nd image is inside 1st
    endif
endif



If the 2nd image is not a rectangle, but is a uniform shape (circle, rectangle, rhombus, hexagon, etc.) and the underlying 1st image is a rectangle, the same code applies.

When the underlying image is not a rectangle, it appears I have to start pixel checking.

If the 2nd image is a rectangle, I can just check the four corners.

sswift,
thanks for the code snippet - I'll have to walk through it before commenting.

Squatting Neville,
thanks for the code snippet - very nice demonstration. I'll have to walk through it more before figuring out which approach to take.

It appears at initial glance, that sswift's approach will also handle holes in the images while Squatting Neville is more straightforward (what I was expecting to see the response based on ).


sswift(Posted 2005) [#6]
Squatting's method is clever, I had to run it and click the left mouse button to figure out what he was doing.

And his method should handle holes in the image just line mine would.

His method requires you to build and maintain inverse mask images though.

My method is basically to replace the imagescollide function with my own which essentially does what the inverse mask method is doing.

His method might be faster, but might result in messier code since you'll have to construct that inverse mask every time you load a new image, maintain it and free it. You'd lose any speed benefit and then some if you built the inverse mask at runtime, as needed, I think.

Given that, I think my method is probably the better of the two, though the ideal would be for imagescollide to support a flag to invert the mask check.