Преобразование HSI обратно в RGB - PullRequest
1 голос
/ 09 апреля 2020

Так что я пытаюсь усреднить интенсивность изображения. Следовательно, я сделал преобразование исходного изображения в HSI, нахождение средней интенсивности исходного изображения, а затем изменил интенсивность изображения HSI перед преобразованием его обратно в RGB. Однако в настоящее время я сталкиваюсь с проблемой преобразования HSI обратно в RGB

def HSI_TO_RGB(Average, img):
     with np.errstate(divide='ignore', invalid='ignore'):

        #Load image with 32 bit floats as variable type
        bgr = np.float32(img)/255

        #Separate color channels
        blue = bgr[:,:,0]
        green = bgr[:,:,1]
        red = bgr[:,:,2]

        #Calculate Saturation
        def calc_saturation(red, blue, green):
            minimum = np.minimum(np.minimum(red, green), blue)
            saturation = 1 - (3 / (red + green + blue + 0.001) * minimum)

            return saturation

        #Calculate Hue
        def calc_hue(red, blue, green):
            hue = np.copy(red)

            for i in range(0, blue.shape[0]):
                for j in range(0, blue.shape[1]):
                    hue[i][j] = 0.5 * ((red[i][j] - green[i][j]) + (red[i][j] - blue[i][j])) / \
                                math.sqrt((red[i][j] - green[i][j])**2 +
                                        ((red[i][j] - blue[i][j]) * (green[i][j] - blue[i][j])))
                    hue[i][j] = math.acos(hue[i][j])

                    if blue[i][j] <= green[i][j]:
                        hue[i][j] = hue[i][j]
                    else:
                        hue[i][j] = ((360 * math.pi) / 180.0) - hue[i][j]

            return hue

        huehue = calc_hue(red, blue, green) * 255
        satsat = calc_saturation(red, blue, green) * 255

        for huehue in range(0,1):
           backR =  (Average + (2 * Average * satsat))
           backG =  (Average - (Average * satsat))
           backB =  (Average - (Average * satsat))
           final = cv2.merge((backR, backG, backB))
           return final

        for huehue in range(1,120):
           backR = (int) (Average + (Average * satsat) * cos(huehue) / cos(60-huehue))
           backG = (int) (Average + (Average * satsat) * (1 - cos(huehue) / cos(60-huehue)))
           backB = (int) (Average - (Average * satsat))
           final = cv2.merge((backR, backG, backB))
           return final
        for huehue in range(120,121):
           backR = (int) (Average - (Average * satsat))
           backG = (int) (Average + (2 * Average * satsat))
           backB = (int) (Average - (Average * satsat))
           final = cv2.merge((backR, backG, backB))
           return final
        for huehue in range(121,240):
           backR = (int) (Average - (Average * satsat))
           backG = (int) (Average + (Average * satsat) * cos(huehue-120) / cos(180-huehue))
           backB = (int) (Average + (Average * satsat) * (1 - cos(huehue-120) / cos(180-huehue)))
           final = cv2.merge((backR, backG, backB))
           return final
        for huehue in range(240,241):
           backR = (int) (Average - (Average * satsat))
           backG = (int) (Average - (Average * satsat))
           backB = (int) (Average + (2 * Average * satsat))
           final = cv2.merge((backR, backG, backB))
           return final
        for huehue in range(241,360): 
           backR = (int) (Average + (Average * satsat) * (1 - cos(huehue-240) / cos(300-huehue)))
           backG = (int) (Average - (Average * satsat))
           backB = (int) (Average + (Average * satsat) * cos(huehue-240) / cos(300-huehue))
           final = cv2.merge((backR, backG, backB))
           return final

        final=final/360*255
        return final   

. Я в основном адаптировал этот код с> RGB к HSI и HSI в RGB <и попытался нормализуйте значения до 0-255, но вместо этого я получаю это. <a href="https://i.stack.imgur.com/Ne3Bf.png" rel="nofollow noreferrer">enter image description here Кто-нибудь может дать мне несколько советов о том, как решить проблему?

1 Ответ

2 голосов
/ 09 апреля 2020

Существует несколько проблем, и я не уверен, что мне удалось исправить все из них:

  • Вы используете for вместо if, например:
    for huehue in range(1,120) должно быть if 1 <= huehue_deg[i][j] < 120.
  • Вы смешиваете градусы и радианы:
    Функция math.cos использует радианы в качестве входных данных.
    Вы используете ее с градусами: cos(60-huehue)
    С другой стороны, calc_hue возвращает значение в радианах, и вы используете range(1,120) в градусах.
  • Вы смешиваете RGB и BGR:
    В начале: blue = bgr[:,:,0]
    В конце: final = cv2.merge((backR, backG, backB))
  • Вы умножаетесь на 255 слишком рано:
    huehue = calc_hue(red, blue, green) * 255 и satsat = calc_saturation(red, blue, green) * 255 это не место.
  • Из вашего поста неясно, что является аргументом Average.
    Я предположил, что это среднее значение RGB после преобразования в float32 (диапазон [0, 1]).

Следующий (исправленный) код считывает входное изображение, передает его в HSI_TO_RGB и отображает вывод:

import cv2
import numpy as np
import math
from math import cos, radians

