EladAskenazi
EladAskenazi

Reputation: 125

How to do histogram equalization without using cv2.equalizeHist

I'm trying to do the histogram equalization in a few steps:

I'm not allowed to use any lib functions that will do it I have to make the equalization function by myself

So far it looks like it's working for the gray-colored images but for RGB it's giving me messed up results.

code:

def transformRGB2YIQ(imgRGB: np.ndarray) -> np.ndarray:
    """
    Converts an RGB image to YIQ color space
    :param imgRGB: An Image in RGB
    :return: A YIQ in image color space
    """

    yiq_from_rgb = np.array([[0.299, 0.587, 0.114],
                             [0.59590059, -0.27455667, -0.32134392],
                             [0.21153661, -0.52273617, 0.31119955]])

    YIQ = np.dot(imgRGB.reshape(-1, 3), yiq_from_rgb).reshape(imgRGB.shape)

    return YIQ

    pass


def transformYIQ2RGB(imgYIQ: np.ndarray) -> np.ndarray:
    """
    Converts an YIQ image to RGB color space
    :param imgYIQ: An Image in YIQ
    :return: A RGB in image color space
    """
    yiq_from_rgb = np.array([[0.299, 0.587, 0.114],
                             [0.59590059, -0.27455667, -0.32134392],
                             [0.21153661, -0.52273617, 0.31119955]])
    rgb_from_yiq = np.linalg.inv(yiq_from_rgb)
    RGB = np.dot(imgYIQ.reshape(-1, 3), rgb_from_yiq).reshape(imgYIQ.shape)

    return RGB
    pass


def hsitogramEqualize(imgOrig: np.ndarray) -> (np.ndarray, np.ndarray, np.ndarray):
    """
        Equalizes the histogram of an image
        :param imgOrig: Original Histogram
        :ret
    """
    print(imgOrig.size)
    if imgOrig.size == 540000:
        img=imgOrig*255
        histOrig, bins = np.histogram(img.flatten(), 256, [0, 256])

        cdf = histOrig.cumsum()
        cdf_m = np.ma.masked_equal(cdf, 0)
        cdf_m = (cdf_m - cdf_m.min()) * 255 / (cdf_m.max() - cdf_m.min())
        cdf = np.ma.filled(cdf_m, 0).astype('uint8')

        imgEq = cdf[img.astype('uint8')]
        histEq, bins2 = np.histogram(imgEq.flatten(), 256, [0, 256])

    else:
        img=transformRGB2YIQ(imgOrig)*255
        histOrig, bins = np.histogram(img[:, :, 0].flatten(), 256, [0, 256])

        cdf = histOrig.cumsum()
        cdf_m = np.ma.masked_equal(cdf, 0)
        cdf_m = (cdf_m - cdf_m.min()) * 255 / (cdf_m.max() - cdf_m.min())
        cdf = np.ma.filled(cdf_m, 0).astype('uint8')

        img[:, :, 0] = cdf[img[:, :, 0].astype('uint8')]
        histEq, bins2 = np.histogram(img[:, :, 0].flatten(), 256, [0, 256])
        imgEq=transformYIQ2RGB(imgOrig)

    plt.imshow(imgEq)
    plt.show()

    return imgEq, histOrig, histEq

    pass

Upvotes: 1

Views: 1783

Answers (1)

EladAskenazi
EladAskenazi

Reputation: 125

if someone ever needed

def transformRGB2YIQ(imgRGB: np.ndarray) -> np.ndarray:
    """
    Converts an RGB image to YIQ color space
    :param imgRGB: An Image in RGB
    :return: A YIQ in image color space
    """
    transMatrix = np.array([[0.299, 0.587, 0.114],
                            [0.59590059, -0.27455667, -0.32134392],
                            [0.21153661, -0.52273617, 0.31119955]]).transpose()
    shape = imgRGB.shape
    return np.dot(imgRGB.reshape(-1, 3), transMatrix).reshape(shape)

    pass


def transformYIQ2RGB(imgYIQ: np.ndarray) -> np.ndarray:
    """
    Converts an YIQ image to RGB color space
    :param imgYIQ: An Image in YIQ
    :return: A RGB in image color space
    """
    transMatrix = np.linalg.inv(np.array([[0.299, 0.587, 0.114],
                                          [0.59590059, -0.27455667, -0.32134392],
                                          [0.21153661, -0.52273617, 0.31119955]])).transpose()
    shape = imgYIQ.shape
    return np.dot(imgYIQ.reshape(-1, 3), transMatrix).reshape(shape)
    pass


def hist_eq(img: np.ndarray) -> (np.ndarray, np.ndarray, np.ndarray):
    """
    This function will do histogram equalization on a given 1D np.array
    meaning will balance the colors in the image.
    For more details:
    https://en.wikipedia.org/wiki/Histogram_equalization
    **Original function was taken from open.cv**
    :param img: a 1D np.array that represent the image
    :return: imgnew -> image after equalization, hist-> original histogram, histnew -> new histogram
    """

    # Flattning the image and converting it into a histogram
    histOrig, bins = np.histogram(img.flatten(), 256, [0, 255])
    # Calculating the cumsum of the histogram
    cdf = histOrig.cumsum()
    # Places where cdf = 0 is ignored and the rest is stored
    # in cdf_m
    cdf_m = np.ma.masked_equal(cdf, 0)
    # Normalizing the cdf
    cdf_m = (cdf_m - cdf_m.min()) * 255 / (cdf_m.max() - cdf_m.min())
    # Filling it back with zeros
    cdf = np.ma.filled(cdf_m, 0)


    # Creating the new image based on the new cdf
    imgEq = cdf[img.astype('uint8')]
    histEq, bins2 = np.histogram(imgEq.flatten(), 256, [0, 256])

    return imgEq, histOrig, histEq

    pass


def hsitogramEqualize(imgOrig: np.ndarray) -> (np.ndarray, np.ndarray, np.ndarray):
    """
        Equalizes the histogram of an image
        The function will fist check if the image is RGB or gray scale
        If the image is gray scale will equalizes
        If RGB will first convert to YIQ then equalizes the Y level
        :param imgOrig: Original Histogram
        :return: imgnew -> image after equalization, hist-> original histogram, histnew -> new histogram
    """

    if len(imgOrig.shape) == 2:

        img = imgOrig * 255
        imgEq, histOrig, histEq = hist_eq(img)

    else:
        img = transformRGB2YIQ(imgOrig)
        img[:, :, 0] = img[:, :, 0] * 255
        img[:, :, 0], histOrig, histEq = hist_eq(img)
        img[:, :, 0] = img[:, :, 0] / 255
        imgEq = transformYIQ2RGB(img)

    return imgEq, histOrig, histEq

    pass

Upvotes: 1

Related Questions