I can adjust the highlights in an image with

highlight[img_, brightness_, contrast_, gamma_, threshold_, colour_, cthreshold_] := 
ImageCompose[img, SetAlphaChannel[ImageAdjust[
 Blend[{img, colour}, cthreshold], {brightness, contrast, gamma}], 
 Binarize[img, threshold]]];

(* highlight[i, 0, .1, .5, .75, Yellow, .1]}}] *)

I have tried to use ImageCompose to change the midtones and shadows too, but am getting a little stuck. I'm trying to get MMA to ignore the highlight area when I adjust the midtones/shadows. I have tried different combinations of ColorNegate@Binarize[img, threshold], but it gets complicated quickly.

I guess the problem reduces to create a threshold between 2 values, and then nest the function.

Is there an clean way to achieve what I'm after?


1 Answer 1


My colour theory is probably wrong here, but I think a nice way to select the mids is to select pixel values with a "middle" luminance, right? We can do that by taking the L channel and thresholding it, them applying the resulting image as a mask.

i = ExampleData[{"TestImage", "Girl3"}]

enter image description here

Now, we create our function to threshold the image. You may want to change this to a "softer" function - you can see some example in the Threshold documentation.

thresh[min_, max_] := Piecewise[{{#, min < # < max}}, 0] &

Now we create our mask, by applying our threshold to the luminance channel. Here we can vary what we might call our "midtones" - right now, I'm saying anything with a luminance value between .3 and .6 are what we want to keep. Of course, getting the highlights or shadows simply involves changing the arguments to thres (for example, shadows might be thresh[0, 0.2] and highlights thresh[0.8, 1]).

mask = Image@
  MapAt[thresh[.3, .6], ImageData[ColorSeparate[i, "L"]], {All, All}]

enter image description here

Finally, we composite our image, making our edits to the full image, then removing the masked section. I also Blur the mask here in order to get slightly less sharp artifacts.

ImageCompose[i, SetAlphaChannel[ImageAdjust[i, {0, .3}], Blur@mask]]

enter image description here

We can see that the background and shirt have become a bit brighter, but the dark hair and most of the face have remained the same. I suppose those would be what I might call the "midtones", but maybe there's a more precise definition that I ignored. You also may want to look into using the "V" of "HSV" (with ColorSeparate[i, "V"], or some other channel of a different colour space.

  • $\begingroup$ Many thanks - sorry for the late response! $\endgroup$
    – martin
    Commented Sep 20, 2021 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.