🥑Python_OpenCV(滤镜_深度传感器_特征匹配_视觉跟踪识别_分类)及其C++ArUco标记姿态计算

Python | OpenCV | 滤镜 | C++ | ArUco | 视觉跟踪识别 | 标记姿态

滤镜

创建黑白铅笔素描

为了获得相机框架的铅笔素描(即黑白图),我们将使用两种图像融合技术,即躲避和刻录。 这些术语是指在传统摄影的打印过程中使用的技术; 在这里,摄影师可以控制暗室照片某些区域的曝光时间,以使其变暗或变暗。 躲避使图像变亮,而刻录使图像变暗。 不应该进行更改的区域用掩膜保护。

如今,现代图像编辑程序(例如Photoshop和Gimp)提供了在数字图像中模拟这些效果的方法。 例如,掩模仍然被用来模仿改变图像的曝光时间的效果,其中具有相对强的值的掩模的区域将使图像更多地曝光,从而使图像变亮。 OpenCV不提供实现这些技术的本机功能。 但是,有了一点见识和一些技巧,我们将得出我们自己的有效实现,可以用来产生漂亮的铅笔素描效果。

如果在Internet上搜索,可能会偶然发现以下通用过程,从RGB(红色,绿色和蓝色)彩色图像中获得铅笔素描:

  1. 首先,将彩色图像转换为灰度。

  2. 然后,将灰度图像反转以获得负片。

  3. 将高斯模糊应用于步骤2中的负片。

  4. 通过使用彩色减淡功能,将灰度图像(来自步骤1)与模糊负片(来自步骤3)混合。

第1步到第3步很简单,而第4步可能有些棘手。 让我们先解决这个问题。

理解躲避和烧录

减淡可以减少我们希望在图像A中变得比以前更亮的图像区域的曝光。在图像处理中,我们通常选择或指定需要使用蒙版更改的图像区域。掩膜B是与可应用掩膜的图像尺寸相同的数组(可将其视为一张纸,用于覆盖其中有孔的图像)。 纸上的“孔”在不透明的区域中用零表示255(如果在0-1范围内,则用1表示)。

在诸如Photoshop之类的现代图像编辑工具中,通过使用下面的三元语句(使用索引i作用于每个像素)来实现图像A与掩膜B的颜色减淡:

((B[i] == 255) ? B[i] :
 min(255, ((A[i] << 8) / (255 - B[i]))))

前面的代码实质上是将A [i]图像像素的值除以B [i]掩膜像素值的倒数(范围为0-255),同时确保所得的像素值将为 (0,255)的范围,并且我们不除以0。

我们可以将先前看起来复杂的表达式或代码转换为以下朴素的Python函数,该函数接受两个OpenCV矩阵(图像和掩膜)并返回混合图像:

def dodge_naive(image, mask):
 # determine the shape of the input image
 width, height = image.shape[:2]
 # prepare output argument with same size as image
 blend = np.zeros((width, height), np.uint8)
 for c in range(width):
  for r in range(height):
  # shift image pixel value by 8 bits
  # divide by the inverse of the mask
  result = (image[c, r] << 8) / (255 - mask[c, r])
  # make sure resulting value stays within bounds
  blend[c, r] = min(255, result)
 return blend

正如您可能已经猜到的那样,尽管先前的代码在功能上可能是正确的,但毫无疑问,它会非常慢。 首先,该函数使用for循环,这在Python中几乎总是一个坏主意。 其次,NumPy数组(Python中OpenCV图像的基本格式)已针对数组计算进行了优化,因此分别访问和修改每个image [c,r]像素将非常慢。

相反,我们应该意识到<< 8运算与将像素值乘以$2^8$(= 256)相同,并且可以使用cv2.divide函数实现按像素划分。 因此,利用矩阵乘法(更快)的躲避函数的改进版本如下所示:

import cv2
def dodge(image, mask):
 return cv2.divide(image, 255 - mask, scale=256)

在这里,我们将躲避函数简化为一行! 新的躲避函数产生的结果与dodge_naive相同,但是它比朴素的版本快几个数量级。 除此之外,cv2.divide会自动处理零除,使结果为零,其中255-mask为零。

使用高斯模糊的优化版本

高斯模糊本质上是具有高斯函数的卷积。卷积的特征之一就是它们的关联属性。 这意味着我们先反转图像然后对其进行模糊处理,还是先模糊图像然后对其进行反转都没有关系。

如果我们从模糊的图像开始并将其逆传递给躲避函数,则在该函数内,图像将再次反转(255掩膜部分),实质上产生了原始图像。 如果我们摆脱了这些多余的操作,则经过优化的convert_to_pencil_sketch函数将如下所示:

def convert_to_pencil_sketch(rgb_image):
 gray_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2GRAY)
 blurred_image = cv2.GaussianBlur(gray_image, (21, 21), 0, 0)
 gray_sketch = cv2.divide(gray_image, blurred_image, scale=256)
 return cv2.cvtColor(gray_sketch, cv2.COLOR_GRAY2RGB)

为了形象化,我们想将转换后的图像(img_sketch)与背景图像(画布)轻轻混合,使其看起来就像我们在画布上绘制图像一样。 因此,在返回之前,我们想与画布混合(如果存在):

if canvas is not None:
 gray_sketch = cv2.multiply(gray_sketch, canvas, scale=1 / 256)

我们将最终函数命名为pencil_sketch_on_canvas,它看起来像这样(连同优化):

def pencil_sketch_on_canvas(rgb_image, canvas=None):
 gray_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2GRAY)
 blurred_image = cv2.GaussianBlur(gray_image, (21, 21), 0, 0)
 gray_sketch = cv2.divide(gray_image, blurred_image, scale=256)
 if canvas is not None:
 gray_sketch = cv2.multiply(gray_sketch, canvas, scale=1 / 256)
 return cv2.cvtColor(gray_sketch, cv2.COLOR_GRAY2RGB)

使用深度传感器的手势识别

通过特征匹配和透视变换查找对象

使用运动结构进行3D场景重建

OpenCV计算图像

视觉跟踪显着对象

识别交通信号

识别面部表情

对象分类和定位

检测和跟踪物体

源代码

🏈指点迷津 | Brief

Last updated