数字图像处理-11-图像的一些合成操作

# ─────────────────────────────────────────────────────────
#  内部辅助函数
# ─────────────────────────────────────────────────────────

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

-效果图
提取两图亮暗不同的区域,相同区域变黑
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值