Suppose RGB has value (0.5, 0, 0) on a point A
and greyscale has value 0.5 there. The other point B
we are interested in has RGB (0.5, 0, 0) and greyscale 0.75, and finally C
has (0.75, 0, 0) and 0.5 greyscale. These points are chosen to illustrate the difference between approaches.
0.) Your solution would see A = (0.75, 0.5, 0.5)
, B = (0.88, 0.75, 0.75)
and C = (0.88, 0.5, 0.5)
. All points would be much lighter shades of red = not what you want.
1.) One solution would be to just set greyscale where there is no RGB image:
someRGB = any(Img2RGB > 0, 3);
ImGrayNoRGB = Img1Gray;
ImGrayNoRGB(someRGB) = 0;
ImgRez = Img2RGB;
ImgRez(:,:,1) = (1 - Img2RGB(:,:,1)) .* ImGrayNoRGB + Img2RGB(:,:,1);
ImgRez(:,:,2) = (1 - Img2RGB(:,:,2)) .* ImGrayNoRGB + Img2RGB(:,:,2);
ImgRez(:,:,3) = (1 - Img2RGB(:,:,3)) .* ImGrayNoRGB + Img2RGB(:,:,3);
Last 4 lines could be simplified to (same option exists in your v0):
ImgRez = (1 - Img2RGB) .* repmat(ImGrayNoRGB, [1, 1, 3]) + Img2RGB;
This is a good solution if RGB is obtained from the same greyscale image and kept color just if it is above threshold, but it will produce poor results for mixing 2 arbitrary images, where greyscale is brighter than the RGB. A = (0.5, 0, 0)
is OK and C = (0.75, 0, 0)
is fine too, but B = (0.5, 0, 0)
is now darker than the supposed greyscale value and this might look bad.
1b) A fix for this "weird looking stuff" would be that luminance of RGB is checked, either by the proper formula (about 0.2R + 0.7G + 0.1B
) or simply checking which value is the highest => max(Img2RGB, [], 3)
. Greyscale is used to set minimum pixel brightness to that value, additively. Assuming max
, points would be A = (0.5, 0, 0)
, B = (0.75, 0.25, 0.25)
and C = (0.75, 0, 0)
.
RGBbright = max(Img2RGB,[], 3); % Get brightness of the RGB image.
deltaBright = greyscale - RGBbright; % Get how much greyscale needs to be added to the RGB.
deltaBright(deltaBright < 0) = 0;
ImgRez = Img2RGB + repmat(deltaBright, [1, 1, 3]);
2.) Another possible solution would be to slightly modify the color mixing in the code, so greyscale is adding white color uniformly and preserving the differences - check maximum RGB and add RGB just in complement to that:
ImgRez = (1 - max(Img2RGB,[], 3)) .* repmat(Img1Gray, [1, 1, 3]) + Img2RGB;
In this case, points are A = (0.75, 0.25, 0.25)
, B = (0.88, 0.38, 0.38)
and C = (0.88, 0.13, 0.13)
.
Now, for the choice between 1b) and 2), hard to say what to pick. Try both.
2 will make colors a little bit duller and it will additionally have abrupt jumps in image brightness - suppose greyscale image is uniform 0.5 and red region varies between 0 and 0.5 - parts that are red will be brighter than the parts that are grey. So it seems 1b should be a better option. On the other hand, brighter image where there are colors might be desirable outcome of this mixing, favoring 2.