python opencv 4.1.0 cv2.convertScaleAbs()函数 (通过线性变换将数据转换成8位[uint8])(用于Intel Realsense D435显示depth图像)

API文档

def convertScaleAbs(src, dst=None, alpha=None, beta=None): # real signature unknown; restored from __doc__
    """
    convertScaleAbs(src[, dst[, alpha[, beta]]]) -> dst
    .   @brief Scales, calculates absolute values, and converts the result to 8-bit.
    	缩放,计算绝对值,然后将结果转换为8位。
    .   
    .   On each element of the input array, the function convertScaleAbs
    .   performs three operations sequentially: scaling, taking an absolute
    .   value, conversion to an unsigned 8-bit type:
    	在输入数组的每个元素上,函数convertScaleAbs依次执行三个操作:缩放,获取绝对值,转换为无符号的8位类型:
    	
    .   \f[\texttt{dst} (I)= \texttt{saturate\_cast<uchar>} (| \texttt{src} (I)* \texttt{alpha} +  \texttt{beta} |)\f]
    
    .   In case of multi-channel arrays, the function processes each channel
    .   independently. When the output is not 8-bit, the operation can be
    .   emulated by calling the Mat::convertTo method (or by using matrix
    .   expressions) and then by calculating an absolute value of the result.
		如果是多通道阵列,该函数将独立处理每个通道。 
		当输出不是8位时,可以通过调用Mat :: convertTo方法(或使用矩阵表达式),
		然后通过计算结果的绝对值来模拟该操作。
		
    .   For example:
    .   @code{.cpp}
    .   Mat_<float> A(30,30);
    .   randu(A, Scalar(-100), Scalar(100));
    .   Mat_<float> B = A*5 + 3;
    .   B = abs(B);
    .   // Mat_<float> B = abs(A*5+3) will also do the job,
    .   // but it will allocate a temporary matrix
    .   @endcode
    .   @param src input array. 输入数组。
    .   @param dst output array. 输出数组。
    .   @param alpha optional scale factor. 可选比例因子。
    .   @param beta optional delta added to the scaled values. 可选增量添加到缩放值。
    .   @sa  Mat::convertTo, cv::abs(const Mat&)
    """
    pass

代码示例:Intel Realsense图像的两种对齐方式

cv.convertScaleAbs(depth_image, alpha=0.03)

假设我们需要让我们的深度摄像头感兴趣的距离范围有差别地显示,那么我们就需要确定一个合适的alpha值,公式为:有效距离*alpha=255,假设我们想让深度摄像头8m距离内的深度被显示,>8m的与8m的颜色显示相同,那么alpha=255/(8*10^3)≈0.03,假设我们想让深度摄像头6m距离内的深度被显示,>6m的与6m的颜色显示相同,那么alpha=255/(6*10^3)≈0.0425cv.convertScaleAbs()函数对输入数组进行如下运算:
在这里插入图片描述
对于输入深度图数组中的每个值srci(它是16位的,数据类型是uint16),先乘以系数α,再加上偏置β,最后将结果取绝对值,并截取为8位(uint8),然后返回与原数组相同维度的数组dsti。

验证猜想

猜测如果计算后的值大于255,则将其取为255(8位最大值)。

import numpy as np
import cv2 as cv
depth_image=np.array([[1000,2,3],[8000,-8000,6],[-1000,8,9]])
print('depth_image:\n',depth_image)
depth_image_map=cv.convertScaleAbs(depth_image,alpha=0.03,beta=100)
print('depth_image_map:\n',depth_image_map)

结果:

depth_image:
 [[ 1000     2     3]
 [ 8000 -8000     6]
 [-1000     8     9]]
depth_image_map:
 [[130 100 100]
 [255 140 100]
 [ 70 100 100]]

验证结果正确!

完整示例代码

import pyrealsense2 as rs
import cv2 as cv
import numpy as np

pipeline = rs.pipeline()

cfg = rs.config()
cfg.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
cfg.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

# 设定需要对齐的方式(这里是深度对齐彩色,彩色图不变,深度图变换)
align_to = rs.stream.color
# 设定需要对齐的方式(这里是彩色对齐深度,深度图不变,彩色图变换)
# align_to = rs.stream.depth

alignedFs = rs.align(align_to)

profile = pipeline.start(cfg)

