简介:本篇文章主要关注sobel边缘检测后的图像数据类型与后续计算和显示的关系问题。
sobel参考链接
1.代码
import os
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def showImage(img, winName="image", waitKey=1, destroyMode=0):
if img is None:
print("in showImage: the input image is None!\n")
return -1
cv.namedWindow(winName, 0)
cv.imshow(winName, img)
cv.waitKey(waitKey)
if destroyMode != 0:
cv.destroyWindow(winName)
def sobel_x(img,ksize=3):
if img is None:
return img
#注:ddepth参数如果用CV_8U的话,负数的梯度会被直接置零,丢失从wight-to-black的梯度
return cv.Sobel(img,cv.CV_64F,1,0,ksize=ksize)
def sobel_y(img,ksize=3):
if img is None:
return img
# 注:ddepth参数如果用CV_8U的话,负数的梯度会被直接置零,丢失从wight-to-black的梯度
return cv.Sobel(img,cv.CV_64F,0,1,ksize=ksize)
def sobel_xy(img,ksize=3,gamma=0):
if img is None:
return img
# 注:ddepth参数如果用CV_8U的话,负数的梯度会被直接置零,丢失从wight-to-black的梯度
sobel_x = cv.Sobel(img,cv.CV_64F,1,0,ksize=ksize)
sobel_y = cv.Sobel(img,cv.CV_64F,0,1,ksize=ksize)
sobel_xy = cv.addWeighted(sobel_x,0.5,sobel_y,0.5,gamma)
return sobel_xy
if __name__ == "__main__":
imagePath = "G:\\imageData\\del.png"
img = readImage(imagePath)
showImage(img,winName="image",waitKey=1)
#sobel_x
sobel_x = sobel_x(img,3)
#sobel_x的数据类型是double类型的,转为uint8时会被截断,显示时出现很多白班
#
showImage(sobel_x,"sobel_x",0)
#sobel_y
sobel_y = sobel_y(img,3)
showImage(sobel_y,"sobel_y",0)
#sobel_xy
sobel_xy = sobel_xy(img,3)
showImage(sobel_xy,"sobel_xy",0)
2.数据类型实验
-
在opencv-python中函数原型如下
dst = cv.Sobel( src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]] )
其中第二个参数ddepth表示的是结果图用多少位深度保存结果,因为opencv中sobel计算的结果从暗到亮是正数,从亮到暗是负数,如果用CV_8U格式(即8位无符号整型)则所有负数都会被置零,也就是从亮到暗的梯度会丢失。 -
把上面代码中所有cv.sobel(img,cv.CV_64F,.....)的参数cv.CV_64F换为cv.CV_8U后,从图像上看就如下图:
image.png
这里的结果显示,从左到右,从上到下,只有从暗到亮的地方的梯度(正数)被保留下来了,从亮到暗的梯度(负数)都损失了。所以sobel算子做边缘提取时还是只能用CV_64F、CV_32F等更多位数的格式保存结果图。
3.显示CV_64F格式的图片
CV_64F的数据格式在显示时会有问题,对返回的CV_64F格式的结果图直接用cv.imshow显示如下
这里的结果表明opencv在显示的时候,CV_64F格式的图片超过255的都被截断了,负数都置为零,看起来就像是二值化的。为了正常显示,需要用cv.convertScaleAbs()函数把图的格式转换一下。
cv.convertScaleAbs()函数包含三个操作:
- 取绝对值
- 尺度缩放
-
映射到8bits 空间
image.png
修改1.中代码
if __name__ == "__main__":
imagePath = "G:\\imageData\\del.png"
img = readImage(imagePath)
showImage(img,winName="image",waitKey=1)
#sobel_x
sobel_x = sobel_x(img,3)
#sobel_x的数据类型是double类型的,转为uint8时会被截断,显示时出现很多白班
#负数部分不会显示,用cv.convertScaleAbs转换
sobel_x = cv.convertScaleAbs(sobel_x)
showImage(sobel_x,"sobel_x",0)
#sobel_y
sobel_y = sobel_y(img,3)
sobel_y = cv.convertScaleAbs(sobel_y)
showImage(sobel_y,"sobel_y",0)
#sobel_xy
sobel_xy = sobel_xy(img,3)
sobel_xy = cv.convertScaleAbs(sobel_xy)
showImage(sobel_xy,"sobel_xy",0)
结果
image.png
网友评论