I want to subtract one image from the other using the first one's alpha channel.
The problem is really hard for me to explain by words, so please bear with me and my art.
Imagine that I have the following image. Let's call it image "A":
I also have another one, image "B":
B is an image of a terrifyingly complex shape. It also has some transparency, as depicted by the checkered background. Now, imagine that after I place B on top of A, I get the following:
Here's the problem; I want to get the following output:
What's happening here is that after placing B on top of A, I want to preserve the area form image A where it intersects with image B's INNER transparent area, but remove parts of A where it intersects with B's OUTER transparent area. Also, B's RGB must be preserved.
How can I achieve this in python?
So as outlined in the comments, you can do this in 2 steps
You can find the "outer part" of B (ie. the background) as opposed to other transparent areas in B by using the cv.connectedComponents()
function (documentation here).
transparent_areas = B[:, :, 3] == 0 # mask of B outlining transparent areas. replace "== 0" with a threshold if those areas aren't completely transparent
n_components, transparent_connected_components = cv2.connectedComponents(transparent_areas.astype(np.uint8))
No we have the 2 connected components of the transparent area:
The non-transparent parts are always going to be labeled 0.
We just have to find which one(s) is/are the outer one(s) (here there is only one, but in a more complicated case, there could be several.)
That is simple: a connected component is a border one iff it contains a pixel at the border. So we just have to check which connected components the border pixels are in:
border_connected_components = np.concat([transparent_connected_components[0, :],
transparent_connected_components[-1, :] ,
transparent_connected_components[:, 0],
transparent_connected_components[:, -1]])
border_connected_components = np.unique(border_connected_components)
# don't forget to remove 0 which represents non-transparent pixels
border_connected_components = border_connected_components[border_connected_components!=0]
Now we only have to set the border connected components to white
B[np.isin(transparent_connected_components, border_connected_components)] = (255, 255, 255, 255)
And to add them as you usually would