python remove boxes from image

I’m doing image annotation recently, and the following picture will appear, and the borders need to be removed.
original image

1. Idea

  1. Manually mark the range P of the picture frame, and use the marking tool to draw a point A on the picture frame.
  2. Get the coordinates and color of point A. Within the range P, replace the color of each point x that is similar to the color of point A with the average color of several points within the range above and below (or left and right) of point x. But for the edge part, there may be problems as shown in the figure below:
    There is a problem with the border
  3. Perform additional processing on the edge part Q of the border. The color of the border may be quite different from the color of point A, so other methods need to be used for processing. I use the outlier detection algorithm because some residual points in Q that were not removed in step 2 will be quite different from the original image. Combining the frequency information can filter out these points and get the following effect:

2. Code implementation

  1. Guide package and necessary parameters and models:
from PIL import Image
import numpy as np
from sklearn.ensemble import IsolationForest
from collections import Counter

# Used to determine rgb similarity, it can be smaller
threshold=15
threshold_border=15

# The sampling radius can be set smaller and can be set according to the thickness of the border.
redius=20
redius_border=20

# Parameters that need to be adjusted to process the border
step_add=37
step_max=2000
step=0
all_outliers=[]
top_outlier_num=10

#Create Isolation Forest model
model = IsolationForest(contamination=0.05) # Set the proportion of outliers
  1. Helper function
#Determine whether the colors are similar
def my_similar(a,b):
    if sum([abs(x-y) for (x,y) in zip(list(a),list(b))])/3<threhold:
        return True
    return False

# Determine whether the colors are similar
def my_similar_border(a,b_s):
    for b in b_s:
        if sum([abs(x-y) for (x,y) in zip(list(a),list(b)[0])])/3<threhold_border:
            return True
    return False

# Get the outlier value, used to process the edge Q of the border
def get_outlier(tmp,model):
    normal_point=[]
    unnormal_point=[]
    # Pass data to the model for training
    model.fit(tmp)

    # Get the prediction label of each data point, -1 represents an abnormal point, 1 represents a normal point
    labels = model.predict(tmp)

    # Print labels for each data point
    for i, label in enumerate(labels):
        if label == -1:
            unnormal_point.append(tmp[i])
        if label==1:
            normal_point.append(tmp[i])
    return normal_point,unnormal_point

# Get neighbor nodes in the horizontal or disposition direction for color replacement
def get_right_neighborhood(target_color,neighborhood_x,neighborhood_y):
    diff_x=0
    diff_y=0
    
    for neighborhood in neighborhood_x:
        diff_x + =abs(sum([x-y for x,y in zip(list(neighborhood),list(target_color))])/3)
    for neighborhood in neighborhood_y:
        diff_y + =abs(sum([x-y for x,y in zip(list(neighborhood),list(target_color))])/3)
    if diff_x>diff_y:
        return neighborhood_x,1
    return neighborhood_y,2
  1. Main function and necessary preparation data
############################################## ########################################
############################Start manually specifying area P and point A############ ####################
###############################Corresponds to "Ideas" Part 1########### ##########################
################################################ #####################################

# Use manual or labeling tools such as labelimg,
# Determine area "P" in part 1 of "Idea"
# Manually select the approximate position of the frame, which needs to be wrapped
x_1=1427
y_1=723
x_2=2061
y_2=1363

# Use manual or labeling tools such as labelimg,
# Determine point "A" in part 1 of "Idea"
x = 1495 #x coordinate of the target pixel
y = 1294 #y coordinate of the target pixel

