This is the 13th day of my participation in the First Challenge 2022

This article is adapted from my wechat public number. The work I described is an interesting small project when I first learned programming. Although it has no gold content, it can be regarded as a brave attempt and interesting exploration of me as a beginner.

background

After intercepting my memorizing curve of words from an APP, I keenly discovered the mathematical law contained in it.

The peak is reached every six months, and the height of the peak is decreasing. In order to draw a line on the graph to fit the broken line, I opened MATLAB and a fierce operation, drew a sinusoidal function modulated by a decay exponential function. But the problem is, I don’t know how to paste these two pictures together, I need to pull the curve drawn by MATLAB out of the white background.

Considering how I used to swipe qr codes with Excel (not using Photoshop at the time), I felt I needed to evolve my image matting skills.

Solid color background matting

In principle, to extract a pattern from such a simple background is to check the color of each pixel, and if it is a background color, change the opacity to 0, otherwise keep it. So it’s very easy to do.

from PIL import Image

im = Image.open('SaoMaYouJingXi.jpg') # fetch image
im = im.convert('RGBA') # Convert to RGBA (RBG+ Transparency) format
pix = im.load()width = im.size[0]
height = im.size[1]

for x in range(width):
    for y in range(height):        
        r, g, b, a = pix[x, y]        
        if (r>100)&(g>100) :# If it's white
        a = 0 Change transparency to 0
        im.putpixel((x,y),(r,g,b,a)) Return four parameters to the pixel
        
im.save("SaoMaYouJingXi.PNG") # save

# Early things were written without even a sense of code specification
Copy the code

Small test:

Worthy of being accurate to pixel matting, zoom in to see so clean and quick.

Color changing background matting

However, it’s boring to extract images from a solid, simple background. Then I remembered the hand-drawn class emblem I used to pull out of the photo with Excel:

It took a lot of work, and the result was fine on a light background, but very ugly on a dark background. So, I decided to think of a way to re-cut the class badge.

First try

Since it is not a simple black or white background, there is no way to directly determine the RGB value range of the color, so we should first let the program to identify and remember the background colors, and then remove the pixels of these colors.

So we’re going to take two big steps:

  1. Manually sample from the background, save screenshots, import programs for its recognition, record;
  2. Import, process and export the entire image.

In this picture of the class emblem, I took a background sample near the four edges, and later added another one where it was not cut out to optimize the effect.

The next step is to get the computer to remember those colors.

As we know, the color of a pixel can be represented by three variables R(0-255), G(0-255), and B(0-255), and the total number of colors in a picture does not exceed 256^3.

Since we only care about the presence of a certain color, let’s create a 256x256x256 3d hash table.

Imagine a big cube with 256^3 cells in it. When the computer sees a certain color (m,n, P), it changes the 0 in the MTH row, NTH column, and PTH layer cell to a 1. By the time the computer has gone through all the pixels, all the ones in these cells have been filled in.

Here, in order to reduce the workload of the computer, we can simplify the three adjacent R/G/B values into one (for example, R=0,1,2→R’=0, R=3,4,5→R’=1), compress the 256x256x256 cube to 1/3 of its length, width and height, and reduce the size of the list to 1/27 of its original size.

matrix=[]
for i in range(85):
    matrix.append([])
    for j in range(85):
        matrix[i].append([])
        for k in range(85):
            matrix[i][j].append(0)
Copy the code

Then we leave the big box alone and let the computer check the second sample… By the time all the samples have been looked at, the box is filled in. At this point, most of the colors in the background have already been marked.

We define this check process as learn:

def learn(str) :
    im = Image.open(str)
    pix = im.load()
    width = im.size[0]
    height = im.size[1]
    for x in range(width):
        for y in range(height):
            r, g, b = pix[x, y]
            matrix[r][g][b]=1
Copy the code

In this case, let the program learn five samples of the background, and then execute the matting main program, save the picture.

Let’s look at the effect:

Disappointed, very disappointed. No matter how much I try to fill it in, add new context to learn, there’s still a lot of residue.

But that’s okay. We can be a little more vague. I’d rather miss a thousand than miss one.

Second attempt

Next, we add a fuzzy degree is dim, mean in the cutout judgment conditions, as long as the point of RGB coordinates appears near the marked coordinate, all three components in a marked point coordinates component plus or minus within the scope of the dim, the point of RGB coordinates in a marked point centered within the cube, the length is 2 * dim, We just cut it out.

The specific operation is not described here. As I increased dim, the residual area did get smaller and smaller, but the results were always disappointing.

Third attempt

So, no longer content with the little cube level of ambiguity, I decided to go big and be radical.

This time, I’m going to calculate the maximum and minimum values of R, G, and B for all pixels in the background, and then cut out all pixels with R, G, and B below the maximum and above the minimum (including the maximum).

In order to judge the feasibility of the scheme, I expanded the picture information by color and presented it in the coordinate system.

Here, X, Y and Z axes are the RGB values after compression respectively, and the range is integers in [0,85].

The color of each point is the color of the RGB value corresponding to its coordinates.

The information of the fourth dimension can be described by introducing transparency in the three dimensional coordinate system. We choose the number of pixels at this coordinate (that is, how many points in the original image have the same color) as the independent variable of transparency.

To control the dependent variable, which is transparency in the range of [0,1], we need to know how many pixels are the same color at most, using this maximum as the denominator.

At the same time, in order to avoid that the maximum value is too large, leading to very high transparency of most points (the closer the transparency is to 0, the higher is denoted), we change the mapping and take the square root of the relative transparency obtained by the ratio four times.

Finally, the picture we drew looks like this:

The more opaque the dot, the more pixels the color has.

Let’s go back to matting.

Analyzing the diagram we just drew with some effort, we find that the three primary colors are relatively well defined. If you don’t believe me, I can find a picture to expand it out for you:

Let’s look at the maximum and minimum values of R, G, and B for all the colors in the background sample.

And this is actually pretty much what you would expect, because as you can see from that frame, the colors that are close to the background are concentrated in places where R, G, and B are very large.

Let’s cut out the points R, G, and B in the corresponding interval and see what happens:

Opponents!

It’s perfect. Although I don’t actually agree with this principle, it’s essentially reckless behavior. But I have to say, the effect is really quite good.

Compare Excel matting, Learn matting and Mang matting:

It’s a piece of increasingly revolutionary music!

conclusion

At this point, I’ve accomplished my initial goal, and I’ve accumulated an extremely rudimentary, yet plausible, image matting solution.

In my opinion, the appeal of code matting lies not only in its pixel-down precision, but also in its flexibility to customize your needs as you wish, and the ease with which you can automatically output results by changing one or two parameters and clicking compile and run.

In addition, I also added some small features that are equally useless, such as mosaics:

Whether it is matting or coding, logic is not difficult to understand, the code is not difficult to achieve. In everyday life, there are times when professional tools such as PhotoShop are simply not at hand for simple tasks. Instead of installing Ps at this time, it is better to write a program, according to their own needs to code the implementation of functions, seemingly troublesome, but in fact it is a shortcut.