Python HSI 到 RGB 的转换 - 不是我所期望的

Python HSI to RGB conversion - not what I expect

我正在尝试使用公式手动处理 HSV -> RGB,而不使用 openCV。

我尝试计算 HSV -> RGB 颜色 space,并给出了我想要的几乎相同的图片,但有一些噪音。

有些图像有很多噪声,有些图像真的没有噪声(有“一些”噪声。)

我试过调试..但似乎不知道我的代码有什么问题。

是我写的Formulla吗?还是我错过了什么?..

我不知道我不知道什么。所以,我需要帮助..

这是我的代码,我将 post 原始图像和下面有噪声的结果图像。

首先,这是我的代码。


def HSI_to_bgr(h, s, i):
    h = degrees(h)
    if 0 < h <= 120 :
        b = i * (1 - s)
        r = i * (1 + (s * cos(radians(h)) / cos(radians(60) - radians(h))))
        g = i * 3 - (r + b)
    elif 120 < h <= 240:
        h -= 120
        r = i * (1 - s)
        g = i * (1 + (s * cos(radians(h)) / cos(radians(60) - radians(h))))
        b = 3 * i - (r + g)
    elif 0 < h <= 360:
        h -= 240
        g = i * (1 - s)
        b = i * (1 + (s * cos(radians(h)) / cos(radians(60) - radians(h))))
        r = i * 3 - (g + b)
    return [b, g, r]


def rgb_to_hue(b, g, r):
    angle = 0
    if b != g != r:
        angle = 0.5 * ((r - g) + (r - b)) / sqrt(((r - g) ** 2) + (r - b) * (g - b))
    if b <= g:
        return acos(angle)
    else:
        return 2 * pi - acos(angle)


def rgb_to_intensity(b, g, r):
    val = (b + g + r) / 3.
    if val == 0:
        return 0
    else:
        return val


def rgb_to_saturity(b, g, r):
    if r + g + b != 0:
        return 1. - 3. * np.min([r, g, b]) / (r + g + b)
    else:
        return 0




def point_process_colorscale_negative_intensity(file_path):
    src = cv2.imread(file_path, cv2.IMREAD_COLOR)

    height, width = src.shape[0], src.shape[1]
    new_image = np.zeros((height, width, 3), dtype=np.uint8)
    I = np.zeros((height, width))
    S = np.zeros((height, width))
    H = np.zeros((height, width))

    for i in range(height) :
        for j in range(width) :
            b = src[i][j][0] / 255.
            g = src[i][j][1] / 255.
            r = src[i][j][2] / 255.
            H[i][j] = rgb_hsi_conversion.rgb_to_hue(b, g, r)
            S[i][j] = rgb_hsi_conversion.rgb_to_saturity(b, g, r)
            I[i][j] = rgb_hsi_conversion.rgb_to_intensity(b, g, r)
            # I[i][j] = 1. - I[i][j]

            bgr_tuple = rgb_hsi_conversion.HSI_to_bgr(H[i][j], S[i][j], I[i][j])

            new_image[i][j][0] = round(bgr_tuple[0] * 255.)
            new_image[i][j][1] = round(bgr_tuple[1] * 255.)
            new_image[i][j][2] = round(bgr_tuple[2] * 255.)

    return new_image, src

这是我的结果图片。

他们都有一些噪音。尤其是狒狒的鼻子和小山羊的紫噪更厉害

先谢谢你了,如果我没有提供足够的信息,我会尽力补充。

主要问题是 b != g != r 行,意思是 b != gg != r,应该是:如果 b == gg == r return0

为了调试问题,您可以找到输出错误值的像素(通过比较 new_imagesrc)。
找到该像素的 b、g、r 值。
实现少量代码来调试特定的 b、g、r 值。
使用调试器查找出错的地方。

这是用于调试值 b, g, r = 74, 74, 229:

的代码示例
b = 74 / 255.
g = 74 / 255.
r = 229 / 255.
H = rgb_to_hue(b, g, r)
S = rgb_to_saturity(b, g, r)
I = rgb_to_intensity(b, g, r)
bgr_tuple = HSI_to_bgr(H, S, I)
new_b = round(bgr_tuple[0] * 255.)
new_g = round(bgr_tuple[1] * 255.)
new_r = round(bgr_tuple[2] * 255.)

这就是我发现 b != g != r 有问题的原因(因为 r==gg!=r)。

请记住,在很多情况下编写一些代码来查找错误(而不是调试原始代码)会更容易。


更正后的代码:

import cv2
import numpy as np
from math import sqrt, cos, acos, degrees, radians, pi

def HSI_to_bgr(h, s, i):
    h = degrees(h)
    if 0 <= h <= 120 :
        b = i * (1 - s)
        r = i * (1 + (s * cos(radians(h)) / cos(radians(60) - radians(h))))
        g = i * 3 - (r + b)
    elif 120 < h <= 240:
        h -= 120
        r = i * (1 - s)
        g = i * (1 + (s * cos(radians(h)) / cos(radians(60) - radians(h))))
        b = 3 * i - (r + g)
    elif 0 < h <= 360:
        h -= 240
        g = i * (1 - s)
        b = i * (1 + (s * cos(radians(h)) / cos(radians(60) - radians(h))))
        r = i * 3 - (g + b)
    return [b, g, r]


def rgb_to_hue(b, g, r):
    if (b == g == r):
        return 0

    angle = 0.5 * ((r - g) + (r - b)) / sqrt(((r - g) ** 2) + (r - b) * (g - b))
    if b <= g:
        return acos(angle)
    else:
        return 2 * pi - acos(angle)


def rgb_to_intensity(b, g, r):
    val = (b + g + r) / 3.
    if val == 0:
        return 0
    else:
        return val


def rgb_to_saturity(b, g, r):
    if r + g + b != 0:
        return 1. - 3. * np.min([r, g, b]) / (r + g + b)
    else:
        return 0




def point_process_colorscale_negative_intensity(file_path):
    src = cv2.imread(file_path, cv2.IMREAD_COLOR)

    height, width = src.shape[0], src.shape[1]
    new_image = np.zeros((height, width, 3), dtype=np.uint8)
    I = np.zeros((height, width))
    S = np.zeros((height, width))
    H = np.zeros((height, width))

    for i in range(height):
        for j in range(width):
            b = src[i][j][0] / 255.
            g = src[i][j][1] / 255.
            r = src[i][j][2] / 255.
            H[i][j] = rgb_to_hue(b, g, r)
            S[i][j] = rgb_to_saturity(b, g, r)
            I[i][j] = rgb_to_intensity(b, g, r)

            bgr_tuple = HSI_to_bgr(H[i][j], S[i][j], I[i][j])

            new_image[i][j][0] = np.clip(round(bgr_tuple[0] * 255.), 0, 255)
            new_image[i][j][1] = np.clip(round(bgr_tuple[1] * 255.), 0, 255)
            new_image[i][j][2] = np.clip(round(bgr_tuple[2] * 255.), 0, 255)

    return new_image, src


new_image, src = point_process_colorscale_negative_intensity('mandrill.png')  # The mandrill image I used is from MATLAB.

cv2.imwrite('new_image.png', new_image)  # Save new_image for testing

cv2.imshow('new_image', new_image)  # Show new_image for testing
cv2.imshow('abs diff*50', np.minimum(cv2.absdiff(src, new_image), 5)*50)  # Show absolute difference of (src - new_image) multiply by 50 for showing small differences.
cv2.waitKey()
cv2.destroyAllWindows()

如果还有问题,请尝试使用一小段代码进行调试...


new_image: