python - opencv、BGR2HSV 会产生大量伪影

标签 python opencv image-processing hsv

enter image description here

这张图片只是一个例子。右上是原始图像,左上是色调,左下是饱和度,右下是值。可以很容易地看出,H 和 S 都充满了伪影。我想降低亮度,所以结果会出现很多这样的伪像。

我做错了什么?

我的代码很简单:

vc = cv2.VideoCapture( 0 )
# while true and checking ret
ret, frame = vc.read()
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
cv2.imshow("h", frame_hsv[:,:,0])
cv2.imshow("s", frame_hsv[:,:,1])
cv2.imshow("v", frame_hsv[:,:,2])

最佳答案

我觉得你的问题有误会。虽然 Boyko Peranov 的回答肯定是正确的,但您提供的图像没有问题。其背后的逻辑如下:您的相机在 RGB 颜色空间中拍摄照片,根据定义,它是一个立方体。当您将其转换为 HSV 颜色空间时,所有像素都映射到以下圆锥体: HSV Cone

Hue(HSV 的第一个 channel )是圆锥上的角度,Saturation(HSV 的第二个 channel ,在图像中称为 Chroma)是到圆锥中心的距离,Value(HSV 的第三个 channel )是圆锥上的高度。

Hue channel 通常定义在 0-360 之间,并以 0 处的红色开始(在 8 位图像的情况下,OpenCV 使用 0-180 范围来适应 the documentation 中所述的无符号字符)。但事实是,值为 0 和 359 的两个像素在颜色上非常接近。通过仅取外表面(当饱和度最大时)使 HSV 锥体变平时,可以更容易地看到它: Flattened HSV cone

即使这些值在感知上很接近(0 时为完全红色,359 时为红色并带有一点点紫色),但这两个值相距甚远。这就是您在 Hue channel 中描述的“伪影”的原因。当 OpenCV 以灰度显示它时,它将黑色映射为 0,将白色映射为 359。实际上,它们是非常相似的颜色,但是当以灰度映射时,显示的距离太远。有两种方法可以规避这个违反直觉的事实:您可以将 H channel 重新转换到具有固定饱和度和值的 RGB 空间中,这将显示更接近我们感知的表示。您还可以使用其他基于感知的颜色空间(例如 Lab color space ),这不会给您带来这些数学副作用。

Boyko Peranov 解释了为什么这些神器补丁是方形的。 JPEG 压缩的工作原理是用近似于它所替换的补丁的更大的正方形替换像素。如果在创建 jpg 时将压缩质量设置得非常低,您甚至可以看到这些方 block 出现在 RGB 图像中。质量越低,方 block 越大越明显。这些方 block 的平均值是一个单一值,对于红色调,最终可能介于 0 和 5(显示为黑色)或 355 和 359(显示为白色)之间。这就解释了为什么“人工制品”是方形的。

我们可能还会问自己,为什么在色调 channel 中可以看到更多的 JPEG 压缩失真。这是因为 chroma subsampling ,基于感知的研究表明,与强度的快速变化相比,我们的眼睛更不容易看到颜色的快速变化。因此,在压缩时,JPEG 会故意丢失色度信息,因为我们无论如何都不会注意到它。

饱和度(左下图)白色变化点的情况类​​似。您描述的像素几乎是黑色的(在锥体的尖端)。因此,饱和度值可能变化很大,但不会对像素的颜色产生太大影响:它总是接近黑色。这也是 HSV 颜色空间不是纯粹基于感知的副作用。

RGB(或 OpenCV 的 BGR)和 HSV 之间的转换(理论上)是无损的。您可以说服自己:将您的 HSV 图像重新转换为 RGB 图像,您将获得与开始时完全相同的图像,没有添加伪影。

关于python - opencv、BGR2HSV 会产生大量伪影,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17239253/

相关文章:

opencv - 使用opencv过滤掉物体检测的误报

c# - 处理图像 : Parameter is not valid

python - 如何将pygame中的3d数组转换为opencv python中的有效输入?

python - 根据数值有条件创建数据框列

python - 如何在没有 twilio 的情况下使用 python 和 opencv 流式传输视频?

android - 无法将裁剪后的图像(opencv Mat)复制到位图中

c# - 在 C# 中使用锁定位写入图像

python - 在Python中获取列表中每个元组的第一个元素

python - 我应该使用多个变量还是一本字典

带范围的 Python 列表