25 像素重映射 Image Remapping
像素重映射定义
- Remapping is the process of taking pixels from one place in the image and locating them in another position in a new image.
- To accomplish the mapping process, it might be necessary to do some interpolation for non-integer pixel locations, since there will not always be a one-to-one-pixel correspondence between source and destination images.
- 像素重映射:把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像。
- 把像素点 P(x, y)重新映射到一个心的位置 P’(x’, y’)
像素重映射函数
cv.remap(src, map1, map2, interpolation[, dst[, borderMode[, borderValue]]])->dst
- src 图像
- map1 表示x, y方向映射规则,或者x方向映射
- map2 如果map1表示x, y映射时为空,否则表示y
- 表示映射时候的像素插值方法
- 支持: INTER_NEAREST 最近邻插值
- INTER_LINEAR 双线性插值法 默认值
- INTER_CUBIC 双三次样条插值 过4x4像素领域内
- INTER_LANCZOS4 lanczos插值 过8x8像素领域内
- borderMode 图像边界处理方式
- BORDER_REPLICATE 重复 aaaaaa|abcdefgh|hhhhhhh
- BORDER_REFLECT 反射 fedcba|abcdefgh|hgfedcb
- BORDER_REFLECT_101 反射101 gfedcb|abcdefgh|gfedcba
- BORDER_WRAP 外包装 cdefgh|abcdefgh|abcdefg
- BORDER_CONSTANT 常量复制 iiiiii|abcdefgh|iiiiii i的值由后一个参数Scalar()确定,如Scalar::all(0) 默认值,表示目标图像中的“离群点”的像素值不会被此函数修改
- boderValue: 若上一参数为BORDER_CONSTANT,则由此参数确定补充上去的像素值,可选用默认值Scalar()即0
- 不同方式重映射像素
import cv2 as cv
import numpy as np
img = cv.imread("starry_night.jpg")
h, w, c = img.shape
cv.imshow("origin", img)
map_x = np.zeros((h, w), dtype=np.float32) #
map_y = np.zeros((h, w), dtype=np.float32)
# 倒立
for i in range(map_x.shape[0]):
map_x[i,:] = [x for x in range(map_x.shape[1])] # x方向保持不变
for j in range(map_y.shape[1]):
map_y[:,j] = [map_y.shape[0] - y for y in range(map_y.shape[0])] # y方向上下对调
dst = cv.remap(img, map_x, map_y, cv.INTER_LINEAR)
cv.imshow("upsidedown", dst)
#镜像
for i in range(map_x.shape[0]):
map_x[i,:] = [map_x.shape[1] - x for x in range(map_x.shape[1])] # x方向上下对调
for j in range(map_y.shape[1]):
map_y[:,j] = [y for y in range(map_y.shape[0])] # y方向保持不变
dst = cv.remap(img, map_x, map_y, cv.INTER_LINEAR)
cv.imshow("mirror", dst)
# 对角线对称
for i in range(map_x.shape[0]):
map_x[i,:] = [map_x.shape[1] - x for x in range(map_x.shape[1])] # x方向上下对调
for j in range(map_y.shape[1]):
map_y[:,j] = [map_y.shape[0] - y for y in range(map_y.shape[0])] # y方向上下对调
dst = cv.remap(img, map_x, map_y, cv.INTER_LINEAR)
cv.imshow("diagonal", dst)
cv.waitKey(0)
cv.destroyAllWindows()
26 图像二值化 Image Binarization
- 传统的机器视觉通常包括两个步骤:预处理和物体检测。而沟通二者的桥梁则是图像分割 image segmentation。图像分割通过简化或改变图像的表示形式,使得图像更易于分析。
- 最简单的图像分割方法是 二值化
图像二值化定义
- 就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果的过程
- 只有两个像素值 0- 表示黑色,1(1~255) - 表示白色
- 前景与背景描述,黑色表示背景,白色表示对象
- 在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,可以进行高度的压缩,节省存储空间,从而能凸显出目标的轮廓
- 由于二值图像数据足够简单,许多视觉算法都依赖二值图像。通过二值图像,能更好地分析物体的形状和轮廓。二值图像也常常用作原始图像的掩模(又称遮罩、蒙版,Mask):它就像一张部分镂空的纸,把我们不感兴趣的区域遮掉。进行二值化有多种方式,其中最常用的就是采用**阈值法(Thresholding)**进行二值化。
图像二值化方法
- inRange
- cv.mean,计算灰度图像均值m
二值化函数
cv.threshold(src, thresh, maxval, type[, dst])->retval, dst
- src 输入图像,图像只能是CV_8U和CV_32F两种数据类型
- thresh 表示阈值
- maxval 表示最大值,它只在THRESH_BINARY 和 THRESH_BINARY_INV两种二值化方法中使用
- type 表示二值化方式
- THRESH_BINARY 0 >阈值改为255,<阈值改为0
- THRESH_BINARY_INV 1 >阈值改为0,<阈值改为255
- THRESH_TRUNC 2 截断,>阈值改为阈值,<阈值不变
- THRESH_TOZERO 3 >阈值不改变,<阈值改为0
- THRESH_TOZERO_INV 4 >阈值改为0,<阈值不改变
- THRESH_OTSU 8 大津法自动寻求全局阈值
- THRESH_TRIANGLE 16 三角法自动寻求全局阈值
- retval 表示返回阈值,dst返回二值图像,与输入图像具有相同的尺寸、数据类型和通道数
27 全局与自适应二值化
全局二值化
- 大津法 Otsu Method: 也叫全局最优阈值处理、最大类间方法差,使用聚类思想,将图像分为前景与背景两类。0~5六个灰度级别,根据直方图分布,以每个灰度等级分割直方图分布为两个部分,分别求取均值跟方差,如图示,最小方法差和对应的灰度值为,分割阈值
- 只需对大津算法稍加扩展也可以完成。对大津算法的多级推广成为多大津算法(multi Otsu method)
- 三角法 Triangle求阈值最早见于Zack的论文《Automatic measurement of sister chromatid exchange frequency》主要是用于染色体的研究,该方法是使用直方图数据,基于纯几何方法来寻找最佳阈值,它的成立条件是假设直方图最大波峰在靠近最亮的一侧,然后通过三角形求得最大直线距离,根据最大直线距离对应的直方图灰度等级即为分割阈值
全局二值化函数
cv.threshold(src, thresh, maxval, type[, dst])->retval, dst
- type 表示二值化
- 不同的全局二值化方法
- THRESH_BINARY | THRESH_OTSU
- THRESH_BINARY | THRESH_TRIANGLE
- THRESH_BINARY_INV | THRESH_OTSU
使用一个全局值作为阈值。但是在所有情况下这可能都不太好。如果图像在不同区域具有不同的照明条件。在这种情况下,自适应阈值阈值可以帮助。
自适应二值化 Adaptive Binarization
- 局部阈值 Local Method 又称自适应阈值
- 有一种改进的阈值处理技术,其使用变化的阈值完成对图像的阈值处理,这种技术被称为自适应阈值处理。在进行阈值处理时,自适应阈值处理的方式通过计算每个像素点周围临近区域的加权平均值获得阈值,并使用该阈值对当前像素点进行处理
- X先对图像做模糊处理,模糊图像-D (可以为 均值模糊/高斯模糊)
- 原图 S + 偏置常量C,用原图与模糊处理之后的图像做差得到一幅图像
- T = S - D > -C ? 255 : 0,判断图像的每一个像素是否大于指定的阈值(C),如果大于则设置为指定的数值(255),否则设置为0。
自适应二值化函数
cv.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst])->dst
- maxValue:满足条件的像素所分配的非零值
- adaptiveMethod:要使用的自适应阈值算法:
- cv.ADAPTIVE_THRESH_MEAN_C 均值模糊
- cv.ADAPTIVE_THRESH_GAUSSIAN_C 高斯模糊
- thresholdType:阈值类型,必须是THRESH_BINARY或者THRESH_BINARY_INV,指示要提取亮区域还是暗区域
- blockSize 必须为奇数,用于计算像素阈值的像素邻域的大小
- C 表示要减去的权重,偏移值调整量,从每个邻域计算出的平均值或高斯加权平均值中减去的常量,就是最终阈值,可以是正数、负数、0
import cv2 as cv
import numpy as np
img = cv.imread("starry_night.jpg")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)
# 大津法
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow("otsu", binary)
# 三角法
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)
cv.imshow("triangle", binary)
# 自适应法
binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 25, 10)
cv.imshow("adaptive", binary)
cv.waitKey(0)
cv.destroyAllWindows()
28 实时人脸检测
OpenCV4 DNN模块 深度神经网络Deep Neural Network
- 来自另外一个开源项目 tiny dnn
- OpenCV3.3正式发布
- 最新版本 OpenCV 4.5.5
- 支持后台硬件加速机制 CPU/GPU 等
- 支持多种任务
- 图像分类;
- 目标检测;
- 图像分割;
- 文字检测和识别;
- 姿态估计;
- 深度估计
- 人脸验证和检测;
- 人体重新识别;
OpenCV DNN模块功能
- 只支持推理(部署),不支持训练
- 支持主流的深度学习框架生成模型,而且OpenCV在载入模型时会使用自己的DNN模型对模型重写,使得模型的运行效率更高
- 推荐使用 pytorch/tensorflow
OpenCV人脸检测支持演化
- OpenCV3.3之前基于 HAAR/LBP 级联检测
- OpenCV3.3开始支持深度学习人脸检测
- 支持人脸检测模型 caffe/tensorflow
- 模型下载地址 https://gitee.com/opencv_ai/opencv_tutorial_data
- OpenCV 的DNN模块中的 一个非常厉害之处就是针对Intel处理器进行了高度优化。在目标检测和图像分割应用中,对于实时视频图像进行模型推理的过程中可以获得很好的处理帧速(FPS)。通过DNN模块使用特定框架下预训练模型经常会得到更高的FPS。
DNN相关函数
- 读取模型: readNetFromTensorflow
readNetFromTensorflow (model[, config])
- model .pb文件的路径,这里是带有网络架构的二进制protobuf,包含经过训练的权重,对于来自不同框架的模型需要使用不同的文件拓展名
- config 包含protobuf的文本图定义的.pbtxt文件路径- config文本文件包含网络配置,针对不同的框架也有不同的拓展名。
- .caffemodel:caffe框架;.prototxt;
- .pb:tensorflow框架;.pbtxt;
- .weights:Darknet框架;.cfg;
- .t7:torch框架;
- .bin:DLDT框架。.xml
- config文本文件包含网络配置,针对不同的框架也有不同的拓展名。
- 转换为blob对象: blobFromImage
cv.dnn.blobFromImage(image[, scalefactor[, size[, mean[, swapRB[, crop[, ddepth]]]]]]) ->retval
- image:输入图像(1、3或者4通道)
- scalefactor:图像各通道数值的缩放比例
- size:输出图像的空间尺寸,如size=(200,300)表示高h=300,宽w=200
- mean:用于各通道减去的值,以降低光照的影响(e.g. image为bgr3通道的图像,mean=[104.0, 177.0, 123.0],表示b通道的值-104,g-177,r-123)
- swapRB:交换RB通道,默认False.(cv2.imread读取的是彩图是BGR通道)
- crop:图像裁剪,默认False.当=True时,先按比例缩放,然后从中心裁剪成size尺寸
- ddepth:输出的图像深度,可选CV_32F 或者 CV_8U
- 当同时进行scalefactor,size,mean,swapRB操作时,优先按swapRB交换通道,其次按scalefactor比例缩放,然后按mean求减,最后按size进行resize操作
- 当进行减均值操作时,ddepth不能选取CV_8U,否则报错
- 当crop=True时,先等比例缩放,直至宽高尺寸一个等于对应的size尺寸,另一个大于或者等于对应的size尺寸,然后再从中心进行裁剪
- retval 4维数组 - 设置输入: setInput
cv.dnn.Net.setInput(blob[, name[, scalefactor[, mean]]]) ->None
- blob CV_32F或是CV_8U
- name input层的名字
- scalefactor 标准化比例
- mean 平均减法值 - 推理预测: forward
cv.dnn.Net.forward([, outputBlobs[, outputName]]) ->outputBlobs
人脸检测显示
- 模型输入: 1x3x300x300
- 模型输出: 1xNx7
- 人脸检测框 - 最后四个
- 预测置信度 - 第三个
- 推理时间与帧率