imagematlabimage-processingcolorspsychtoolbox

How can I change the overall hue of an image, akin to Photoshop's hue adjustment?


Within Photoshop, I can adjust the overall hue of an image so that the black/white/grey levels remain unaffected while the colour hues change respectively to around -100 (picture of scale attached). Is there a MATLAB or PsychToolbox function that could accomplish this?

For example, some function like newImage = hueadjust(Image, -100) or something simple like this.

I have many images, and I'm sure there's a way to batch all my images through Photoshop so the same hue scale is applied to them all, but wondering if this can be accomplished relatively easily through code given my lack of coding experience.

Adobe Photoshop's hue adjustment


Solution

  • Yeah that's pretty simple. Simply convert the image to HSV, take the hue channel and add or subtract modulo 360 degrees, then convert the image back. Note that manipulating the hue does not affect the black/gray/white colours seen in the image which is actually what you desire. The saturation and value components in the HSV colour space do that for us. This addition and/or subtraction of each pixel's hue component is what Photoshop (and other similar graphical editors like GIMP) performs under the hood.

    Use the function rgb2hsv and its equivalent counterpart hsv2rgb. However, the dynamic range of each converted channel is from [0,1] but usually the hue is represented between 0 and 360 degrees. Therefore, multiply the hue channel by 360, do the modulo, and then divide by 360 when you're done.

    If you wanted to create a function called hueadjust as you have in your post, simply do this:

    function newImage = hueadjust(img, hAdjust)
        hsv = rgb2hsv(img);
        hue = 360*hsv(:,:,1);
        hsv(:,:,1) = (mod(hue + hAdjust, 360)) / 360;
        newImage = hsv2rgb(hsv);
    end
    

    The first line of code converts an image into HSV. The next line of code copies over the hue channel into a variable called hue and multiplies each value by 360. We then write back into the hue channel of the original image by taking each hue value of the original image (stored in hue) adding each hue by hAdjust which is the desired shift in degrees and ensuring that we wrap around back to 0 if we exceed 360 degrees (that's what mod is doing), then dividing the result by 360 to get back to the [0,1] dynamic range that is expected. This modified image is now converted back into RGB and is sent to the output.

    Take note that the output image will be of a double type due to the call to hsv2rgb. The dynamic range for each channel is still within the range of [0,1] so you can easily write these images to file without a problem. If you for some reason want to go back to the original type of the image itself, you can use functions such as im2uint8 from the Image Processing Toolbox to convert an input back into its unsigned 8-bit integer form. Most images seen in practice adopt this standard.

    Here's a quick example seeing how this function works. Also let's take a look at what the hue circle looks like just for completeness:

    Source: Lode's Computer Graphics Tutorial

    We can see that red has a hue of around 0 degrees while magenta has a hue of around 315 degrees or -45 degrees. Let's also use the onions.png image that is accompanied with the Image Processing Toolbox in MATLAB. It looks like this:

    enter image description here

    Let's also read in this image first. The above image can be read in directly from the Internet using the URL that the image refers to:

    im = imread('https://i.sstatic.net/BULoQ.png');
    

    The nice thing about the imread function from the IPT is that you can read images directly from the Internet. I'd like to transform or shift the hues so that the red hues are magenta so that means shifting all of the hues in the each by -45 degrees. So run the function like so:

    out = hueadjust(im, -45);
    

    Showing the image with imshow(out), we get:

    enter image description here

    Note that the rest of the hues when transformed make sense. The greens are a rather dull green and are hovering probably at around the 60 degree hue or so. Subtracting by 45 would push this to a red hue and you can see that in the resulting image. The same can be said about the yellow colours as they hover at around a 30 - 40 degree hue. Also note that the white colours are affected a bit slightly most likely because the colours seen in those white areas are not purely white (a.k.a. not 100% saturation) which is to be expected.