幻影坦克制作

  1. 1. 黑白
    1. 1.1. 原理
    2. 1.2. 实现
    3. 1.3. numpy计算
  2. 2. 彩色
    1. 2.1. 原理
    2. 2.2. 实现
    3. 2.3. numpy计算

其实就是用到了图片在不同背景下得到的效果,这里提供一个测试的地方

黑白

原理

这里用到图形学里的一个混合的计算公式:

现已知混合图某个像素点的值为

其在白色背景下混合值为,在黑色背景下的混合值为

其实就是解个方程组





求解得





这里有个问题就是有三种表达式,并且三个表达式的值要相等。一种想法就是将其转为灰度图,即。这时的三种表达式就相等了。解也可简化为

结果


这也就是将图片混合的公式

其次是的值可能超出其的值域,为了避免这种情况就得使,也就是将的值变大的值变小。

实现

这里有两张图片

图片1
图片2

接着按照上面的结果来计算生成结果的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import cv2 as cv
import numpy as np

img1 = cv.imread("img1.png",0)
img2 = cv.imread("img2.png",0)
h,w = img1.shape
img3 = np.zeros((w,h,4))

for i in range(h):
for j in range(w):
r1 = img1[i][j] if img1[i][j] > 100 else 100 # 小于100的像素点都算100,增大r1
r2 = img2[i][j] * 0.35 # 为了使r2更小等比例缩小r2
alpha = 255 - r1 + r2 # 这里值为1时即为255 对应公式 1 - r1 + r2
rx = 255 * r2 / alpha # 对应r2 / alpha
img3[i][j] = (rx,rx,rx,alpha)

cv.imwrite("img.png",img3)

numpy计算

1
2
3
4
5
6
r1 = (np.where(img1 < 100, 100, img1)).astype(np.uint8)
r2 = (img2 * 0.35).astype(np.uint8)
alpha = 255 - (r1 - r2)
alpha = np.where(alpha == 0, 1, alpha).astype(np.uint8)
rx = (255 * PB.astype(np.float32) / alpha).astype(np.uint8)
img3 = np.stack([rx, rx, rx, alpha], axis=-1)
合成结果

结果1

彩色

原理

回顾上面方程的解





其主要问题是有三个表达式,如果能将通道分为rgb三个那么问题就很容易解决了。但我们只有rgba四个通道,现在能做的是让三个的值尽可能相等,上面通过转为灰度图来解决,但不足的就是没有颜色。现在采用取取均值,即

但这样的效果下的黑底并不是很好

结果2

所以需要插值来平均色彩

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import cv2 as cv
import numpy as np

img1 = cv.imread("img1.png")
img2 = cv.imread("img2.png")
h,w,_ = img1.shape
img3 = np.zeros((h,w,4))

scale1,scale2 = 1,0.2
lerp1,lerp2 = 0.5,0.7

for i in range(h):
for j in range(w):

b1,g1,r1 = img1[i][j] * scale1
b2,g2,r2 = img2[i][j] * scale2

img1_c = 0.334 * r1 + 0.333 * g1 + 0.333 * b1
r1 = r1 * lerp1 + img1_c * (1 - lerp1)
g1 = g1 * lerp1 + img1_c * (1 - lerp1)
b1 = b1 * lerp1 + img1_c * (1 - lerp1)

img2_c = 0.334 * r2 + 0.333 * g2 + 0.333 * b2
r2 = r2 * lerp2 + img2_c * (1 - lerp2)
g2 = g2 * lerp2 + img2_c * (1 - lerp2)
b2 = b2 * lerp2 + img2_c * (1 - lerp2)

ab = 255 - b1 + b2
ag = 255 - g1 + g2
ar = 255 - r1 + r2

a = 0.2126 * ar + 0.7152 * ag + 0.0722 * ab

B = 255 * b2 / a
G = 255 * g2 / a
R = 255 * r2 / a
A = a
img3[i][j] = (B,G,R,A)

print(img3)
cv.imwrite("ans1.png",img3)

numpy计算

1
2
3
4
5
6
7
8
9
10
11
12
13
image1 = image1.astype(np.float32) * scale1
image2 = image2.astype(np.float32) * scale2

img1_c = 0.334 * image1[:, :, 2] + 0.333 * image1[:, :, 1] + 0.333 * image1[:, :, 0]
image1 = image1 * lerp1 + np.stack([img1_c, img1_c, img1_c], axis=-1) * (1 - lerp1)

img2_c = 0.334 * image2[:, :, 2] + 0.333 * image2[:, :, 1] + 0.333 * image2[:, :, 0]
image2 = image2 * lerp2 + np.stack([img2_c, img2_c, img2_c], axis=-1) * (1 - lerp2)

a = 255 - image1 + image2
a = 0.2126 * a[:, :, 2] + 0.7152 * a[:, :, 1] + 0.0722 * a[:, :, 0]

res_img = np.dstack((255 * image2 / np.stack([a, a, a], axis=-1), a[..., np.newaxis]))

通过调整到插值来达成效果

这是我认为还不错的结果

结果3

两张图片的区别较小时结果会更为理想