数字图像处理-11-图像的一些合成操作 文章目录1.图像加法合成2.图像减法合成3.图像与运算合成4.图像或运算合成5.图像非运算合成6.图像或非运算合成7.图像与非运算合成8 图像异或合成# ─────────────────────────────────────────────────────────# 内部辅助函数# ─────────────────────────────────────────────────────────def_binarize(data,row_bytes,width,height,is_gray): 将像素数据二值化 对每个像素val 128 → 1否则 → 0 参数 data - 源像素bytearray row_bytes - 每行字节数含4字节对齐填充 width - 图像宽度像素仅灰度图使用 height - 图像高度像素 is_gray - True8位灰度每像素1字节False24位彩色按通道字节 返回 bytearray每个字节位置存0或1与源数据等大 # 决定迭代步长# 8位图有效列范围 [0, width)步长row_bytes# 24位图有效列范围 [0, row_bytes)步长row_bytes含BGR及填充col_endwidthifis_grayelserow_bytes bufbytearray(row_bytes*height)# 初始全0forjinrange(height):basej*row_bytesforiinrange(col_end):ifdata[basei]128:buf[basei]1returnbuf1.图像加法合成原理对两幅图像对应位置的像素值直接相加结果超出255时截断饱和加法。公式result(x,y) min(A(x,y) B(x,y), 255)效果将两图叠加整体亮度提升高亮区域快速饱和变白常用于多曝光融合、亮度增强python代码defimage_add(img_src,img_bg): 图像加法合成: 两张图像的宽高要一样,否则大概率会出现花屏图片. 参数 img_src - 源图像 (BmpImage) img_bg - 背景/第二张图像 (尺寸须与img_src相同) 返回 新BmpImage内容为加法结果不修改输入图像 resultimg_src.clone()dataresult.data# 拷贝的图像数据,bmp格式bgimg_bg.data widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:# ── 8位灰度图 ──# 初始化临时缓冲区为255边框像素默认为白色tempbytearray(row_bytes*height)forkinrange(len(temp)):temp[k]255# 逐像素相加跳过最外层边框forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi valdata[idx]bg[idx]# 融合的两张图片宽高要一样temp[idx]255ifval255elseval# 将结果写回dataforkinrange(len(data)):data[k]temp[k]else:# ── 24位彩色图 ──# dib_width row_bytes包含BGR三通道及对齐填充dib_widthrow_bytes tempbytearray(height*dib_width)forjinrange(1,height-1):# i 从3开始跳过左边框像素3字节1像素到dib_width-3止# 再次说明,这里包含RGB 3通道的数据,所以,宽度是原来3倍,即为dib_widthforiinrange(3,dib_width-3):idxj*dib_widthi valdata[idx]bg[idx]# 简单粗暴,直接相加temp[idx]255ifval255elsevalforkinrange(len(data)):data[k]temp[k]returnresult效果图可以看到,因为中间图片后面的天空是白色的,所以合成后,天空全白了.2.图像减法合成原理用源图像减去背景图像结果小于0时截断为0饱和减法。公式result(x,y) max(A(x,y) - B(x,y), 0)效果提取两图的差异相同区域变黑可用于背景去除、运动检测、差分图像常用于视频监控中的前景提取python代码defimage_sub(img_src,img_bg): 参数与返回值同 image_add resultimg_src.clone()# 第一张图像拷贝,当作画布dataresult.data bgimg_bg.data#背景图像拷贝widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:tempbytearray(row_bytes*height)forkinrange(len(temp)):temp[k]255# 边框默认白色forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi valdata[idx]-bg[idx]temp[idx]0ifval0elsevalforkinrange(len(data)):data[k]temp[k]else:# 如果不是灰度图,根据像素宽度,dib_widthrow_bytes tempbytearray(height*dib_width)forjinrange(1,height-1):foriinrange(1,dib_width-1):# dib_width是RGB 3通道的数据总长idxj*dib_widthi valdata[idx]-bg[idx]temp[idx]0ifval0elsevalforkinrange(len(data)):data[k]temp[k]returnresult效果图注意:中间这张是输入的原图,第一张是背景图.计算时是第二张 - 第一张. 随意能看到天空颜色变暗了.但由于是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区域提取. 比如: 在医学影像中,只保留病变区进行分析,我们制作了一张掩膜图像,在想要保留的区域填上白色,不想保留的背景填上黑色.那么进行与预算后,我们就能把病变区的图像抠出来.defimage_and(img_src,img_bg): 图像与(AND)运算合成 参数与返回值同 image_add resultimg_src.clone()dataresult.data bgimg_bg.data widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:# 二值化两图边框及整体范围都处理temp1_binarize(data,row_bytes,width,height,True)temp2_binarize(bg,row_bytes,width,height,True)# AND运算跳过边框边框保持初始0值forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi# 下面能直接看到,只有两张图都是1的情况下,才置为白色.temp1[idx]255if(temp1[idx]1andtemp2[idx]1)else0forkinrange(len(data)):data[k]temp1[k]else:dib_widthrow_bytes temp1_binarize(data,row_bytes,None,height,False)temp2_binarize(bg,row_bytes,None,height,False)forjinrange(1,height-1):foriinrange(1,dib_width-1):idxj*dib_widthi# 下面能直接看到,只有两张图都是1的情况下,才置为白色.temp1[idx]255if(temp1[idx]1andtemp2[idx]1)else0forkinrange(len(data)):data[k]temp1[k]returnresult效果图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、水印叠加到一张大背景图上时defimage_or(img_src,img_bg): 图像或(OR)运算合成 参数与返回值同 image_add resultimg_src.clone()dataresult.data bgimg_bg.data widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:temp1_binarize(data,row_bytes,width,height,True)temp2_binarize(bg,row_bytes,width,height,True)forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi temp1[idx]0if(temp1[idx]0andtemp2[idx]0)else255forkinrange(len(data)):data[k]temp1[k]else:dib_widthrow_bytes temp1_binarize(data,row_bytes,None,height,False)temp2_binarize(bg,row_bytes,None,height,False)forjinrange(1,height-1):foriinrange(1,dib_width-1):idxj*dib_widthi temp1[idx]0if(temp1[idx]0andtemp2[idx]0)else255forkinrange(len(data)):data[k]temp1[k]returnresult效果图5.图像非运算合成原理先对图像各像素以阈值128进行二值化再对每个像素取逻辑非(NOT)。NOT规则 1 → 0 → 0黑 0 → 1 → 255白效果将亮区变暗、暗区变亮产生负片/反色效果常用于图像互补掩膜的生成、对比度反转defimage_not(img_src): 图像非(NOT)运算合成单图操作 参数 img_src - 源图像 返回 新BmpImage内容为NOT结果 resultimg_src.clone()dataresult.data is_gray(img_src.bit_count9)row_bytesimg_src.row_bytes heightimg_src.height# 8位图迭代到width24位图迭代到row_bytes逐通道字节col_endimg_src.widthifis_grayelserow_bytes temp_binarize(data,row_bytes,img_src.width,height,is_gray)# NOT运算跳过边框forjinrange(1,height-1):foriinrange(1,col_end-1):idxj*row_bytesi# 黑的变白,白的变黑temp[idx]255iftemp[idx]0else0forkinrange(len(data)):data[k]temp[k]returnresult效果图白的变黑,黑的变白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结果的互补图defimage_nor(img_src,img_bg): 图像或非(NOR)运算合成 参数与返回值同 image_add resultimg_src.clone()dataresult.data bgimg_bg.data widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:temp1_binarize(data,row_bytes,width,height,True)temp2_binarize(bg,row_bytes,width,height,True)# NOR两图都为0时才输出255其余为0forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi temp1[idx]255if(temp1[idx]0andtemp2[idx]0)else0forkinrange(len(data)):data[k]temp1[k]else:dib_widthrow_bytes temp1_binarize(data,row_bytes,None,height,False)temp2_binarize(bg,row_bytes,None,height,False)# 24位彩色NOR边框扩大到3字节1像素forjinrange(1,height-1):foriinrange(3,dib_width-3):idxj*dib_widthi temp1[idx]255if(temp1[idx]0andtemp2[idx]0)else0forkinrange(len(data)):data[k]temp1[k]returnresult效果图提取两张图共同的暗区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结果的互补图提取两图中不同时亮的区域-效果图defimage_nand(img_src,img_bg): 图像与非(NAND)运算合成 参数与返回值同 image_add resultimg_src.clone()dataresult.data bgimg_bg.data widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:temp1_binarize(data,row_bytes,width,height,True)temp2_binarize(bg,row_bytes,width,height,True)# NAND两图都为1时输出0其余为255forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi temp1[idx]0if(temp1[idx]1andtemp2[idx]1)else255forkinrange(len(data)):data[k]temp1[k]else:dib_widthrow_bytes temp1_binarize(data,row_bytes,None,height,False)temp2_binarize(bg,row_bytes,None,height,False)forjinrange(1,height-1):foriinrange(3,dib_width-3):idxj*dib_widthi temp1[idx]0if(temp1[idx]1andtemp2[idx]1)else255forkinrange(len(data)):data[k]temp1[k]returnresult效果图提取两图中不同时亮的区域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# ─────────────────────────────────────────────────────────defimage_xor(img_src,img_bg): 图像异或(XOR)运算合成 参数与返回值同 image_add resultimg_src.clone()dataresult.data bgimg_bg.data widthimg_src.width heightimg_src.height row_bytesimg_src.row_bytes is_gray(img_src.bit_count9)ifis_gray:temp1_binarize(data,row_bytes,width,height,True)temp2_binarize(bg,row_bytes,width,height,True)# XOR两者之和1 → 输入不同 → 255forjinrange(1,height-1):foriinrange(1,width-1):idxj*row_bytesi temp1[idx]255if(temp1[idx]temp2[idx]1)else0forkinrange(len(data)):data[k]temp1[k]else:dib_widthrow_bytes temp1_binarize(data,row_bytes,None,height,False)temp2_binarize(bg,row_bytes,None,height,False)forjinrange(1,height-1):foriinrange(3,dib_width-3):idxj*dib_widthi temp1[idx]255if(temp1[idx]temp2[idx]1)else0forkinrange(len(data)):data[k]temp1[k]returnresult-效果图提取两图亮暗不同的区域相同区域变黑