OpenCV笔记3-图像修复
图像修复
图像修复是计算机视觉中的一类算法,其目标是填充图像或视频内的区域。该区域使用二进制掩模进行标识,填充通常根据需要填充的区域边界信息来完成。图像修复的最常见应用是恢复旧的扫描照片。图像修复不仅可以去除图像中得“划痕”,它还用于删除图像中的小的不需要的对象(去除图像中得水印、日期等)。
OpenCV 实现了两种修复算法:
- “一种基于快速行进法的图像修复技术”,Alexandru Telea,2004: 这是基于快速行进法(FMM)。查看要修复的区域,该算法首先从边界像素开始,然后到达边界内的像素。它用背景中像素的加权和替换每个要修复的像素,将更多的权重赋予更近的像素和边界像素。
- “纳维尔-斯托克斯,流体动力学,图像和视频修复”,贝尔塔米奥,马塞洛,安德里亚·l·贝尔托齐和吉列尔莫·萨皮罗,2001: 该算法受偏微分方程的启发。从边缘(已知区域)开始向未知区域传播等照度线(连接同强度点的线)。最后,区域中的变化被最小化以填充颜色。
Image Inpainting with OpenCV (C++/Python) | LearnOpenCV #
理论可以看看这篇。
dst = cv2.inpaint(src, inpaintMask, inpaintRadius, flags)来实现修复图像,
参数含义:
src:源图像,也就是需要修复的图像
inpaintMask:二进制掩码,指示要修复的像素。
dst:结果图像
inpaintRadius:表示修复的半径
flags : 修复算法
import cv2
import rclpy
from rclpy.node import Node
import numpy as np
from ament_index_python.packages import get_package_share_directory #获取shares目录绝对路径
class OpenCVNode(Node):
def readImg(self,img_name: str):
default_image_path = get_package_share_directory('yahboom_esp32ai_car')+'/resource/'
self.get_logger().info(f'打开图片:{default_image_path}')
dam_img = cv2.imread(default_image_path+img_name)
#mask = np.zeros((height,width,1),np.uint8)
#灰度
gray = cv2.cvtColor(dam_img,cv2.COLOR_BGR2GRAY)
#2值化
_,mask = cv2.threshold(gray,150,255,cv2.THRESH_BINARY_INV)
#
# kernel_3X3 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))#构造卷积核
# mask_after_open = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_3X3)#形态学
dst_fmm = cv2.inpaint(src=dam_img, inpaintMask=mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA)
dst_ns = cv2.inpaint(dam_img,mask,10,cv2.INPAINT_NS)
cv2.imshow('dam_img',dam_img)
cv2.imshow('paint',mask)
cv2.imshow('Inpaint Output using FMM', dst_fmm)
cv2.imshow('Inpaint Output using ns',dst_ns)
cv2.waitKey(0)
def main():
rclpy.init()
node = OpenCVNode('opencvNode')
node.readImg('d3.jpg')
rclpy.spin(node)
rclpy.shutdown()
我自己测试了下,关键是掩模的生成,算法效果区别不大。简单图像对比明显的效果好,背景复杂的干扰项效果较差。效果好的:
效果不好的修复
图片亮度增强
简单来说就是调整rgb的值。可以看看大佬们写的专业分析
8、OpenCV调整图像对比度和亮度_照片对比度csdn-CSDN博客
import cv2
import rclpy
from rclpy.node import Node
import numpy as np
import math
from ament_index_python.packages import get_package_share_directory #获取shares目录绝对路径
class OpenCVNode(Node):
def readImg(self,img_name: str):
default_image_path = get_package_share_directory('yahboom_esp32ai_car')+'/resource/'
self.get_logger().info(f'打开图片:{default_image_path}')
img = cv2.imread(default_image_path+img_name)
gamma_val = 0.5
#gamma
gamma_table = [np.power(x / 255.0, gamma_val) * 255.0 for x in range(256)] # 建立映射表
gamma_table = np.round(np.array(gamma_table)).astype(np.uint8) # 颜色值为整数
img_gamma = cv2.LUT(img, gamma_table) # 图片颜色查表。另外可以根据光强(颜色)均匀化原则设计自适应算法。
#
cv2.imshow('img',img)
cv2.imshow('img_gamma',img_gamma)
cv2.waitKey(0)
def main():
rclpy.init()
node = OpenCVNode('opencvNode')
node.readImg('20.jpg')
rclpy.spin(node)
rclpy.shutdown()
当然这里还有很多细节参数的,直接调整过大,图片处理不好容易过曝。
效果如下:
图片磨皮
磨皮算法的核心就是让皮肤区域的像素变得平滑,过渡自然,让皮肤看起来十分光滑。
我大概在网上搜了下,效果好一些的大佬主要包含了两部分:滤波算法、皮肤区域检测、肤色提取等。这个比较复杂,因为不加区域的话,过滤完图片很多细节会丢失,所以需要指定区域去美化效果才好。
这里就先测试下opencv的单个函数,没有深入学习。简单了解下:双边滤波(Bilateral filter)
是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点。双边滤波优点:对边缘信息有较好的保留,缺点:不能较好的消除噪声
推荐几个大佬写的,可以对比下大佬的效果:
https://zhuanlan.zhihu.com/p/407017507 这篇讲理论
[Opencv基础]人脸磨皮_cv 磨皮算法-CSDN博客
我的这个磨皮测试图片也是用的这个,明显还是大佬的专业,效果好,推荐大家看看。
void bilateralFilter( InputArray src,
OutputArray dst,
int d,
double sigmaColor,
double sigmaSpace,
int borderType = BORDER_DEFAULT );
参数:
- 第一个参数,InputArray类型的src,输入图像,即源图像,需要为8位或者浮点型单通道、三通道的图像。
- 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
- 第三个参数,int类型的d,表示在过滤过程中每个像素邻域的直径。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。
- 第四个参数,double类型的sigmaColor,颜色空间滤波器的sigma
- 。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
- 第五个参数,double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。
- 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
import cv2
import rclpy
from rclpy.node import Node
import numpy as np
import math
from ament_index_python.packages import get_package_share_directory #获取shares目录绝对路径
class OpenCVNode(Node):
def readImg(self,img_name: str):
default_image_path = get_package_share_directory('yahboom_esp32ai_car')+'/resource/'
self.get_logger().info(f'打开图片:{default_image_path}')
img = cv2.imread(default_image_path+img_name)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 进行离散傅里叶变换
#dft = cv2.dft(np.float32(gray), flags=cv2.DFT_COMPLEX_OUTPUT)
kernel = np.ones((3,3),np.float32)
kernel = kernel/9.
# 使用高斯滤波器对频域图像进行滤波
#blurred = cv2.GaussianBlur(img, (3, 3), 0)
smoothed = cv2.bilateralFilter(img, 10, 30, 30)
cv2.imshow('img',img)
cv2.imshow('smoothed',smoothed)
cv2.waitKey(0)
def main():
rclpy.init()
node = OpenCVNode('opencvNode')
node.readImg('9.jpg')
rclpy.spin(node)
rclpy.shutdown()
效果如下: