【Open CV图像处理】修改运算与平滑处理
目录图像修改图片打码图片组合图片缩放图像运算图片加法cv2.add运算图片加权运算阈值处理图像平滑处理椒盐噪声生成滤波处理均值滤波方框滤波高斯滤波中值滤波视频平滑处理作业一、图像修改图片打码import cv2 import numpy as np # 图片打码 a cv2.imread(r./xin.jpg) xxx np.random.randint(0, 256, (3, 3)) print(xxx) a[100:200, 200:300] np.random.randint(0, 256, (100, 100, 3)) cv2.imshow(masaike, a) cv2.waitKey(0) cv2.destroyAllWindows()1. 图片本质是三维numpy数组(高度, 宽度, 3个RGB通道)可通过数组切片直接修改像素。2. 切片语法a[高度起始:高度结束, 宽度起始:宽度结束]对应图片的矩形区域。3. np.random.randint(0,256,(h,w,3))生成0~255的随机像素值模拟马赛克效果。注意赋值的数组大小必须完全匹配切片区域的大小切片100:200 高度共 100行200:300 宽度共 100列随机数组必须是 (100,100,3)行列数量不一致会直接报错。运行效果图片组合# 图片组合 a cv2.imread(xin.jpg) b cv2.imread(o.png) b[200:350, 200:350] a[50:200, 100:250] cv2.imshow(b, b) cv2.imshow(a, a) cv2.waitKey(0) cv2.destroyAllWindows()1. 图片像素可以跨图片复制粘贴将一张图的像素区域直接赋值给另一张图的区域。2. 原理OpenCV图片均为numpy数组数组之间支持直接赋值操作。注意两张图片的切片区域尺寸必须严格一致行列数量不匹配会直接报错。运行效果图片缩放# 图片缩放 a cv2.imread(xin.jpg) # 写法1直接指定宽高缩放 a_new cv2.resize(a, dsize(600,200)) # 写法2按比例缩放fx宽比例、fy高比例 # a_new cv2.resize(a, None, fx1.5, fy0.5) cv2.imshow(a,a) cv2.imshow(a_new,a_new) cv2.waitKey(0) cv2.destroyAllWindows()两个核心使用方式方式1dsize(宽度, 高度)直接指定输出图片的宽高方式2fx、fy 缩放系数fx1.5代表宽度放大1.5倍fy0.5代表高度缩小一半注意1. dsize 格式为 (宽, 高)与图片数组(高,宽)顺序相反容易写反。2. 两种缩放方式二选一指定dsize后fx/fy会自动失效。3. 缩小图片会丢失细节放大图片会产生模糊无法还原原始清晰度。运行效果二、图像运算图片加法import cv2 # 图像加法运算:当某位置像素相加得到的数值大于255时将该位置数值相加结果阶段减去256例如相加后得到260实际是260-2564 a cv2.imread(mimi.jpg) b cv2.imread(xin_new.jpg) c a100 cv2.imshow(yuan, a) cv2.imshow(a10, c) cv2.waitKey(0) c a[50:450, 50:450]b[50:450, 50:450] cv2.imshow(ab, c) cv2.waitKey(0)1. 像素和 255结果 两像素直接相加2. 像素和 255执行取模运算循环截断公式结果 总和 - 256例260 → 260-256 4注意他的本质是 numpy 数组运算遵循 uint8 类型的循环溢出规则两张图片相加时参与运算的区域尺寸必须完全一致否则直接报错运行效果cv2.add运算# cv2.add()运算规则当某位置像素相加得到的数字大于255时该位置数值为255 a cv2.imread(mimi.jpg) b cv2.imread(xin_new.jpg) b cv2.resize(b, (400, 400)) a cv2.resize(a, (400, 400)) c cv2.add(a, b) cv2.imshow(a add b, c) cv2.waitKey(0) cv2.destroyAllWindows()1. 像素和 255结果 两像素直接相加2. 像素和 255执行饱和截断直接固定最大值为255注意1. 他与 运算最大区别是溢出后不会归零直接保持纯白2552. 两张图片宽高必须完全一致否则运算直接报错3. 专门用于图像融合是OpenCV官方推荐的加法方式运行效果图片加权运算# 图像加权运算:计算两张图片的像素值之和将每张图的权重都考虑进来公式c像素a像素×α权重b像素×β权重γ偏移量/变亮变暗 a cv2.imread(mimi.jpg) b cv2.imread(xin_new.jpg) b cv2.resize(b, (400, 400)) a cv2.resize(a, (400, 400)) c cv2.addWeighted(a, 0.5, b, 0.4, 10) cv2.imshow(addWeighed, c) cv2.waitKey(0) cv2.destroyAllWindows()公式dst src1 × α src2 × β γalpha(α)第一张图的权重系数透明度0~1之间beta(β)第二张图的权重系数透明度0~1之间gamma(γ)全局亮度偏移值给整张融合图片统一提亮/压暗注意1. 同样要求两张图片尺寸完全一致2. 权重之和 alphabeta 通常设为1保证亮度均衡大于1画面会整体变亮3. gamma为最终提亮值正数提亮、负数压暗是调整画面明暗的常用参数运行效果阈值处理剔除图像内像素值高于/低于设定阈值的像素点实现图像二值分割黑白区分。标准函数格式retval, dst cv2.threshold(src, thresh, maxval, type)1. src需要做阈值分割的图像必须先转为灰度图代码中 flags0 就是读取灰度图2. thresh手动设定的分割阈值3. maxval像素超过阈值时填充的最大值4. type阈值分割的5种类型返回值retval最终生效的阈值手动设置时和thresh一致自动阈值算法才会变化dst阈值处理后的结果图像阈值类型像素值 175其他情况≤175含义cv2.THRESH_BINARY设为maxval(255)纯白设为0纯黑标准二值化亮部变白暗部变黑cv2.THRESH_BINARY_INV设为0纯黑设为maxval(255)纯白反二值化亮部变黑暗部变白cv2.THRESH_TRUNC固定为阈值175保持原灰度值高光截断超过阈值的像素统一变暗画面呈现灰调cv2.THRESH_TOZERO保持原灰度值设为0纯黑暗部抑制低于阈值的像素变黑亮部保持不变cv2.THRESH_TOZERO_INV设为0纯黑保持原灰度值亮部抑制高于阈值的像素变黑暗部保持不变import cv2 image cv2.imread(zl.png, 0) ret, binary cv2.threshold(image, 175, 255, cv2.THRESH_BINARY) ret1, binaryinv cv2.threshold(image, 175, 255, cv2.THRESH_BINARY_INV) ret2, trunc cv2.threshold(image, 175, 255, cv2.THRESH_TRUNC) ret3, tozero cv2.threshold(image, 175, 255, cv2.THRESH_TOZERO) ret4, tozeroinv cv2.threshold(image, 175, 255, cv2.THRESH_TOZERO_INV) cv2.imshow(gray, image) cv2.waitKey(0) cv2.imshow(binary, binary) cv2.waitKey(0) cv2.imshow(binaryinv, binaryinv) cv2.waitKey(0) cv2.imshow(trunc, trunc) cv2.waitKey(0) cv2.imshow(tozero, tozero) cv2.waitKey(0) cv2.imshow(tozeroinv, tozeroinv) cv2.waitKey(0)1. 强制灰度图threshold 函数只能接收单通道灰度图彩色图必须先转灰度否则直接报错2. maxval仅2种模式生效只有 BINARY / BINARY_INV 会用到maxval另外3种类型该参数无效3. 像素取值范围所有阈值处理基于 0~255 的uint8像素值超出范围会直接截断运行效果三、图像平滑处理椒盐噪声生成给图片添加椒盐噪声黑白随机噪点1. 定义生成椒盐噪点的函数2. 读取原图并显示3. 调用函数生成带噪点的图片4. 显示带噪点的图片import cv2 import numpy as np # 导入OpenCV图像处理库与数值计算库是所有OpenCV项目的基础依赖。 # 定义【椒盐噪声生成函数】 def add_peppersalt_noise(image, n10000): # 复制原图避免直接修改原始图片 result image.copy() # 获取图片的高度、宽度shape[:2]只取前两个维度排除RGB通道 h, w image.shape[:2] # 循环n次生成n个随机噪点 for i in range(n): # 随机生成x坐标纵向0 ~ 图片高度h之间 x np.random.randint(0, h) # 随机生成y坐标横向0 ~ 图片宽度w之间 y np.random.randint(0, w) # 50%概率生成黑点50%概率生成白点 if np.random.randint(0, 2) 0: result[x, y] 0 # 0 纯黑色胡椒噪点 else: result[x, y] 255 # 255 纯白色盐粒噪点 # 返回添加完噪点的图片 return result函数核心知识点1. 椒盐噪声定义0 → 黑色胡椒噪点255 → 白色盐粒噪点2. 参数n10000噪点的总数量数值越大噪点越密集画面越模糊。3. image.copy()复制原图操作核心原则绝对不能直接修改原始图片。4. np.random.randint(0,2)随机生成0或1保证黑白噪点的生成概率各占一半。# 读取原始图片 image cv2.imread(xin_new.png) # 显示原图 cv2.imshow(yntu, image) cv2.waitKey(0) # 等待按键不按则窗口一直停留 # 调用函数给图片添加椒盐噪点 noise add_peppersalt_noise(image) # 显示添加噪点后的图片 cv2.imshow(noise, noise) cv2.waitKey(0)注意1. 彩色图兼容该函数可直接用于彩色图片代码会自动给3个RGB通道同时添加黑白噪点无需额外修改。2. 噪点数量调整n5000轻微噪点n10000常规密度噪点当前代码默认值n50000重度噪点画面会严重受损滤波处理均值滤波blur_1 cv2.blur(noise, (3, 3)) cv2.imshow(blur_1, blur_1) cv2.waitKey(0) blur_2 cv2.blur(noise, (63, 63)) cv2.imshow(blur_2, blur_2) cv2.waitKey(0)1. 参数 (3,3)卷积核大小代表取周围3×39个像素求平均值替换中心像素2. 原理邻域所有像素取平均值让整体画面模糊平滑3. 两组对比效果(3,3)小卷积核轻微模糊能去除部分噪点(63,63)大卷积核画面极度模糊丢失大量细节去除噪声效果差只能弱化噪点无法彻底清除画面会整体发糊。效果展示方框滤波boxFilter_1 cv2.boxFilter(noise, -1, (3,3), normalize True) cv2.imshow(boxFilter_1,boxFilter_1) cv2.waitKey(0) boxFilter_2 cv2.boxFilter(noise, -1, (3,3), normalize False) cv2.imshow(boxFilter_2,boxFilter_2) cv2.waitKey(0)1. -1输出图像深度固定写 -1 即可代表和原图格式保持一致2. (3,3)卷积核大小和均值滤波完全一致3. normalizeTrue 归一化求和后÷像素数量结果和 cv2.blur 均值滤波一模一样False 不归一化直接累加所有像素值数值极易超过255画面会变成几乎纯白色方框滤波本质是均值滤波的通用版仅归一化模式有实际使用价值。高斯滤波GaussianB cv2.GaussianBlur(noise, (3,3), sigmaX1) cv2.imshow(GaussianBlur,GaussianB) cv2.waitKey(0)1. 原理距离中心越近的像素权重越高模拟人眼观察效果模糊效果更自然2. 参数 sigmaX1X方向高斯标准差数值越大模糊程度越强去噪效果优于均值滤波画面不会出现生硬的方块模糊但对椒盐噪声的去除效果依旧一般仅能弱化噪点无法彻底清除中值滤波medianB cv2.medianBlur(noise, 3) cv2.imshow(medianBlur,medianB) cv2.waitKey(0) cv2.destroyAllWindows()1. 参数 3卷积核尺寸必须是奇数3、5、7……2. 原理取3×3邻域内所有像素的中间值直接剔除0和255的极值噪点去除椒盐噪声效果最好能直接清除黑白噪点画面保留细节不会像均值滤波一样整体严重发糊效果展示视频平滑处理作业给定一个视频文件‘test.avi’要求完成以下操作1、使其每一帧画面都随机生成10000个黑白点椒盐噪声添加噪声效果2、然后选择合适的图像平滑处理方法处理每一帧画面消除噪声的同时尽可能使原画面清晰3、同时弹出三个窗口分别展示原视频、含有噪声的视频、平滑处理后的视频。代码实现import cv2 import numpy as np def add_peppersalt_noise(image, n10000): result image.copy() h, w image.shape[:2] for i in range(n): x np.random.randint(0, h) y np.random.randint(0, w) if np.random.randint(0, 2) 0: result[x, y] 0 else: result[x, y] 255 return result video_capture cv2.VideoCapture(test.avi) if not video_capture.isOpened(): print(无法打开视频文件) exit() while True: ret, frame video_capture.read() if not ret: break noise_frame add_peppersalt_noise(frame, n10000) medianB_frame cv2.medianBlur(noise_frame, 3) cv2.imshow(yuan Video, frame) cv2.imshow(Noise Video, noise_frame) cv2.imshow(medianB Video, medianB_frame) if cv2.waitKey(100) 27: break video_capture.release() cv2.destroyAllWindows()代码解读整体逻辑流程1. 定义函数给单张图片添加椒盐黑白噪点2. 打开视频文件循环读取每一帧画面3. 给每一帧视频画面添加噪点4. 使用中值滤波去除椒盐噪点5. 同时显示「原图、带噪视频、去噪后视频」三个窗口对比效果6. 按下ESC键结束程序第一部分椒盐噪声生成函数import cv2 import numpy as np # 定义椒盐噪声生成函数 def add_peppersalt_noise(image, n10000): # 复制原图绝对不修改原始图片 result image.copy() # 获取图片高度、宽度只取前两个维度排除RGB通道 h, w image.shape[:2] # 循环n次生成n个随机噪点 for i in range(n): # 随机生成纵向坐标x0 ~ 图片高度之间 x np.random.randint(0, h) # 随机生成横向坐标y0 ~ 图片宽度之间 y np.random.randint(0, w) # 50%概率生成黑点50%概率生成白点 if np.random.randint(0, 2) 0: result[x, y] 0 # 0 纯黑色胡椒噪点 else: result[x, y] 255 # 255 纯白色盐粒噪点 return result第二部分视频读取 逐帧处理逻辑# 打开视频文件test.avi video_capture cv2.VideoCapture(test.avi) # 判断视频是否成功打开 if not video_capture.isOpened(): print(无法打开视频文件) exit() # 无限循环读取视频每一帧 while True: # 读取一帧画面ret是否读取成功frame当前帧图片 ret, frame video_capture.read() # 视频播放完毕跳出循环结束 if not ret: break # 1. 给当前帧添加椒盐噪点 noise_frame add_peppersalt_noise(frame, n10000) # 2. 中值滤波去除椒盐噪点3×3卷积核去噪最优方案 medianB_frame cv2.medianBlur(noise_frame, 3) # 三个窗口同步显示实时对比效果 cv2.imshow(yuan Video, frame) # 原始干净视频 cv2.imshow(Noise Video, noise_frame) # 布满黑白噪点的视频 cv2.imshow(medianB Video, medianB_frame) # 中值滤波去噪后的视频 # 按下ESC键按键码27退出循环 if cv2.waitKey(100) 27: break # 释放视频资源关闭所有窗口 video_capture.release() cv2.destroyAllWindows()cv2.VideoCapture(test.avi)打开视频视频本质就是连续播放的图片帧while True 循环一帧一帧读取视频画面逐帧处理关键执行顺序原图帧 → 添加椒盐噪点 → 中值滤波去噪处理顺序不能颠倒中值滤波去除椒盐噪点的效果最好必须先生成噪点再去噪卷积核尺寸必须是奇数3、5、7……偶数会直接报错waitKey(100)控制视频播放速度数值越大播放越慢视频读取完毕后会自动结束循环不会卡死程序运行展示