try:
    while True:
        fs = pipeline.wait_for_frames()
        aligned_frames = alignedFs.process(fs)

        color_frame = aligned_frames.get_color_frame()
        depth_frame = aligned_frames.get_depth_frame()

        if not depth_frame or not color_frame:
            continue

        color_image = np.asanyarray(color_frame.get_data())
        depth_image = np.asanyarray(depth_frame.get_data())

        # D·C 191122:打印depth_image的最大值看看
        # print(depth_image.max())
        # 可以看到,最大的数值从一万到六万不等(表示最远距离十多米到六十米这样)

        # D·C 191122:打印数据类型看看
        # print(depth_image.dtype)
        # uint16
        # print(color_image.dtype)
        # uint8

        # D·C 191122:打印color_image的维度看看
        # print(color_image.shape)
        # (480, 640, 3)
        # print(depth_image.shape)
        # (480, 640)

        # D·C 191122:打印cv.convertScaleAbs(depth_image, alpha=0.03)的数据类型和维度看看:
        # print(cv.convertScaleAbs(depth_image, alpha=0.03).dtype)
        # uint8
        # print(cv.convertScaleAbs(depth_image, alpha=0.03).shape)
        # (480, 640)

        # D·C 191122:打印cv.applyColorMap(cv.convertScaleAbs(depth_image, alpha=0.03), cv.COLORMAP_JET)的数据类型和维度看看
        # print(cv.applyColorMap(cv.convertScaleAbs(depth_image, alpha=0.03), cv.COLORMAP_JET).dtype)
        # uint8
        # print(cv.applyColorMap(cv.convertScaleAbs(depth_image, alpha=0.03), cv.COLORMAP_JET).shape)
        # (480, 640, 3)

        # D·C 191122:打印cv.convertScaleAbs(depth_image, alpha=0.03)的最大值看看
        # print(cv.convertScaleAbs(depth_image, alpha=0.03))
        # 可看到最大值为255
        # 估计若原值*alpha大于255,则将其取值为255,而当alpha为0.03时,能够映射的最大可变距离为255/0.03=8500mm=8.5m

        # D·C 191122:修改alpha参数后,发现图像对比度发生变化(比如alpha=1,图像基本呈红没啥对比度、alpha=0.001,图像呈蓝也没啥对比度、alpha=1点几,效果也不行)
        # origin:depth_image = cv.applyColorMap(cv.convertScaleAbs(depth_image, alpha=0.03), cv.COLORMAP_JET)
        depth_image = cv.applyColorMap(cv.convertScaleAbs(depth_image, alpha=0.03), cv.COLORMAP_JET)

        images = np.hstack((color_image, depth_image))

        # window = cv.namedWindow('window', cv.WINDOW_AUTOSIZE)

        cv.imshow('window', images)

        cv.waitKey(1)
finally:
    pipeline.stop()

参考文章1:【OpenCV3】cv::convertScaleAbs()使用详解

参考文章2:opencv中图像基础(大小,深度,通道)

