Python opencv realizes Meitu XiuXiu video editing effect [special effects]

preface

Recently, I learned some simple image geometric transformation and wanted to find something to practice. So I thought of Meitu XiuXiu on my mobile phone and found some special effects to imitate 😜

Of course, there is no gif image generated here, but the effect is displayed through imshow and waitKey, but the basic principle can be realized. It must not be difficult to find a library to generate gif again

In order to avoid too long, this article only discusses the special effect implementation of a single picture (the next article discusses the transition implementation of two pictures)

Here are two pictures used in the exercise


001.jpg

002.jpg

1, Card frame

Effect comparison


Meitu XiuXiu [card frame]

OpenCV implementation [card frame]

Realization idea

Simple timing map

Implementation code

import cv2
import numpy as np

'''Read in image'''
img = cv2.imread("001.jpg")
rows, cols = img.shape[:2]

'''Zoom original 80%'''
img = cv2.resize(img, (int(rows * 0.8), int(cols * 0.8)))
rows_new, cols_new = img.shape[:2]

'''Prepare a larger canvas'''
cav_np = np.zeros((rows, cols), np.uint8)
cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)

'''Offset preparation'''
dic = {
    0: (int(cols * 0.08), int(rows * 0.12)),
    1: (int(cols * 0.12), int(rows * 0.08)),
    2: (int(cols * 0.12), int(rows * 0.06)),
    3: (int(cols * 0.16), int(rows * 0.07)),
    4: (int(cols * 0.14), int(rows * 0.10)),
    5: (int(cols * 0.13), int(rows * 0.05)),
    6: (int(cols * 0.14), int(rows * 0.08)),
    7: (int(cols * 0.15), int(rows * 0.10))
}

'''Special effects display'''
for i in range(8):
    xs, ys = dic[i]
    xe, ye = (xs + rows_new, ys + cols_new)
    cav[xs: xe, ys: ye] = img
    cv2.imshow("show", cav)
    cv2.waitKey(500)

'''close window'''
cv2.waitKey(1000)
cv2.destroyAllWindows()

2, Vertical opening / horizontal opening

Effect comparison


Meitu XiuXiu [vertical opening]

OpenCV implementation [vertical opening]

Meitu XiuXiu [horizontal opening]

OpenCV realizes [horizontal opening]

Realization idea

