# ─────────────────────────────────────────────────────────
# 内部辅助函数
# ─────────────────────────────────────────────────────────
def _binarize(data, row_bytes, width, height, is_gray):
"""
将像素数据二值化
对每个像素:val > 128 → 1,否则 → 0
参数:
data - 源像素bytearray
row_bytes - 每行字节数(含4字节对齐填充)
width - 图像宽度(像素),仅灰度图使用
height - 图像高度(像素)
is_gray - True=8位灰度(每像素1字节),False=24位彩色(按通道字节)
返回:
bytearray,每个"字节位置"存0或1(与源数据等大)
"""
# 决定迭代步长
# 8位图:有效列范围 [0, width),步长=row_bytes
# 24位图:有效列范围 [0, row_bytes),步长=row_bytes(含BGR及填充)
col_end = width if is_gray else row_bytes
buf = bytearray(row_bytes * height) # 初始全0
for j in range(height):
base = j * row_bytes
for i in range(col_end):
if data[base + i] > 128:
buf[base + i] = 1
return buf
1.图像加法合成
-
原理:
对两幅图像对应位置的像素值直接相加,结果超出255时截断(饱和加法)。
公式:result(x,y) = min(A(x,y) + B(x,y), 255) -
效果:
- 将两图叠加,整体亮度提升
- 高亮区域快速饱和变白
- 常用于多曝光融合、亮度增强
-
python代码
def image_add(img_src, img_bg):
"""
图像加法合成:
两张图像的宽高要一样,否则大概率会出现花屏图片.
参数:
img_src - 源图像 (BmpImage)
img_bg - 背景/第二张图像 (尺寸须与img_src相同)
返回:
新BmpImage,内容为加法结果(不修改输入图像)
"""
result = img_src.clone()
data = result.data # 拷贝的图像数据,bmp格式
bg = img_bg.data
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
# ── 8位灰度图 ──
# 初始化临时缓冲区为255(边框像素默认为白色)
temp = bytearray(row_bytes * height)
for k in range(len(temp)):
temp[k] = 255
# 逐像素相加(跳过最外层边框)
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
val = data[idx] + bg[idx] # 融合的两张图片宽高要一样
temp[idx] = 255 if val > 255 else val
# 将结果写回data
for k in range(len(data)):
data[k] = temp[k]
else:
# ── 24位彩色图 ──
# dib_width = row_bytes,包含BGR三通道及对齐填充
dib_width = row_bytes
temp = bytearray(height * dib_width)
for j in range(1, height - 1):
# i 从3开始跳过左边框像素(3字节=1像素),到dib_width-3止
# 再次说明,这里包含RGB 3通道的数据,所以,宽度是原来3倍,即为dib_width
for i in range(3, dib_width - 3):
idx = j * dib_width + i
val = data[idx] + bg[idx] # 简单粗暴,直接相加
temp[idx] = 255 if val > 255 else val
for k in range(len(data)):
data[k] = temp[k]
return result
- 效果图
可以看到,因为中间图片后面的天空是白色的,所以合成后,天空全白了.

2.图像减法合成
-
原理:
用源图像减去背景图像,结果小于0时截断为0(饱和减法)。
公式:result(x,y) = max(A(x,y) - B(x,y), 0) -
效果:
- 提取两图的差异,相同区域变黑
- 可用于背景去除、运动检测、差分图像
- 常用于视频监控中的前景提取
-
python代码
def image_sub(img_src, img_bg):
"""
参数与返回值同 image_add
"""
result = img_src.clone() # 第一张图像拷贝,当作画布
data = result.data
bg = img_bg.data #背景图像拷贝
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
temp = bytearray(row_bytes * height)
for k in range(len(temp)):
temp[k] = 255 # 边框默认白色
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
val = data[idx] - bg[idx]
temp[idx] = 0 if val < 0 else val
for k in range(len(data)):
data[k] = temp[k]
else: # 如果不是灰度图,根据像素宽度,
dib_width = row_bytes
temp = bytearray(height * dib_width)
for j in range(1, height - 1):
for i in range(1, dib_width - 1): # dib_width是RGB 3通道的数据总长
idx = j * dib_width + i
val = data[idx] - bg[idx]
temp[idx] = 0 if val < 0 else val
for k in range(len(data)):
data[k] = temp[k]
return result
- 效果图
注意:中间这张是输入的原图,第一张是背景图.计算时是"第二张 - 第一张". 随意能看到天空颜色变暗了.
但由于是RGB各通道都进行了减法操作,合成后的图像人脑暂时合成不出来. 凑合着看吧.

