Here is my approach using only the red and green channels of the image (using OpenCV, see my comments in the code for the explanation):
import cv2
import imageio
import numpy as np
# extract red and green channel from the image
r, g = cv2.split(imageio.imread('https://i.stack.imgur.com/bMSzZ.png'))[:2]
imageio.imsave('r-channel.png', r)
imageio.imsave('g-channel.png', g)
# white image as canvas for drawing contours
canvas = np.ones(r.shape, np.uint8) * 255
# find contours in the inverted green channel
# change [0] to [1] when using OpenCV 3, in which contours are returned secondly
contours = cv2.findContours(255 - g, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]
# filter out contours that are too large and have length 4 (rectangular)
contours = [
cnt for cnt in contours
if cv2.contourArea(cnt) <= 500 and len(cnt) == 4
]
# fill kept contours with black on the canvas
cv2.drawContours(canvas, contours, -1, 0, -1)
imageio.imsave('filtered-contours.png', canvas)
# combine kept contours with red channel using '&' to bring back the "AAA"
# use '|' with the green channel to remove contour edges around the "BBB"
result = canvas & r | g
imageio.imsave('result.png', result)
r-channel.png

g-channel.png

filtered-contours.png

result.png

Update
Here is a more generalisable solution based on another example image you provided in the chat:
import cv2
import numpy as np
img = cv2.imread('example.png')
result = np.ones(img.shape[:2], np.uint8) * 255
for channel in cv2.split(img):
canvas = np.ones(img.shape[:2], np.uint8) * 255
contours = cv2.findContours(255 - channel, cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)[0]
# size threshold may vary per image
contours = [cnt for cnt in contours if cv2.contourArea(cnt) <= 100]
cv2.drawContours(canvas, contours, -1, 0, -1)
result = result & (canvas | channel)
cv2.imwrite('result.png', result)
Here I no longer filter on contour length, as this causes problems when other characters are touching the rectangle. All channels of the image are used to make it compatible with different colours.