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 & y = \ frac (3-T) ^ n \ Quad (n \ GEQ 2) \ \ \ \ & where, \ begin T & time (in seconds) \ \ Y & height percentage of unloaded part from the middle position \ end \end y=3n50% (3 − t)n(n ≥ 2), where & \ text = (0.5 - y) \ cdot \ text \ \ \ & where \ text represents the height that needs to be loaded from the middle up at time t \ end 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} 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()
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 & fade: 100 \% → 0 \%, decrease \ \ & fade: 0 \% → 100 \%, increase \ end 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 & fade: y = 100 \% - \ frac T ^ n \ Quad (n \ GEQ 1) \ \ \ \ & fade: y = 100 \% - \ frac (3-T) ^ n \ Quad (n \ GEQ 1) \ \ \ \ & where, \ begin T & time (in seconds) \ \ Y & brightness percentage \ end \end Fade out: y=100% − 3n100% tn(n ≥ 1) fade out: y=100% − 3n100% (3 − t)n(n ≥ 1) where, } 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()
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 & left push length: 0 \% → 20 \%, nonlinear growth (slower and slower) \ \ & left pull length: 20 \% → 0 \%, nonlinear decrease (slower and slower) \ \ \ end 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 & push close: y = 33 \% - \ frac (3-T) ^ n \ Quad (n \ GEQ 2) \ \ \ \ & pull away: y = \ frac (3 - t) ^ n \ Quad (n \ GEQ 2) \ \ \ \ & where, \ begin T & time (unit: seconds) \ \ Y & left push / pull away percentage \ end \end Push in: y=33% − 3n33% (3 − t)n(n ≥ 2) pull away: y=3n33% (3 − t)n(n ≥ 2) where, \ begin & \ BM \ \ \ & \ textbf = \ begin \ textbf & \ textbf \ \ \ \ textbf & \ textbf \ \ \ \ end \end a% → b%mode = β©βͺβ¨βͺβ§ fasterslower faster and slower
You can generate one based on the current time t \bm Tcalculate the current arrival percentage c % \bm 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 & \bm \textbf\bm{(a \% - b \%) \cdot \frac{\delta \%}{(\textbf)^n} \cdot (\textbf - t)^n + b \%} & \textbf = \textbf \ \ & \bm \textbf\bm{(b \% - a \%) \cdot \frac{\delta \%}{(\textbf)^n} \cdot t^n + a \%} & \textbf = \textbf \ \ & \textbf \ BM {\ Delta \% = |; a \% - B \% \; |} \ end β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 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 & \ textbf is \ text , swap} \ bm\textbf \ bm\textbf - t} \ \ \ & \ BM \ textbf \ BM {(B \% - a \%) \ cdot \ frac {\ Delta \%} {(\ textbf ) ^ n} \ cdot T ^ n + a \%} \ \ \ end 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()
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 & half width of local square: 0 \% → 50 \%, nonlinear growth (faster and faster) \ \ \ end 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()