参考文章3:图像位深度 8位 16位 24位 32位区别对比 RGB 真彩色 基本概念:(大小,深度,通道)位深度数据类型转换原理 Mat数据读取(opencv里的imread)

  • 22
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
#图像梯度 (注意都需要cv.convertScaleAbs将得到的有些负值取绝对值得到正数,并将数据转化到0-255之间,且sobel与Scarr算法中的数据位数都是32位浮点型的) import cv2 as cv import numpy as np def sobel_demo(image): #注意是32位float数据 grad_x = cv.Scharr(image, cv.CV_32F, 1, 0) grad_y = cv.Scharr(image, cv.CV_32F, 0, 1) #当用sobel算子不能很好的得到边缘的时候,就可以用Scharr算子,这是加强版的sobel算子,就可以得到 #原图像不是很明显的边缘了 # grad_x =cv.Sobel(image,cv.CV_32F,1,0) # grad_y =cv.Sobel(image,cv.CV_32F,0,1) gradx =cv.convertScaleAbs(grad_x) grady = cv.convertScaleAbs(grad_y) #cv.imshow("gradx",gradx) #cv.imshow("grady",grady) dst = cv.addWeighted(gradx,0.5,grady,0.5,0) cv.imshow("sobel_demo",dst) def lapalace_demo(image): #dst =cv.Laplacian(image,cv.CV_32F) #dst =cv.convertScaleAbs(dst) 会把dst变成单通道的8位的0-255的图像 #也可以用filter2D来做拉普拉斯算子 kernel = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]]) dst = cv.filter2D(image,cv.CV_32F,kernel) dst = cv.convertScaleAbs(dst) cv.imshow("lapalace",dst) src = cv.imread("E:/opencv/picture/step.jpg") cv.imshow("inital_window",src) #sobel_demo(src) lapalace_demo(src) cv.waitKey(0) cv.destroyAllWindows() 分析: 图像梯度可以把图像看成二维离散函数图像梯度其实就是这个二维离散函数的求导。 一、 Sobel算子是普通一阶差分,是基于寻找梯度强度。拉普拉斯算子(二阶差分)是基于过零点检测。通过计算梯度,设置阀值,得到边缘图像。 def sobel_demo(image): #注意是32位float数据 grad_x = cv.Scharr(image, cv.CV_32F, 1, 0) grad_y = cv.Scharr(image, cv.CV_32F, 0, 1) #当用sobel算子不能很好的得到边缘的时候,就可以用Scharr算子,这是加强版的sobel算子,就可以得到 #原图像不是很明显的边缘了 # grad_x =cv.Sobel(image,cv.CV_32F,1,0) # grad_y =cv.Sobel(image,cv.CV_32F,0,1) gradx = cv.convertScaleAbs(grad_x) grady = cv.convertScaleAbs(grad_y) #cv.imshow("gradx",gradx) #cv.imshow("grady",grady) dst = cv.addWeighted(gradx,0.5,grady,0.5,0) cv.imshow("sobel_demo",dst) 1.Sobel算子用来计算图像灰度函数的近似梯度。Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。 2.Sobel具有平滑和微分的功效。即:Sobel算子先将图像横向或纵向平滑,然后再纵向或横向差分,得到的结果是平滑后的差分结果。 OpenCV的Sobel函数原型为:Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst 注:一般就设置src,ddepth = cv.CV_32F,dx,dy(对x方求梯度就是1,0对y方向求梯度就是0,1) src参数表示输入需要处理的图像。 ddepth参数表示输出图像深度,针对不同的输入图像,输出目标图像有不同的深度。   具体组合如下:   src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F (一般源图像都为CV_8U,为了避免溢出,一般ddepth参数选择CV_32F)   src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F   src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F   src.depth() = CV_64F, 取ddepth = -1/CV_64F   注:ddepth =-1时,代表输出图像与输入图像相同的深度。 dx参数表示x方向上的差分阶数,1或0 。 dy参数表示y 方向上的差分阶数,1或0 。 dst参数表示输出与src相同大小和相同通道数的图像。 ksize参数表示Sobel算子的大小,必须为1、3、5、7。 scale参数表示缩放导数的比例常数,默认情况下没有伸缩系数。 delta参数表示一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中。 borderType表示判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。 2.OpenCVconvertScaleAbs函数使用线性变换转换输入数组元素成8位无符号整型。函数原型:convertScaleAbs(src[, dst[, alpha[, beta]]]) -> dst src参数表示原数组。 dst参数表示输出数组 (深度为 8u)。 alpha参数表示比例因子。 beta参数表示原数组元素按比例缩放后添加的值。 3.OpenCV的addWeighted函数是计算两个数组的加权和。函数原型:addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) -> dst 用于将x,y方向的梯度合成。 二、Scharr算子 当用sobel算子发现得到的边缘信息不明显的时候,就可以用Scharr算子了。该算子是sobel算子的加强版,用法也和sobel算子一样,效果更加突出。 Scharr算子也是计算x或y方向上的图像差分。OpenCV的Scharr函数原型为:Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]) -> dst 参数和Sobel算子的几乎差不多,意思也一样,只是没有ksize大小。 三、拉普拉斯算子 1.拉普拉斯算子(Laplace Operator)是n维欧几里德空间中的一个二阶微分算子,定义为梯度(▽f)的散度(▽•f)。 2.OpenCV的Laplacian函数原型为:Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]) -> dst src参数表示输入需要处理的图像。 ddepth参数表示输出图像深度,针对不同的输入图像,输出目标图像有不同的深度。   具体组合如下:   src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F (一般源图像都为CV_8U,为了避免溢出,一般ddepth参数选择CV_32F) 注:当然我们也可以cv.filter2D命令来make一个拉普拉斯算子: kernel = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]]) dst = cv.filter2D(image,cv.CV_32F,kernel) dst = cv.convertScaleAbs(dst) cv.imshow("lapalace",dst) Canny算法 canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是: 好的检测- 算法能够尽可能多地标识出图像中的实际边缘。 好的定位- 标识出的边缘要尽可能与实际图像中的实际边缘尽可能接近。 最小响应- 图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。 3.算法步骤:   ①高斯模糊 - GaussianBlur   ②灰度转换 - cvtColor   ③计算梯度 – Sobel/Scharr   ④非最大信号抑制   ⑤高低阈值输出二值图像 #canny算法常用步骤: #高斯模糊:因为canny对噪声很敏感,注意核size别太大 #源图像灰度化 #canny算法: 像素值小于低阈值的舍弃,高于高阈值的保留作为边缘信息,大于低阈值且该像素仅仅在连接到一个高于高阈值的像素时被保留。一般高阈值:低阈值在2:1到3:1之间 def canny_demo(image): image = cv.GaussianBlur(image,(3,3),0) gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) dst = cv.Canny(image,50,150) cv.imshow("Canny_demo",dst)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dontla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值