Prepare the black canvas, control the time to map on the canvas, and control the speed to be slower and slower, that is, the loading amount is less and less
The requirements are as follows: stay 3 second within , 50 % β†’ 0 % , wrong Line nature reduce less ( More come More slow ) In 3 seconds, 50 \% → 0 \%, nonlinear reduction (slower and slower) Within 3 seconds, 50% → 0%, non-linearity decreases (more and more slowly)
Simple polynomial functions can be set y = 50 % 3 n ( 3 βˆ’ t ) n ( n β‰₯ 2 ) his in , { t Time between ( single position : second ) y from in between position Set towards upper , not plus load Department branch of high degree hundred branch than \Begin {aligned} & y = \ frac {50 \%} {3 ^ n} (3-T) ^ n \ Quad (n \ GEQ 2) \ \ \ \ & where, \ begin {cases} T & time (in seconds) \ \ Y & height percentage of unloaded part from the middle position \ end{cases} \end{aligned} y=3n50% (3 − t)n(n ≥ 2), where {ty time (in seconds) is the height percentage of the unloaded part from the middle position upward
Then you can know pt = ( 0.5 βˆ’ y ) β‹… height his in , pt surface show stay t Time moment , need want from in between towards upper square plus load of high degree \Begin {aligned} & \ text{pt} = (0.5 - y) \ cdot \ text {height} \ \ \ & where \ text{pt} represents the height that needs to be loaded from the middle up at time t \ end{aligned} pt=(0.5 − y) ⋅ height, where pt represents the height that needs to be loaded from the middle up at time t

Take the quintic function here( n = 5 n = 5 n=5), per 30 30 Load once every 30 milliseconds

Tips: tested, n β€Ύ \bm{\underline{n}} The larger the value of n, the faster the animation display (the earlier the full picture is loaded)

Implementation code

  • Vertical opening
    import cv2
    import numpy as np
    
    '''Read in image'''
    img = cv2.imread("001.jpg")
    rows, cols = img.shape[:2]
    
    '''Canvas preparation'''
    cav_np = np.zeros((rows, cols), np.uint8)
    cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)
    
    '''Special effects display'''
    load_f = 30
    n = 5
    half = int(rows / 2)
    xs1, xs2 = half, half
    xe1, xe2 = half, half
    for t in range(3000 // load_f):
        load_percent = 0.5 / (3 ** n) * ((3 - t * load_f / 1000) ** n)
        load_height = int((0.5 - load_percent) * rows)
        xe1, xe2 = half - load_height, half + load_height
        cav[xe1:xs1, :] = img[xe1:xs1, :]
        cav[xs2:xe2, :] = img[xs2:xe2, :]
        xs1, xs2 = xe1, xe2
        cv2.imshow("show", cav)
        cv2.waitKey(load_f)
    
    '''close window'''
    cv2.waitKey(1000)
    cv2.destroyAllWindows()
    
  • Horizontal opening
    import cv2
    import numpy as np
    
    '''Read in image'''
    img = cv2.imread("001.jpg")
    rows, cols = img.shape[:2]
    
    '''Canvas preparation'''
    cav_np = np.zeros((rows, cols), np.uint8)
    cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)
    
    '''Special effects display'''
    load_f = 30
    n = 5
    half = int(rows / 2)
    ys1, ys2 = half, half
    ye1, ye2 = half, half
    for t in range(3000 // load_f):
        load_percent = 0.5 / (3 ** n) * ((3 - t * load_f / 1000) ** n)
        load_height = int((0.5 - load_percent) * rows)
        ye1, ye2 = half - load_height, half + load_height
        cav[:, ye1:ys1] = img[:, ye1:ys1]
        cav[:, ys2:ye2] = img[:, ys2:ye2]
        ys1, ys2 = ye1, ye2
        cv2.imshow("show", cav)
        cv2.waitKey(load_f)
    
    '''close window'''
    cv2.waitKey(1000)
    cv2.destroyAllWindows()
    

3, Fade / fade

Effect comparison


Meitu XiuXiu [fading]

OpenCV implementation [fade]

Meitu XiuXiu [gradually showing]

OpenCV implementation [ fade ]

Realization idea

Prepare the image, control the time, change the image intensity (brightness), and control the speed faster and faster
The requirements are as follows: gradually latent : 100 % β†’ 0 % , reduce less gradually display : 0 % β†’ 100 % , increase long \Begin {aligned} & fade: 100 \% → 0 \%, decrease \ \ & fade: 0 \% → 100 \%, increase \ end{aligned} Fade: 100% → 0%, decrease: 0% → 100%, increase
Simple polynomial functions can be set gradually latent : y = 100 % βˆ’ 100 % 3 n t n ( n β‰₯ 1 ) gradually display : y = 100 % βˆ’ 100 % 3 n ( 3 βˆ’ t ) n ( n β‰₯ 1 ) his in , { t Time between ( single position : second ) y bright degree hundred branch than \Begin {aligned} & fade: y = 100 \% - \ frac {100 \%} {3 ^ n} T ^ n \ Quad (n \ GEQ 1) \ \ \ \ & fade: y = 100 \% - \ frac {100 \%} {3 ^ n} (3-T) ^ n \ Quad (n \ GEQ 1) \ \ \ \ & where, \ begin {cases} T & time (in seconds) \ \ Y & brightness percentage \ end{cases} \end{aligned} Fade out: y=100% − 3n100% tn(n ≥ 1) fade out: y=100% − 3n100% (3 − t)n(n ≥ 1) where, {ty time (unit: Second) brightness percentage
This side is gradually hidden n = 1 n = 1 n=1, gradual display n = 1.5 n = 1.5 n=1.5, total time 2 2 2 seconds per 40 40 Load once every 40 milliseconds

Tips: tested, n β€Ύ \bm{\underline{n}} The larger the value of n, the faster the animation will be displayed (therefore, the starting time of the animation can be set at about 40% of the time, skipping the slow growth stage of higher-order polynomials)

Implementation code

  • Fade
    import cv2
    import numpy as np
    
    '''Read in image'''
    img = cv2.imread("001.jpg")
    rows, cols = img.shape[:2]
    
    '''Special effects display'''
    load_f = 40
    n = 1
    time = 2
    for t in range(time * 1000 // load_f):
        sc = 1 - 1 / (time ** n) * (t * load_f / 1000) ** n
        img_show = cv2.multiply(img, (1, 1, 1, 1), scale=sc)
        cv2.imshow("show", img_show)
        cv2.waitKey(load_f)
    
    '''close window'''
    cv2.waitKey(500)
    cv2.destroyAllWindows()
    
  • Gradually show
    import cv2
    import numpy as np
    
    '''Read in image'''
    img = cv2.imread("001.jpg")
    rows, cols = img.shape[:2]
    
    '''Special effects display'''
    load_f = 40
    n = 1.5
    time = 2
    for t in range(time * 1000 // load_f):
        sc = 1 - 1 / (time ** n) * (time - t * load_f / 1000) ** n
        img_show = cv2.multiply(img, (1, 1, 1, 1), scale=sc)
        cv2.imshow("show", img_show)
        cv2.waitKey(load_f)
    
    '''close window'''
    cv2.waitKey(500)
    cv2.destroyAllWindows()
    

4, Push close / pull far

Effect comparison


Meitu XiuXiu [push closer]

OpenCV implementation [push closer]

Meitu XiuXiu [pull away]

OpenCV implementation [pull away]

Realization idea

Prepare the image and control the time to display the part of the image after resizing. The speed is getting slower and slower
The requirements are as follows: Left side PUSH near long degree : 0 % β†’ 20 % , wrong Line nature increase long ( More come More slow ) Left side PULL far long degree : 20 % β†’ 0 % , wrong Line nature reduce less ( More come More slow ) \Begin {aligned} & left push length: 0 \% → 20 \%, nonlinear growth (slower and slower) \ \ & left pull length: 20 \% → 0 \%, nonlinear decrease (slower and slower) \ \ \ end{aligned} Left push length: 0% → 20%, non-linear growth (slower and slower) left pull length: 20% → 0%, non-linear reduction (slower and slower)
Simple polynomial functions can be set PUSH near : y = 33 % βˆ’ 33 % 3 n ( 3 βˆ’ t ) n ( n β‰₯ 2 ) PULL far : y = 33 % 3 n ( 3 βˆ’ t ) n ( n β‰₯ 2 ) his in , { t Time between ( single position : second ) y Left side PUSH near / PULL far hundred branch than \Begin {aligned} & push close: y = 33 \% - \ frac {33 \%} {3 ^ n} (3-T) ^ n \ Quad (n \ GEQ 2) \ \ \ \ & pull away: y = \ frac {33 \%} {3 ^ n} (3 - t) ^ n \ Quad (n \ GEQ 2) \ \ \ \ & where, \ begin {cases} T & time (unit: seconds) \ \ Y & left push / pull away percentage \ end{cases} \end{aligned} Push in: y=33% − 3n33% (3 − t)n(n ≥ 2) pull away: y=3n33% (3 − t)n(n ≥ 2) where, {ty time (in seconds) push in / pull away percentage on the left
It's a little troublesome to find such a function relationship by ourselves, so we need to define a function, given a % β†’ b % mode = { faster Faster and faster slower More and more slowly \Color {#aa66ff} \ begin {aligned} & \ BM {a \% → B \%} \ \ \ & \ textbf {mode} = \ begin {cases} \ textbf {fast} & \ textbf {faster} \ \ \ \ textbf {slower} & \ textbf {slower} \ \ \ \ end{cases} \end{aligned} a% → b%mode = ⎩βŽͺ⎨βŽͺ⎧ fasterslower faster and slower
You can generate one based on the current time t \bm{t} Tcalculate the current arrival percentage c % \bm{c\%} Function of c%

After simple induction and calculation on the draft paper, the formula is as follows:
y = sgn ( a % βˆ’ b % ) β‹… Ξ΄ % ( time ) n β‹… ( time βˆ’ t ) n + b % mode = slower y = sgn ( b % βˆ’ a % ) β‹… Ξ΄ % ( time ) n β‹… t n + a % mode = faster Among them, Ξ΄ % = ∣ β€…β€Š a % βˆ’ b % β€…β€Š ∣ \color{#AA66FF} \begin{aligned} & \bm{y =} \textbf{sgn}\bm{(a \% - b \%) \cdot \frac{\delta \%}{(\textbf{time})^n} \cdot (\textbf{time} - t)^n + b \%} & \textbf{mode} = \textbf{slower} \ \ & \bm{y =} \textbf{sgn}\bm{(b \% - a \%) \cdot \frac{\delta \%}{(\textbf{time})^n} \cdot t^n + a \%} & \textbf{mode} = \textbf{faster} \ \ & \textbf {where,} \ BM {\ Delta \% = |; a \% - B \% \; |} \ end {aligned} ​y=sgn(a%−b%)⋅(time)n δ% ​⋅(time−t)n+b%y=sgn(b%−a%)⋅(time)n δ% ⋅ tn+a%, where, δ%= ∣a%−b%βˆ£β€‹mode=slowermode=faster​

Again faster \textbf{faster} Fast is the benchmark. To sum up, it is
If the mode is slow, swap a and b , order Β  β€…β€Š t Β  = Β  time Β  - Β  t y = sgn ( b % βˆ’ a % ) β‹… Ξ΄ % ( time ) n β‹… t n + a % \Color {#aa66ff} \ begin {aligned} & \ textbf {if \ text{mode} is \ text {lower}, swap} \ bm{a}\textbf {and} \ bm{b}\textbf {so that \; t = \ text {time} - t} \ \ \ & \ BM {y =} \ textbf {SGN} \ BM {(B \% - a \%) \ cdot \ frac {\ Delta \%} {(\ textbf {time}) ^ n} \ cdot T ^ n + a \%} \ \ \ end {aligned} If the mode is slow, exchange a and B to make   t  =  time  -  ty=sgn(b%−a%)⋅(time)n δ% ​⋅tn+a%​

The following is the code of the percentage polynomial calculation function generator:

def percent_func_gen(a, b, time, n, mode):
    """
    Higher order polynomial calculation function generator
    :param a: Starting percentage (e.g. 0).25)
    :param b: End percentage
    :param time: Animation duration
    :param n: Polynomial degree
    :param mode: faster(Faster and faster) slower((slower and slower)
    :return: Calculation function of arrival percentage at each time
    """
    if mode == "slower":
        a, b = b, a
    delta = abs(a - b)
    sgn = 1 if b - a > 0 else (-1 if b - a < 0 else 0)

    def percent_calc(ti):
        if mode == "slower":
            ti = time - ti
        return sgn * delta / (time ** n) * (ti ** n) + a

    return percent_calc

Push close here n = 4 n = 4 n=4. Pull in n = 3 n = 3 n=3. Total time 2 2 2 seconds per 40 40 Load once every 40 milliseconds

Implementation code

  • Push close
    import cv2
    import numpy as np
    
    
    def percent_func_gen(a, b, time, n, mode):
        """
        Higher order polynomial calculation function generator
        :param a: Starting percentage (e.g. 0).25)
        :param b: End percentage
        :param time: Animation duration
        :param n: Polynomial degree
        :param mode: faster(Faster and faster) slower((slower and slower)
        :return: Calculation function of arrival percentage at each time
        """
        if mode == "slower":
            a, b = b, a
        delta = abs(a - b)
        sgn = 1 if b - a > 0 else (-1 if b - a < 0 else 0)
    
        def percent_calc(ti):
            if mode == "slower":
                ti = time - ti
            return sgn * delta / (time ** n) * (ti ** n) + a
    
        return percent_calc
    
    
    '''Read in image'''
    img = cv2.imread("001.jpg")
    rows, cols = img.shape[:2]
    
    '''Special effects display'''
    load_f = 40
    tim = 2
    percent_func = percent_func_gen(a=0, b=0.2, time=tim, n=4, mode="slower")
    for t in range(tim * 1000 // load_f + 1):
        percent = percent_func(t * load_f / 1000)
        xs, xe = int(percent * rows), int((1 - percent) * rows)
        ys, ye = int(percent * cols), int((1 - percent) * cols)
        img_show = img[xs:xe, ys:ye]
        img_show = cv2.resize(img_show, (rows, cols))
        cv2.imshow("show", img_show)
        cv2.waitKey(load_f)
    
    '''close window'''
    cv2.waitKey(500)
    cv2.destroyAllWindows()
    
  • Pull away
    import cv2
    import numpy as np
    
    
    def percent_func_gen(a, b, time, n, mode):
        """
        Higher order polynomial calculation function generator
        :param a: Starting percentage (e.g. 0).25)
        :param b: End percentage
        :param time: Animation duration
        :param n: Polynomial degree
        :param mode: faster(Faster and faster) slower((slower and slower)
        :return: Calculation function of arrival percentage at each time
        """
        if mode == "slower":
            a, b = b, a
        delta = abs(a - b)
        sgn = 1 if b - a > 0 else (-1 if b - a < 0 else 0)
    
        def percent_calc(ti):
            if mode == "slower":
                ti = time - ti
            return sgn * delta / (time ** n) * (ti ** n) + a
    
        return percent_calc
    
    
    '''Read in image'''
    img = cv2.imread("001.jpg")
    rows, cols = img.shape[:2]
    
    '''Special effects display'''
    load_f = 40
    tim = 2
    percent_func = percent_func_gen(a=0.2, b=0, time=tim, n=3, mode="slower")
    for t in range(tim * 1000 // load_f + 1):
        percent = percent_func(t * load_f / 1000)
        xs, xe = int(percent * rows), int((1 - percent) * rows)
        ys, ye = int(percent * cols), int((1 - percent) * cols)
        img_show = img[xs:xe, ys:ye]
        img_show = cv2.resize(img_show, (rows, cols))
        cv2.imshow("show", img_show)
        cv2.waitKey(load_f)
    
    '''close window'''
    cv2.waitKey(500)
    cv2.destroyAllWindows()
    

5, Square opening

Effect comparison


Meitu XiuXiu [square opening]

OpenCV implementation [square opening]

Realization idea

Prepare the canvas and control the time to display the parts of the image of the corresponding size. The speed is getting faster and faster
The requirements are as follows: game Department just square shape of half wide degree : 0 % β†’ 50 % , wrong Line nature increase long ( More come More fast ) \Begin {aligned} & half width of local square: 0 \% → 50 \%, nonlinear growth (faster and faster) \ \ \ end{aligned} Half width of local square: 0% → 50%, nonlinear growth (faster and faster)

This way n = 5 n = 5 n=5, total time 1 1 1 second per 10 10 Load once every 10 milliseconds

Implementation code

import cv2
import numpy as np


def percent_func_gen(a, b, time, n, mode):
    """
    Higher order polynomial calculation function generator
    :param a: Starting percentage (e.g. 0).25)
    :param b: End percentage
    :param time: Animation duration
    :param n: Polynomial degree
    :param mode: faster(Faster and faster) slower((slower and slower)
    :return: Calculation function of arrival percentage at each time
    """
    if mode == "slower":
        a, b = b, a
    delta = abs(a - b)
    sgn = 1 if b - a > 0 else (-1 if b - a < 0 else 0)

    def percent_calc(ti):
        if mode == "slower":
            ti = time - ti
        return sgn * delta / (time ** n) * (ti ** n) + a

    return percent_calc


'''Read in image'''
img = cv2.imread("001.jpg")
rows, cols = img.shape[:2]

'''Canvas preparation'''
cav_np = np.zeros((rows, cols), np.uint8)
cav = cv2.cvtColor(cav_np, cv2.COLOR_GRAY2BGR)

'''Special effects display'''
load_f = 30
tim = 3
percent_func = percent_func_gen(a=0, b=0.5, time=tim, n=6, mode="faster")
rows_half = rows // 2
cols_half = cols // 2
for t in range(tim * 1000 // load_f + 1):
    percent = percent_func(t * load_f / 1000)
    width, height = int(percent * rows), int(percent * cols)
    xs, xe = rows_half-width, rows_half+width
    ys, ye = cols_half-height, cols_half+height
    cav[xs:xe, ys:ye] = img[xs:xe, ys:ye]
    cv2.imshow("show", cav)
    cv2.waitKey(load_f)

'''close window'''
cv2.waitKey(500)
cv2.destroyAllWindows()

6, Grayscale gradient

Effect comparison


Meitu XiuXiu [grayscale gradient]

OpenCV implementation [grayscale gradient]

Realization idea

Prepare the gray canvas, control the time and display the local color image of corresponding size at a uniform speed

Implementation code

import cv2
import numpy as np


def percent_func_gen(a, b, time, n, mode):
    """
    Higher order polynomial calculation function generator
    :param a: Starting percentage (e.g. 0).25)
    :param b: End percentage
    :param time: Animation duration
    :param n: Polynomial degree
    :param mode: faster(Faster and faster) slower((slower and slower)
    :return: Calculation function of arrival percentage at each time
    """
    if mode == "slower":
        a, b = b, a
    delta = abs(a - b)
    sgn = 1 if b - a > 0 else (-1 if b - a < 0 else 0)

    def percent_calc(ti):
        if mode == "slower":
            ti = time - ti
        return sgn * delta / (time ** n) * (ti ** n) + a

    return percent_calc


'''Read in image'''
img = cv2.imread("001.jpg")
rows, cols = img.shape[:2]

'''Grayscale preparation'''
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_gray_bgr = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)

'''Special effects display'''
load_f = 20
tim = 1
percent_func = percent_func_gen(a=0, b=1, time=tim, n=1, mode="slower")
ys, ye = 0, 0
for t in range(tim * 1000 // load_f + 1):
    percent = percent_func(t * load_f / 1000)
    width = int(percent * cols)
    ye = width
    img_gray_bgr[:, ys:ye] = img[:, ys:ye]
    ys = ye
    cv2.imshow("show", img_gray_bgr)
    cv2.waitKey(load_f)

'''close window'''
cv2.waitKey(500)
cv2.destroyAllWindows()

Tags: Python OpenCV

Posted on Wed, 29 Sep 2021 18:04:12 -0400 by badre