3.图像与运算合成
-
原理:
先对两图各像素以给定阈值(下面demo的阈值为128)进行二值化,再逐像素做逻辑与(AND)运算。二值化后,与运算很简单,同为1为1,有一个不是1,就是0. 过程如下所示.二值化:val > 128 → 1,否则 → 0 AND规则: 1 AND 1 = 1 → 255(白) 其余组合 = 0 → 0(黑) 真值表: A B │ A AND B ─────┼──────── 0 0 │ 0 0 1 │ 0 1 0 │ 0 1 1 │ 1 ← 仅当两图同时为亮时结果才亮 -
效果:
- 保留两图共同的亮区域,其余变黑
- 常用于图像掩膜(mask)操作、ROI区域提取. 比如: 在医学影像中,只保留病变区进行分析,我们制作了一张"掩膜图像",在想要保留的区域填上白色,不想保留的背景填上黑色.那么进行与预算后,我们就能把病变区的图像抠出来.
def image_and(img_src, img_bg):
"""
图像与(AND)运算合成
参数与返回值同 image_add
"""
result = img_src.clone()
data = result.data
bg = img_bg.data
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
# 二值化两图(边框及整体范围都处理)
temp1 = _binarize(data, row_bytes, width, height, True)
temp2 = _binarize(bg, row_bytes, width, height, True)
# AND运算(跳过边框,边框保持初始0值)
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
# 下面能直接看到,只有两张图都是1的情况下,才置为白色.
temp1[idx] = 255 if (temp1[idx] == 1 and temp2[idx] == 1) else 0
for k in range(len(data)):
data[k] = temp1[k]
else:
dib_width = row_bytes
temp1 = _binarize(data, row_bytes, None, height, False)
temp2 = _binarize(bg, row_bytes, None, height, False)
for j in range(1, height - 1):
for i in range(1, dib_width - 1):
idx = j * dib_width + i
# 下面能直接看到,只有两张图都是1的情况下,才置为白色.
temp1[idx] = 255 if (temp1[idx] == 1 and temp2[idx] == 1) else 0
for k in range(len(data)):
data[k] = temp1[k]
return result
- 效果图

4.图像或运算合成
-
原理:
先对两图各像素以阈值128进行二值化,再逐像素做逻辑或(OR)运算。只要两张图像在相同位置的像素中,有一个为白色(或1),结果就会是白色;只有当两个像素都为黑色(或0)时,结果才为黑色。
或运算的逻辑如下所示.OR规则: 0 OR 0 = 0 → 0(黑) 其余组合 = 1 → 255(白) 真值表: A B │ A OR B ─────┼──────── 0 0 │ 0 ← 仅当两图同时为暗时结果才黑 0 1 │ 1 1 0 │ 1 1 1 │ 1 -
效果:
- 合并两图的亮区域,两图中任一亮的地方结果都亮
- 常用于图像区域合并、多目标检测结果融合,比如:在将一个小图像(如公司Logo、水印)叠加到一张大背景图上时
def image_or(img_src, img_bg):
"""
图像或(OR)运算合成
参数与返回值同 image_add
"""
result = img_src.clone()
data = result.data
bg = img_bg.data
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
temp1 = _binarize(data, row_bytes, width, height, True)
temp2 = _binarize(bg, row_bytes, width, height, True)
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
temp1[idx] = 0 if (temp1[idx] == 0 and temp2[idx] == 0) else 255
for k in range(len(data)):
data[k] = temp1[k]
else:
dib_width = row_bytes
temp1 = _binarize(data, row_bytes, None, height, False)
temp2 = _binarize(bg, row_bytes, None, height, False)
for j in range(1, height - 1):
for i in range(1, dib_width - 1):
idx = j * dib_width + i
temp1[idx] = 0 if (temp1[idx] == 0 and temp2[idx] == 0) else 255
for k in range(len(data)):
data[k] = temp1[k]
return result
- 效果图

5.图像非运算合成
-
原理:
先对图像各像素以阈值128进行二值化,再对每个像素取逻辑非(NOT)。NOT规则: 1 → 0 → 0(黑) 0 → 1 → 255(白) -
效果:
- 将亮区变暗、暗区变亮,产生负片/反色效果
- 常用于图像互补掩膜的生成、对比度反转
def image_not(img_src):
"""
图像非(NOT)运算合成(单图操作)
参数:
img_src - 源图像
返回:
新BmpImage,内容为NOT结果
"""
result = img_src.clone()
data = result.data
is_gray = (img_src.bit_count < 9)
row_bytes = img_src.row_bytes
height = img_src.height
# 8位图迭代到width,24位图迭代到row_bytes(逐通道字节)
col_end = img_src.width if is_gray else row_bytes
temp = _binarize(data, row_bytes, img_src.width, height, is_gray)
# NOT运算(跳过边框)
for j in range(1, height - 1):
for i in range(1, col_end - 1):
idx = j * row_bytes + i
# 黑的变白,白的变黑
temp[idx] = 255 if temp[idx] == 0 else 0
for k in range(len(data)):
data[k] = temp[k]
return result
- 效果图
白的变黑,黑的变白

