) V' [: H5 Q& C3 P% D! y& |& [) a) t for i in range(h): $ a6 `% Y; B) D/ }) v for j in range(w): 4 k) g9 Y! M& N& N( f # (B, G, R)" Z; g% c7 u3 _
if mean_square_loss(img[i, j], origin_bgr) < 50:. w& v. f1 H3 [7 S1 U1 f
img[i, j] = target_bgr ; Z0 k! }/ B2 v" c8 h+ H0 a1 [8 N E0 O/ Z# `- c
cv2.imwrite(result_png, img)' v. O# y7 {5 V( a" p
print('图片写入 {} 成功'.format(result_png))1 g$ h1 N" \4 k/ g$ c& L) h9 W
, ^7 N q% z7 E- M; C( I4 I4 M# O' S7 X' J$ b
if __name__ == '__main__':! a0 S7 d8 i c3 W. D" Y* N
# origin_png = 'result_png/result_png.png'" {4 L3 s; t) T1 {
origin_png = 'origin_png/person.jpg' 5 f; {5 j- ]& b result_png = 'result_png/result_refine.png' * n: D# }( K) g change_red2blue(origin_png, result_png)* Z$ d [; N" _6 [ ]4 C( f0 a
1 * a. _1 q) R2 I) ]8 k' q+ Q8 r2 / ?; Z* ?! S3 l) @4 C7 \* P3 . U# H9 n! h3 ^8 P4 1 ]/ Q5 P1 K; ]0 _5 k2 ^5# V0 R! q, T% o1 _
6 6 f. Y. r1 x- i0 i7 7 e3 T: Z: N; ~& g! t88 r. t4 F; s3 U8 ?& D
9 ; Q$ n- @. M2 P) H) p x3 {/ W10 7 j) |4 t/ a, m; N4 K. k/ O11% d; J: i( L" Y5 R- `
12 ; u$ e7 l" ~" d4 ?. a4 r: j13- N9 ]2 W( w. s
14 ' \" k5 |3 c5 k& j) Z8 K% {15/ P! j' j+ [% p$ D" S6 ~% A! z' |
16* x& g* A8 h" k: c& @
17 ]+ X( j$ `7 u, U& m+ |2 ?. U18% g6 c" \4 y1 q
191 j" {% K- V7 y+ B' }5 D# q# Y
20( k: A8 i+ c- H3 `, F% l
21 4 p* ?) r% d; x, o22 + c3 v' g& ~; l- e5 D6 O23" [5 `3 a; ^+ m. t
24; b( H7 V) r! R* i7 ?1 B
25% @+ o: U6 g9 g/ V2 |1 h
26 + K9 Q- J" ^ ?9 A3 D0 W27 6 }( ~! h7 b; N: Q. Y8 a28 6 o2 L3 D- H) W" h3 U4 O# n298 e4 W7 v j: C
30- S- r7 \( k7 \4 _
31 9 @7 Z; o8 b, r; I: [8 k32 / U' e5 G( _ r33 9 V+ ^: K/ y8 z" w( J6 Z4 S% A34 4 n8 T& ~1 X: ~# x; L" S35 2 x+ V H8 N. q! \/ Y! i; z结果人与背景边缘仍会存在红色像素残留0 f2 m+ M+ N; o& @+ R, b
/ l- P) [6 U, Z* \4 q( a8 ]$ p, b
/ s7 Q! v# I0 l3 n 0 |2 T3 x" ? L9 x3 J/ n0 p) F $ d' u2 @4 }. T6 ?: u% i9 J( _1 Z6 |5 K8 B
PIL& t4 S+ c/ @2 G! q2 f
from torchvision.transforms.functional import to_tensor, to_pil_image8 x7 @4 f1 n( ^" l
from PIL import Image q' b |9 T1 _9 ^, |
import torch . h+ s! L- \! x$ Y5 ~import time- m/ {4 z: j1 F$ Y
9 a+ H. q, h l+ N( s4 P; G8 A% _9 i* y* E" z. |' k& N( ~" p
def mean_square_loss(a_ts, b_ts):$ |0 L7 R) z% n7 D
# print(a_ts.shape) 6 D) z" O. T6 {/ L # print(b_ts)- O8 @9 P4 E) _& d
sl = (a_ts - b_ts) ** 2 8 e1 Y+ b6 S% s" N4 L. k, r& D return sl.sum() R) c% O) N1 C9 `' ] U: n) ]8 ^0 @ , ?9 _) G" N6 C5 ~8 r: s8 ~0 K) X, Q
def change_red2blue(origin_png, result_png): 1 T' Z/ W4 t- r4 E src = Image.open(origin_png) 4 M' s* l) k* A% V: ]9 p' S" F src = to_tensor(src) : X* j7 t6 ~+ x6 U/ [+ o # print(src.shape) # torch.Size([3, 800, 600])* z0 g7 _ N D2 t! V9 {/ r; S2 A
# channel: (R, G, B) / 255% n$ M' i R' w; V* }# k' E
h, w = src.shape[1], src.shape[2]5 J4 R4 V( y; a4 u
' C5 I$ P: ? |1 S; ?0 q
pha = torch.ones(h, w, 3) 6 n- n5 ~$ l+ h- ^- L5 \0 l! ^0 l9 @ : o" A. ~$ f' V) d+ ^# j bg = torch.tensor([168,36,32]) / 255 2 S6 J: p. l5 u3 n! ` target_bg = torch.tensor([19,122,171]) / 255 , b$ r8 ~% i: `( R4 H ' ~4 e- [' Z5 p0 P% Q. e* L # C, H, W -> H, W, C 0 i. Z- D3 b% Z$ G& T4 ~/ Z src = src.permute(1, 2, 0)+ I+ i0 p' B3 R6 s& E% U
for i in range(h): - v. q+ S9 }% e; r) C for j in range(w): S% d6 X7 y% W) O) `4 s
if mean_square_loss(src[j], bg) < 0.025: # 0.025是阈值,超参数( L) a& A/ e! W3 r9 U5 x; [5 c% `
pha[j] = torch.tensor([0.0, 0.0, 0.0]) 8 a5 \: o* N4 ^8 a% r, y3 D, R / V! X5 a& R1 k% U3 G; D/ F6 g # H, W, C -> C, H, W4 l% e1 E" J4 I! A5 D, p: k
src = src.permute(2, 0, 1) m/ L9 N3 `9 c0 s1 V) V$ f2 d7 i& W
pha = pha.permute(2, 0, 1) " z; M( @# ?" L; `4 R" D com = pha * src + (1 - pha) * target_bg.view(3, 1, 1)1 X% p/ `+ k. ?( h. |. S
to_pil_image(com).save(result_png) : E# i5 y/ o4 ?/ w3 j6 A9 A3 B2 f& ? r' n6 Z+ l+ c6 I
9 i' Y+ A$ r3 m! Y/ `3 Y
if __name__ == '__main__': [$ X/ ]: k/ t' B- H e# c
origin_png = 'origin_png/person.jpg'. L- w; e) K3 h& M% p
result_png = 'result_png/com.png', ]& H$ @( }0 o7 X: G
start_time = time.time()5 t5 G+ ^8 \% F1 c% r9 E2 {# e
change_red2blue(origin_png, result_png) $ x6 c# \3 x& ^- W+ e. i spend_time = round(time.time() - start_time, 2)1 [! [$ \: k& ~; i) L, m
print('生成成功,共花了 {} 秒'.format(spend_time))( `9 U& D Q" T; D- D/ R* `" D
1 . Q* [" m/ H/ c6 |8 ]6 D2 7 h1 H( A# n$ z$ r, M3 1 U7 l( c3 e. P4 6 a4 _+ m$ p& y" ^( r3 r- B+ I5 + h: d# `1 a, |6 ! d( f; {) c$ O$ O9 O( D7 , w& [& W) s& Y: m* }8 , c4 \) {+ {2 E6 ]9; n) s1 I" k5 T) J
108 F; J4 ^; Y9 F2 w& p
114 ^5 y' l$ X' p! \ q O
12 $ S( y+ S& g, R+ c2 T13 ' T8 T, C! }, C14* c$ R8 L1 I* r' i. g) D4 F
15 / a% O" v' D$ @! _* w16 . K/ S/ ^, z/ t R( ^4 Y178 d$ S/ `5 E# g9 F) G3 b; j, t
18# O: @( j4 S. s2 j, z- }1 H
19 . M. v; x4 ~8 F6 a, l7 k207 B% e) i: V& I- n2 H" V4 Q
21 ; J) R) C! b u# x. x2 r- ?22 8 H( E9 j/ @5 Z* o: S/ w6 }4 f$ t23 . B. [3 m2 r& p0 n* \; [) L$ u24. v0 F3 v3 s1 ~& i5 M
25 1 b5 F# F& n3 `' v& B% A* O264 U' o0 F8 `8 |+ m+ }) b
27 # c- M9 p5 L: k8 w, p) A28 " r- }+ Y' h6 H296 z U; R1 J* W6 O) H) `9 |% g( ]
308 t, U: F+ t! k& c2 W
31( _5 `) U6 ^' [7 ]4 W8 ?
325 _0 }+ l* \$ D! ^- j
33 * j3 V* W6 ^& k1 B8 A34' @* O8 z+ ]7 V2 A6 H+ I& B
35- o* p6 V# e; |/ x
36 ; {' p6 \0 f; v! ^% @: r37 p" U) f. [! d3 u3 W% T: N7 |- K& M+ T# m38( |2 O6 z3 v$ y& j3 E
39/ X) | c0 p$ M5 z# g; T$ p2 _
40 ' `3 D9 `/ a( }* ?0 Y! l" n41 , y U" x4 u j$ ]$ h. q9 P. u42 $ Q4 M; Z+ F2 _) o43. P8 C4 }. T2 _5 O8 \
44- C; h0 p g3 f- A2 w, l
45$ X; D$ u0 T4 `) M; h* j
46 ; Y9 z# c% @5 |6 d4 B! T& l j该方法质量较好,但一张图片大概需要12秒。! R3 o: G8 [4 Q! s; C
( \# ^2 m5 ^" g5 `. c, {# M( {2 N+ l! T3 ^( B, x, l
3 O" c0 b6 U& v d' w+ P; l! i% C方法四: Background MattingV21 p e' C% K% U$ V# e5 u) L
Real-Time High-Resolution Background Matting & Z& S9 n, D: K" QCVPR 2021 oral) G$ L' r: m- \' i ^5 W
; i5 m# Q2 R: ~- L; J+ `+ h$ j论文:https://arxiv.org/abs/2012.078103 R" d! [# \! D3 {
代码:https://github.com/PeterL1n/BackgroundMattingV2 c+ o: P0 {3 C% f; y e & U J8 |/ k2 _! z0 Ggithub的readme.md有inference的colab链接,可以用那个跑; s e# c- W+ I. Z l5 `5 k
. i" B: s/ L; M' N1 S8 y8 @
由于这篇论文是需要输入一张图片(例如有人存在的草地上)和背景图片的(如果草地啥的), 然后模型会把人抠出来。 ! H& h4 b6 q- A6 g 1 [5 b0 U) E j于是这里我需要生成一个背景图片。0 F# C1 n8 L8 D* h) O' Z
首先我先借助firefox的颜色拾取器(或者微信截图,或者一些在线工具,例如菜鸟工具),得到十六进制,再用在线转换工具转成rgb。 7 I3 n8 P( C( t" [9 T; i& m) J# q 9 d4 ^& T$ w0 \- ]* J3 K" r然后生成一个背景图片。 : O8 ?; A% c1 @& Z# o ( e* m2 M x% Y( D2 fimport cv2 1 K& \ y+ W0 G; Z3 V: f8 s/ aimport numpy as np 8 ], \( A3 }8 i) X9 A& e y. D. K/ D
! g0 N# t! o4 {' t; E
image = cv2.imread("origin_png/person.jpg") ( M& o( Z! ~ x1 [) r; Uorigin_rgb = (168,36,32) # 可以用浏览器啥的控制台工具提取出背景的rgb值$ @" [" E* Z4 p7 a- X
origin_bgr = (origin_rgb[2], origin_rgb[1], origin_rgb[0]) ' }; ^8 h D3 ^2 o0 _. o9 x- f" Kimage[:, :] = origin_bgr8 {: }, K. L2 D% p* ~, z
, ?7 e I2 _: y0 t& j
cv2.imwrite("mask/bg.png", image)7 O: o2 s# O/ P+ w4 L* i
1 2 ]& t- q2 M# C$ `, p6 ]$ ]' D2 E8 O, v7 T) k3 \, {6 p5 S" E& ]( P% C
4* ^8 R0 K5 }7 U+ w5 b; J' m
5' E9 ~6 r4 ^* n3 V
6 4 Y9 q$ g4 p& v, y; Q# Q- M8 \7 ; T$ e/ T3 T+ P4 h H& o# c3 H8% ^6 J5 {* {7 O1 Y4 x
98 E3 [' J) r- e j7 g
10, `2 x+ j) R. l4 S4 U" t! d" P1 K
) l) Q d. A1 U% o6 x1 j7 X7 r
需要上传人的照片和背景照片, 如果名字和路径不一样则需要修改一下代码 - M* y$ u7 ]! Q4 q, d6 g- p ?: [5 }4 C @' W: m
src = Image.open('src.png') ! Z6 X6 }0 ]3 D4 abgr = Image.open('bgr.png')/ N! t w d2 X Q; t% B" ~
1% }/ O1 |8 H) E
2* j' s; T! n! x9 b _
另外原论文是边绿底,要变蓝底,白底,红底则可以修改RGB值,举个例子,原来是这样的(绿底, RGB120, 255, 155)- I4 w8 q' m. |0 ?3 V# V