def HSI_TO_RGB(Average, img):
     with np.errstate(divide='ignore', invalid='ignore'):

        #Load image with 32 bit floats as variable type
        bgr = np.float32(img)/255

        #Separate color channels
        blue = bgr[:,:,0]
        green = bgr[:,:,1]
        red = bgr[:,:,2]

        #Calculate Saturation
        def calc_saturation(red, blue, green):
            minimum = np.minimum(np.minimum(red, green), blue)
            saturation = 1 - (3 / (red + green + blue + 0.001) * minimum)

            return saturation

        #Calculate Hue
        def calc_hue(red, blue, green):
            hue = np.copy(red)

            for i in range(0, blue.shape[0]):
                for j in range(0, blue.shape[1]):
                    hue[i][j] = 0.5 * ((red[i][j] - green[i][j]) + (red[i][j] - blue[i][j])) / \
                                math.sqrt((red[i][j] - green[i][j])**2 +
                                        ((red[i][j] - blue[i][j]) * (green[i][j] - blue[i][j])))
                    hue[i][j] = math.acos(hue[i][j])

                    if blue[i][j] <= green[i][j]:
                        hue[i][j] = hue[i][j]
                    else:
                        hue[i][j] = ((360 * math.pi) / 180.0) - hue[i][j]

            return hue

        huehue = calc_hue(red, blue, green) # * 255
        satsat = calc_saturation(red, blue, green) # * 255

        huehue = np.nan_to_num(huehue)  # Replace nan with zeros

        # Convert from radians to degrees
        huehue_deg = np.rad2deg(huehue)

        # Initiazlie with zeros
        backR = np.zeros_like(satsat)
        backG = np.zeros_like(satsat)
        backB = np.zeros_like(satsat)

        for i in range(0, satsat.shape[0]):
            for j in range(0, satsat.shape[1]):

                if 0 <= huehue_deg[i][j] < 1:
                   backR[i][j] =  (Average[i][j] + (2 * Average[i][j] * satsat[i][j]))
                   backG[i][j] =  (Average[i][j] - (Average[i][j] * satsat[i][j]))
                   backB[i][j] =  (Average[i][j] - (Average[i][j] * satsat[i][j]))                   

                elif 1 <= huehue_deg[i][j] < 120:
                   backR[i][j] = (Average[i][j] + (Average[i][j] * satsat[i][j]) * cos(huehue[i][j]) / cos(radians(60)-huehue[i][j]))
                   backG[i][j] = (Average[i][j] + (Average[i][j] * satsat[i][j]) * (1 - cos(huehue[i][j]) / cos(radians(60)-huehue[i][j])))
                   backB[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))

                elif 120 <= huehue_deg[i][j] < 121:
                   backR[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))
                   backG[i][j] = (Average[i][j] + (2 * Average[i][j] * satsat[i][j]))
                   backB[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))

                elif 121 <= huehue_deg[i][j] < 240:
                   backR[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))
                   backG[i][j] = (Average[i][j] + (Average[i][j] * satsat[i][j]) * cos(huehue[i][j]-radians(120)) / cos(radians(180)-huehue[i][j]))
                   backB[i][j] = (Average[i][j] + (Average[i][j] * satsat[i][j]) * (1 - cos(huehue[i][j]-radians(120)) / cos(radians(180)-huehue[i][j])))

                elif 240 <= huehue_deg[i][j] < 241:
                   backR[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))
                   backG[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))
                   backB[i][j] = (Average[i][j] + (2 * Average[i][j] * satsat[i][j]))

                else: #elif 241 <= huehue_deg[i][j] < 360:
                   backR[i][j] = (Average[i][j] + (Average[i][j] * satsat[i][j]) * (1 - cos(huehue[i][j]-radians(240)) / cos(radians(300)-huehue[i][j])))
                   backG[i][j] = (Average[i][j] - (Average[i][j] * satsat[i][j]))
                   backB[i][j] = (Average[i][j] + (Average[i][j] * satsat[i][j]) * cos(huehue[i][j]-radians(240)) / cos(radians(300)-huehue[i][j]))

        #final = cv2.merge((backR, backG, backB))

        # The correct order is BGR and not RGB (at the beginning of the funtion: blue = bgr[:,:,0])
        final = cv2.merge((backB, backG, backR))

        #final = final/360*255

        # Convert from flot32 to uint8:
        final = np.round(final * 255).astype(np.uint8)
        return final


##### Converting to HSI using OpenCV is simple, converting back is difficult #####
def bgr2hsi(bgr):
    """Convert image from BGR color format to HSI color format"""
    # Convert from BGR to HSV using OpenCV
    hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)

    # Difference between HSV and HSI:
    # In HSV: V = max(R, G, B)
    # In HSI: I = (R + G + B)/3
    hsi = hsv
    hsi[:, :, 2] = np.mean(bgr, 2)

    return hsi


bgr = cv2.imread('tree.png')

#hsi = bgr2hsi(bgr)

average = np.mean(np.float32(bgr)/255, 2)
new_bgr = HSI_TO_RGB(average, bgr)

cv2.imshow('new_bgr', new_bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()

Примечание:
Я не пытался оптимизировать производительность, и я не искал существующую реализацию RGB для HSI.
Я просто попытался исправить отправленный вами код.


Результат:
enter image description here

...