6.图像或非运算合成
-
原理:
NOR = NOT(OR),先OR再整体取非。
等价于:仅当两图都为暗(0)时,结果才为亮(255)。真值表: A B │ A NOR B ─────┼───────── 0 0 │ 1 ← 两图都暗才亮 0 1 │ 0 1 0 │ 0 1 1 │ 0 -
效果:
- 提取两图共同的暗区(背景区域)
- 是OR结果的互补图
def image_nor(img_src, img_bg):
"""
图像或非(NOR)运算合成
参数与返回值同 image_add
"""
result = img_src.clone()
data = result.data
bg = img_bg.data
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
temp1 = _binarize(data, row_bytes, width, height, True)
temp2 = _binarize(bg, row_bytes, width, height, True)
# NOR:两图都为0时才输出255,其余为0
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
temp1[idx] = 255 if (temp1[idx] == 0 and temp2[idx] == 0) else 0
for k in range(len(data)):
data[k] = temp1[k]
else:
dib_width = row_bytes
temp1 = _binarize(data, row_bytes, None, height, False)
temp2 = _binarize(bg, row_bytes, None, height, False)
# 24位彩色NOR(边框扩大到3字节=1像素)
for j in range(1, height - 1):
for i in range(3, dib_width - 3):
idx = j * dib_width + i
temp1[idx] = 255 if (temp1[idx] == 0 and temp2[idx] == 0) else 0
for k in range(len(data)):
data[k] = temp1[k]
return result
- 效果图
提取两张图共同的暗区

7.图像与非运算合成
-
原理:
NAND = NOT(AND),先AND再整体取非。
等价于:仅当两图都为亮(1)时,结果才为暗(0),其余为亮(255)。真值表: A B │ A NAND B ─────┼────────── 0 0 │ 1 0 1 │ 1 1 0 │ 1 1 1 │ 0 ← 两图都亮才黑 -
效果:
- 是AND结果的互补图
- 提取两图中"不同时亮"的区域
- 效果图
def image_nand(img_src, img_bg):
"""
图像与非(NAND)运算合成
参数与返回值同 image_add
"""
result = img_src.clone()
data = result.data
bg = img_bg.data
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
temp1 = _binarize(data, row_bytes, width, height, True)
temp2 = _binarize(bg, row_bytes, width, height, True)
# NAND:两图都为1时输出0,其余为255
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
temp1[idx] = 0 if (temp1[idx] == 1 and temp2[idx] == 1) else 255
for k in range(len(data)):
data[k] = temp1[k]
else:
dib_width = row_bytes
temp1 = _binarize(data, row_bytes, None, height, False)
temp2 = _binarize(bg, row_bytes, None, height, False)
for j in range(1, height - 1):
for i in range(3, dib_width - 3):
idx = j * dib_width + i
temp1[idx] = 0 if (temp1[idx] == 1 and temp2[idx] == 1) else 255
for k in range(len(data)):
data[k] = temp1[k]
return result
- 效果图
提取两图中"不同时亮"的区域

8 图像异或合成
-
原理:
先对两图各像素以阈值128进行二值化,再逐像素做逻辑异或(XOR)运算。
XOR检测"不同":当且仅当两个输入值不同时结果为1。判断方式: temp1[idx] + temp2[idx] == 1 → 255(两者不同) temp1[idx] + temp2[idx] != 1 → 0 (两者相同) 真值表: A B │ A XOR B ─────┼───────── 0 0 │ 0 ← 都暗,结果黑 0 1 │ 1 ← 不同,结果白 1 0 │ 1 ← 不同,结果白 1 1 │ 0 ← 都亮,结果黑 -
效果:
- 提取两图亮暗不同的区域,相同区域变黑
- 常用于图像差异检测、边缘提取、加密水印
# ─────────────────────────────────────────────────────────
# 8. 异或运算合成(XOR)
# ─────────────────────────────────────────────────────────
def image_xor(img_src, img_bg):
"""
图像异或(XOR)运算合成
参数与返回值同 image_add
"""
result = img_src.clone()
data = result.data
bg = img_bg.data
width = img_src.width
height = img_src.height
row_bytes = img_src.row_bytes
is_gray = (img_src.bit_count < 9)
if is_gray:
temp1 = _binarize(data, row_bytes, width, height, True)
temp2 = _binarize(bg, row_bytes, width, height, True)
# XOR:两者之和==1 → 输入不同 → 255
for j in range(1, height - 1):
for i in range(1, width - 1):
idx = j * row_bytes + i
temp1[idx] = 255 if (temp1[idx] + temp2[idx] == 1) else 0
for k in range(len(data)):
data[k] = temp1[k]
else:
dib_width = row_bytes
temp1 = _binarize(data, row_bytes, None, height, False)
temp2 = _binarize(bg, row_bytes, None, height, False)
for j in range(1, height - 1):
for i in range(3, dib_width - 3):
idx = j * dib_width + i
temp1[idx] = 255 if (temp1[idx] + temp2[idx] == 1) else 0
for k in range(len(data)):
data[k] = temp1[k]
return result
-效果图
提取两图亮暗不同的区域,相同区域变黑

3656

被折叠的 条评论
为什么被折叠?



