对此图像执行什么颜色转换(或其他操作)

时间:2017-06-27 18:09:01

标签: python opencv

我制作了一个非常简单的程序来读取图像,评估索贝尔过滤器然后用imshow呈现它。

import cv2
img = cv2.imread("/home/alex/imagens/train_5.jpg")

sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)  # x
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
norm = cv2.magnitude(sobelx, sobely)

normUint8 = norm.astype('uint8')

cv2.imshow("img", img)
cv2.imshow("norm", norm)
cv2.imshow("normUint8", normUint8)

print "img=" + str(img.dtype) + ", sobel=" + str(norm.dtype) + ", normUint8=" + str(normUint8.dtype)

cv2.waitKey(0)
cv2.destroyAllWindows()

我在此附上结果。enter image description here

我期望结果显示标准,并且normUint8将是相同或更相似的,因为它们的值在每个像素处小于1。 因此,我相信当我使用CV_64FC3图像时,opencv会在呈现之前执行某些操作。

我有兴趣找到这个操作才能使用它。

任何人都可以帮忙吗?

这里我附上我使用的原始图像。

enter image description here

感谢。

2 个答案:

答案 0 :(得分:3)

您正在将64FC3(3频道,64位浮动)图像投放到imshow。该函数的文档说明:

  

该功能可能会缩放图像,具体取决于其深度:

     
      
  • 如果图像是8位无符号,则按原样显示。
  •   
  • 如果图像是16位无符号或32位整数,则像素除以256.即,值范围[0,255 * 256]映射到[0,255]。
  •   
  • 如果图像是32位浮点,则像素值乘以255.即,值范围[0,1]映射到[0,255]。
  •   

尽管没有提到64位浮点数,但我们可以假设它们的处理方式与32位浮点数相同。如果我们查看源代码,我们会发现转换是由函数cvConvertImage完成的。具体来说,在line 622

double scale = src_depth <= CV_8S ? 1 : src_depth <= CV_32S ? 1./256 : 255;

为那些不熟悉类型枚举顺序的人解释这一点,它是8U,8S,16U,16S,32S,32F,64F。因此,字节不会缩放,其他整数除法,其余(浮点数)乘法。

由于显示我们需要一个8位图像,重要的是要注意缩放将在饱和状态下完成(在这种情况下,任何超过255的变为255,低于0的任何变为0)。

既然明确了imshow的转变是什么,那么让我们来看看为什么你会在白色的海洋中看到那些色块。

由于normuint8的简单投射会为您提供一个并非全黑的图像,我们可以放心地假设norm的值范围[0.0-1.0]。当值缩放255时,大于或等于1.0的任何内容将变为255(白色)。由于是3通道图像,我们最终可能只有一些通道是不饱和的,因此我们会看到各种颜色的斑块。

我们可以通过以下脚本模拟此行为:

b,g,r = cv2.split(norm)

r = np.uint8(np.where(r < 1.0, 0, 255))
g = np.uint8(np.where(g < 1.0, 0, 255))
b = np.uint8(np.where(b < 1.0, 0, 255))

cv2.imwrite('sobel_out.png', cv2.merge([b,g,r]))

我们将像素设置为黑色以获得值&lt; 1.0,其他一切都变白了。当我们组合平面时,我们得到以下图像:

看起来很熟悉?

注意:我怀疑方形图案来自您用于输入的JPEG压缩。

答案 1 :(得分:1)

Dan的答案非常好,并描述为什么 float图片可能会出现意外的显示属性。图像需要最小值和最大值才能知道黑色和白色是什么,并且float图像并不总是精确定义。

例如,您可以使用float图像,该图像仍然具有严格在0到255之间的值,仅用于计算精度,稍后舍入为int进行显示。但是在文献中通常分别使用0和1作为图像值的最小值和最大值,因为它使数学更加简单;由于您需要float个值来表示介于0和1之间的值,因此float图像使用范围0到1的情况很常见。因此,OpenCV坚持使用此值来显示float图像。对于float使图像在0到1范围内饱和,这意味着它会截断上下的值。

现在,如果您读入图像,默认情况下它将被读取为8位无符号整数(3通道图像为CV_U8C3)。当您应用Sobel运算符时,您指定了想要的float图像。这完全没问题,但是知道the Sobel operator is a convolution which multiplies multiple values and sums them up,所以这个操作可以给你的值大于原始图像的起始值。如果您使用了不同的返回类型,那么这些值可能会饱和。但是,使用浮动,它们在显示时间之前不会饱和。这非常有目的; Sobel算子可用于任意矩阵,因此并不总是需要使值饱和。

为了显示没有奇怪瑕疵的图像,您需要手动缩放图像,如上面链接的Stack Overflow应答或使用cv2.normalize()。或者你可以像你一样直接投射到另一种类型,使价值达到高端。