# Main function
def replace_color_around_point(image_path, x, y, radius=redius):
    
    # Number of sampling steps
    step=0
    
    # Open image
    image = Image.open(image_path)
    pixels = image.load()

    # Get the width and height of the image
    width, height = image.size

    ################################################ #####################################
    ############################Start processing the internal nodes of the border############## ##################
    ################################Corresponds to Part 2 of "Ideas"########### ##########################
    ################################################ #####################################
    # Get the color of the target pixel
    target_color = pixels[x, y]
    # Loop through each pixel in the image
    for i in range(x_1,x_2):
        for j in range(y_1,y_2):
            # If the pixel color is the same as the target color, replace it with the average color of the surrounding area
            if my_similar(pixels[i, j],target_color):
                # Calculate the color average of the surrounding horizontal and vertical areas
                neighborhood_x = []
                neighborhood_y=[]
                
                for m in range(i - redius, i + radius + 1):
                        if 0 <= m < width:
                            neighborhood_x.append(pixels[m, j])
                            
                for n in range(j - redius, j + radius + 1):
                        if 0 <= n < height:
                            neighborhood_y.append(pixels[i, n])
                            
                neighborhood,direction=get_right_neighborhood(target_color,neighborhood_x,neighborhood_y)
                neighborhood=[n for n in neighborhood if not my_similar(n,target_color)]
                neighborhood = np.array(neighborhood)
                average_color=tuple(np.mean(neighborhood, axis=0, dtype=int))
                average_color_part_1 = tuple(np.mean(neighborhood[0:int(len(neighborhood)/2)], axis=0, dtype=int))
                average_color_part_2 = tuple(np.mean(neighborhood[int(len(neighborhood)/2) + 1:], axis=0, dtype=int))
                
                # Replace pixel color
                pixels[i, j] = average_color
                
                # If it is horizontal direction
                if direction==1:
                    for m in range(i - int(redius_border/3), i):
                        if 0 <= m < width:
                                pixels[m,j]=average_color_part_1

                    for m in range(i, i + int(redius_border/3) + 1):
                        if 0 <= m < width:
                                pixels[m,j]=average_color_part_2
                
                # If it is vertical direction
                if direction==2:
                    for n in range(j - int(redius_border/3), j):
                        if 0 <= n < height:
                                pixels[i,n]=average_color_part_1

                    for n in range(j ,j + int(redius_border/3) + 1):
                        if 0 <= n < height:
                                pixels[i,n]=average_color_part_2
                
                step + =1
                
                if step%step_add==0 and step<step_max:
                    normal_point,unnormal_point=get_outlier(neighborhood,model)
                    unnormal_point=[tuple(x) for x in unnormal_point]
                    all_outliers.extend(unnormal_point)

    ################################################ #####################################
    ############################Start processing the edge nodes of the border############## ##################
    ###############################corresponds to "Ideas" Part 2########### ##########################
    ################################################ #####################################

    # Use Counter to count the number of occurrences of triples
    all_outlier_counts = Counter(all_outliers)

    # Get the ten triplets that appear most often and use them to remove borders
    top_outliers = all_outlier_counts.most_common(top_outlier_num)
    
    # Loop through each pixel in the image
    for i in range(x_1,x_2):
        for j in range(y_1,y_2):
            
            # If the color of this point is similar to that of the abnormal point, replace it
            if my_similar_border(pixels[i, j] ,top_outliers):
                # Calculate the color average of the surrounding horizontal and vertical areas
                neighborhood_x = []
                neighborhood_y=[]
                
                for m in range(i - int(radius/3), i + int(radius/3) + 1):
                        if 0 <= m < width:
                            neighborhood_x.append(pixels[m, j])
                            
                for n in range(j - int(radius/3), j + int(radius/3) + 1):
                        if 0 <= n < height:
                            neighborhood_y.append(pixels[i, n])
                            
                neighborhood,direction=get_right_neighborhood(target_color,neighborhood_x,neighborhood_y)
                neighborhood=[n for n in neighborhood if not n in top_outliers]
                neighborhood = np.array(neighborhood)
                average_color=tuple(np.mean(neighborhood, axis=0, dtype=int))
                
                # Replace pixel color
                pixels[i, j] = average_color
                                               
    # Save the modified image
    image.save(r"../data/bbb.jpg")
  1. transfer
image_path = r"../data/aaa.jpg" # Replace with your input image path
replace_color_around_point(image_path, x, y)

3.Existing problems

  1. When doing color replacement, only the average is used (average_color related content in the code), maybe other linear interpolation algorithms can be used.
  2. The parameters need to be carefully adjusted, otherwise the image in the frame may have the following “burr phenomenon”, and the “frame” cannot be completely removed:
    Parameter adjustment is not very good
    After adjusting the threshold parameter to a smaller value, the glitches disappear. Other parameters can also be adjusted.